2017-02-17 13 views
1

Я разрабатываю программное обеспечение для транзакций EMV, и у меня возникает огромная нехватка документации от компании, которая наняла меня. Один из них касается MKD для генерации ARQC (во время первого GENERATE AC). Я знаю, что из запроса на сообщение о том, что IAD является, как показано ниже:Какая деривация ключа метода (MKD) для криптограммы версии 5

0FA501A030F8000000000000000000000F000000000000000000000000000000

В соответствии с этим Cryptogram версии 5, но я понятия не имею о МКД.

Кто-нибудь, кто был вовлечен в эту тему, знает что-то о MKD, которое я должен использовать для создания ARQC?

Я буду благодарен за любые комментарии. Спасибо.

+0

При возникновении сомнений обратитесь к стандарту (EMV). –

+0

Привет @MaartenBodewes, я сделал, как вы мне предложили, и это сработало. MDK соответствует стандарту EMV 4.2. Благодарю. – brienze

+0

Отлично, рад, что сработало для вас! –

ответ

1

(В контексте ванили EMV и общего ядра Спецификации)

Приводя EMV 4.3, книга 2, раздел 8.1.2:

Способ генерации Применение криптограммы принимает в качестве входных уникальный МТП Application Мастер-ключ Cryptogram MKAC и данные , выбранные, как описано в разделе 8.1.1, и вычисляют 8-байтовую криптограмму приложения на следующих двух этапах:

  1. Используйте функцию деривации ключа сеанса, указанную в Приложении A1.3, чтобы получить ключ сеанса сеанса криптограммы приложения из ICC. Мастер-ключ Cryptogram Application MKAC и 2-байтовое приложение. Счетчик транзакций (ATC) ICC.
  2. Сгенерируйте 8-байтовую криптографию приложения, применяя алгоритм MAC, указанный в Приложении A1.2, к выбранным данным и используя ключ сеанса криптограмм приложения, полученный на предыдущем шаге. Для AES 8-байтовые Криптограммы Применения создаются путем установки параметр с до 8.

Самого MKAC является производной от «Эмитента (Приложение криптограммы) мастер-ключ» (раздел 8.3):

Для криптограммы, определяемой определениями общего ядра с помощью версии криптограммы «5», главный ключ ICC должен быть получен с использованием метода опциона B, описанного в приложении A1.4.2.

См. Упомянутые приложения EMV Book 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 может использоваться для вычисления ключей, криптограммы ...).

Удачи вам!

+0

Добро пожаловать @brienze ... Удачи вам в вашем проекте! – vlp

+0

Привет @vlp, прежде всего, спасибо вам большое! Я следил за вашими рекомендациями, и я мог сделать ARQC. Я должен был внести некоторые изменения для генерации MDK, потому что мой PAN равен 16 цифрам, поэтому мне не пришлось использовать SHA-1 (вариант B). Вместо этого я использовал вариант A. Другое изменение, которое я сделал для поколения SessionKey; поскольку мой ключ = 8n, я вычислил SK = ALG (MK) [R], вместо того, чтобы применять DES дважды, как вы это делали. Затем, чтобы сгенерировать криптограмму, я использовал режим ECB вместо использования режима CBC, и я правильно сделал ARQC! Спасибо! – brienze