2017-02-17 5 views
1

私はEMVトランザクション用のソフトウェアを開発していますが、私を雇った会社からのドキュメンテーションが非常に不足しています。 これらのうちの1つは、ARQCを生成するためのMKD(最初のGENERATE ACの間)です。私は、IADは以下の通りであることをメッセージ要求から知っている:暗号化バージョン5のメソッドキー導出(MKD)はどれですか

0FA501A030F8000000000000000000000F000000000000000000000000000000

それによると暗号文のバージョンは5ですが、私はMKDについては考えています。

ARQCを生成するために使用すべきMKDについて、このテーマに関わったことがある人は誰ですか?

コメントありがとうございます。おかげさまで

+0

疑問がある場合は、(EMV)規格を参照してください。 –

+0

こんにちは@MaartenBodewes、私はあなたが私を提案し、それがうまくいった。 MDKはEMV 4.2標準に準拠しています。ありがとう。 – brienze

+0

偉大な、あなたのためにうまくいってうれしい! –

答えて

1

(バニラEMVと共通コア仕様書の文脈において)

EMV 4.3を引用し、予約2、セクション8.1.2:

アプリケーション暗号発生のための方法は、入力として ユニークICCアプリケーションを取りCryptogram Master Key MKACとデータを として選択し、8バイトの アプリケーション暗号を次の2つのステップで計算します。

  1. ICC アプリケーション暗号文マスターキーMKACと2バイトアプリケーション ICCのトランザクションカウンタ(ATC)からアプリケーション暗号文セッションキーSKACを導出するために、附属書A1.3で指定されたセッション鍵導出関数を使用する。
  2. 前の手順で導出した アプリケーション暗号化セッションキーを使用して、附属書A1.2で指定したMACアルゴリズムを選択したデータに適用して、8バイトのアプリケーション暗号を生成します。 ため8バイトのアプリケーション暗号文8.

MKAC自体に パラメータsを設定して「発行者(アプリケーション暗号文)マスターキー」(セクション8.3)から導出され作成されAES:

暗号文のバージョンが「5」のCommon Core Definitionsで定義された暗号については、ICCマスターキーは、 を使用して派生されるものとする。

詳細な説明については、前述のEMVブック2の附属書を参照してください。

