哪个是密码版本5的方法密钥派生(MKD)

时间:2017-02-17 17:49:49

标签: cryptography emv

我正在为EMV交易开发一个软件,我面临着雇用我的公司缺乏文档的问题。 其中一个是关于用于生成ARQC的MKD(在第一个GENERATE AC期间)。我从消息请求中知道IAD如下:

  

0FA501A030F8000000000000000000000F000000000000000000000000000000

根据它,密码版本是5,但我不知道MKD。

参与此主题的人是否知道我应该用于生成ARQC的MKD?

我感激任何评论。 感谢。

1 个答案:

答案 0 :(得分:2)

(在香草EMV和共同核心规范的背景下)

引用EMV 4.3,第2册,第8.1.2节:

  

应用程序密码生成的方法作为输入a   独特的ICC应用密码图主密钥MKAC和数据   按照8.1.1节中的描述选择,并计算8字节   应用密码学分为以下两个步骤:

     
      
  1. 使用附件A1.3中指定的会话密钥导出函数从ICC中导出应用程序密码会话密钥SKAC   应用程序密码主密钥MKAC和2字节应用程序   ICC的交易柜台(ATC)。
  2.   
  3. 通过将附件A1.2中指定的MAC算法应用于所选数据并使用,来生成8字节应用程序密码   应用程序密码会话密钥在上一步中派生。对于   通过设置,创建8字节应用程序密码的AES   参数s到8。
  4.   

MKAC本身源自发行人(应用密码)主密钥' (第8.3节):

  

对于由公共核心定义定义的密码   密码版本的' 5',ICC主密钥应使用   选项B方法见附件A1.4.2。

有关详细说明,请参阅EMV第2册中提到的附件。

我可以提供以下java代码(半测试但没有任何保证):

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;
}

非常好的信息来源是EFTlab website(他们的BP-CCalc工具可用于计算密钥,密码......)。

祝你好运!