Iは、次のJavaコード(半試験が、任意の保証なしで)提供することができる:(そのBP-CCalcツールキーを計算するのに使用できる情報の非常に良い源はEFTlab websiteある

public static byte[] deriveMasterKey(byte[] issuerMasterKey, byte[] pan, byte[] panSequenceNumber) { 
    String concat; 
    if(((pan[pan.length-1]&0x0F)==0x0F)) { 
     String help=ByteArrayUtils.toString(pan); 
     concat = "0" + help.substring(0, help.length()-1) + ByteArrayUtils.toString(panSequenceNumber); 
    } else { 
     concat = ByteArrayUtils.toString(pan) + ByteArrayUtils.toString(panSequenceNumber); 
    } 
    logger.debug("Concat: " + concat); 
    byte[] concatBytes=ByteArrayUtils.fromSafeString(concat); 
    byte[] sha1Bytes = SwCryptUtils.sha1(concatBytes); 
    String sha1=ByteArrayUtils.toString(sha1Bytes); 
    logger.debug("X: " + sha1); 
    StringBuilder b1 = new StringBuilder(); 
    StringBuilder b2 = new StringBuilder(); 
    for(char c : sha1.toCharArray()) { 
     if(Character.isDigit(c)) { 
      b1.append(c); 
     } else { 
      b2.append((char)(c-('A'-'0'))); 
     } 
    } 
    String y = b1.toString() + b2.toString(); 
    logger.debug("Y': " + y); 
    y = y.substring(0, 16); 
    logger.debug("Y: " + y); 
    byte[] yBytes = ByteArrayUtils.fromSafeString(y); 
    byte[] leftBytes = SwCryptUtils.desEncryptEcb(issuerMasterKey, yBytes); 
    String left = ByteArrayUtils.toString(leftBytes); 
    logger.debug("Z_{L}': " + left); 
    byte[] yXorBytes = yBytes.clone(); 
    for (int i = 0; i < yXorBytes.length; i++) { 
     yXorBytes[i]^=0xFF; 
    } 
    logger.debug("Y_{xor}': " + ByteArrayUtils.toString(yXorBytes)); 
    byte[] rightBytes = SwCryptUtils.desEncryptEcb(issuerMasterKey, yXorBytes); 
    String right = ByteArrayUtils.toString(rightBytes); 
    logger.debug("Z_{R}': " + right); 
    String result=left+right; 
    logger.debug("MK:" + result); 
    return ByteArrayUtils.fromSafeString(result); 
} 

public static byte[] deriveCommonSessionKey(byte[] masterKey, byte[] atc) { 
    byte[] rBytes=Arrays.copyOf(atc, 8); 
    logger.debug("R: " + ByteArrayUtils.toString(rBytes)); 
    byte[] f1Bytes=rBytes.clone(); 
    f1Bytes[2]=(byte)0xF0; 
    logger.debug("F1: " + ByteArrayUtils.toString(f1Bytes)); 
    byte[] f2Bytes=rBytes.clone(); 
    f2Bytes[2]=(byte)0x0F; 
    logger.debug("F2: " + ByteArrayUtils.toString(f2Bytes)); 
    byte[] f1EncBytes = SwCryptUtils.desEncryptEcb(masterKey, f1Bytes); 
    logger.debug("ENC(F1): " + ByteArrayUtils.toString(f1EncBytes)); 
    byte[] f2EncBytes = SwCryptUtils.desEncryptEcb(masterKey, f2Bytes); 
    logger.debug("ENC(F2): " + ByteArrayUtils.toString(f2EncBytes)); 
    byte[] result = ArrayUtils.addAll(f1EncBytes, f2EncBytes); 
    logger.debug("SK: " + ByteArrayUtils.toString(result)); 
    return result; 
} 

public static byte[] generateApplicationCryptogram(byte[] sessionKey, byte[] terminalData, byte[] iccData) { 
    byte[] dataBytes = ArrayUtils.addAll(terminalData, iccData); 
    logger.debug("DATA: " + ByteArrayUtils.toString(dataBytes)); 
    byte[] paddedDataBytes = ArrayUtils.add(dataBytes, (byte)0x80); 
    paddedDataBytes=Arrays.copyOf(paddedDataBytes, ((paddedDataBytes.length+7)/8)*8); 
    logger.debug("PADDED DATA: " + ByteArrayUtils.toString(paddedDataBytes)); 

    byte[] skBytes=sessionKey; 
    byte[] skL = Arrays.copyOf(skBytes, 8); 
    logger.debug("SK_{L}: " + ByteArrayUtils.toString(skL)); 
    byte[] skR = Arrays.copyOfRange(skBytes, 8, 16); 
    logger.debug("SK_{R}: " + ByteArrayUtils.toString(skR)); 

    byte[] pom = SwCryptUtils.desEncryptCbcZeroIv(skL, paddedDataBytes); 
    logger.debug("POM: " + ByteArrayUtils.toString(pom)); 
    pom=Arrays.copyOfRange(pom, pom.length-8, pom.length); 
    logger.debug("POM: " + ByteArrayUtils.toString(pom)); 
    pom=SwCryptUtils.desDecryptEcb(skR, pom); 
    logger.debug("POM: " + ByteArrayUtils.toString(pom)); 
    pom=SwCryptUtils.desEncryptEcb(skL, pom); 
    logger.debug("POM: " + ByteArrayUtils.toString(pom)); 
    logger.debug("AC: " + ByteArrayUtils.toString(pom)); 
    return pom; 
} 

を暗号文...)。

幸運を祈る!

+0

ようこそ@brienze ...あなたのプロジェクトに幸運を祈る! – vlp

+0

こんにちは@vlp、まず、ありがとう! 私はあなたのガイドラインに従いました。私はARQCを受けることができました。私のPANは16桁の長さに等しいので、MDAを生成するためにいくつかの変更を加えなければならなかったので、SHA-1(オプションB)を使用する必要はありませんでした。代わりにオプションAを使用しました。 SessionKey生成のために他の変更を行いました。私の鍵= 8nとしてDESを2回適用するのではなく、SK = ALG(MK)[R]を計算しました。 次に、暗号文を生成するために、私はCBCモードを使用する代わりにECBモードを使用しました。そしてボイルラは正しくARQCを実行しました! ありがとう! – brienze

関連する問題