Page 1 of 5

3DES

Posted: Sat Apr 29, 2017 1:36 am
by deepanshsinghal
Hi Everyone,

Does anyone have code snippet for implementation of 3DES.
i implemented 3DES but it is not generating correct MAC.

public EMVCrypto(GenerateAC x) {
theApplet = x; // reference back to the applet

diversification_data = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_DESELECT);
sessionkey = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_DESELECT);
transaction_data = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_DESELECT);

desCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
desMAC = Signature.getInstance(Signature.ALG_DES_MAC8_ISO9797_M2, false);

mk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_2KEY, false);
mk.setKey(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09,
(byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16 }, (short) 0);
sk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_2KEY, false);
}

private void setSessionKey(APDU apdu) {

// as 8-byte diversification data we take the ATC followed by all zeroes
Util.setShort(diversification_data, (short) 0, theApplet.protocolState.getATC());
// Util.arrayFillNonAtomic(diversification_data, (short) 2, (short) 6, (byte) 0);

desCipher.init(mk, Cipher.MODE_ENCRYPT);

// compute left 8 bytes of the session key
diversification_data[2] = (byte) 0xF0;
desCipher.doFinal(diversification_data, (short) 0, (short) 8, sessionkey, (short) 0);

// compute right 8 byte of the session key
diversification_data[2] = (byte) 0x0F;
desCipher.doFinal(diversification_data, (short) 0, (short) 8, sessionkey, (short) 0);

sk.setKey(sessionkey, (short) 0);

}


private void computeAC(byte cid, byte[] apduBuffer, short length, byte[] response, short offset) {

Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short) 0, length);

// MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2
desMAC.init(sk, Signature.MODE_SIGN);
desMAC.sign(transaction_data, (short) 0, (short) (length), response, offset);

}

This code snippet is taken from openemv

Correct me where i am doing mistake.

Regards,
Deepansh

Re: 3DES

Posted: Tue May 02, 2017 2:39 am
by UNKNwYSHSA
Please make sure first that your key is
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16

not
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F

Re: 3DES

Posted: Tue May 02, 2017 2:53 am
by UNKNwYSHSA
And follow the EMV specification, it said:
For the session key used to generate and verify the Application Cryptogram and
the ARPC, the diversification value is the ATC followed by n-2 bytes of '00':
R := ATC || '00' || '00' || … || '00' || '00' || '00'.

But your implementation is:

Code: Select all

private void setSessionKey(APDU apdu) {

   // as 8-byte diversification data we take the ATC followed by all zeroes
   Util.setShort(diversification_data, (short) 0, theApplet.protocolState.getATC());
   // Util.arrayFillNonAtomic(diversification_data, (short) 2, (short) 6, (byte) 0);

   desCipher.init(mk, Cipher.MODE_ENCRYPT);

   // compute left 8 bytes of the session key
   diversification_data[2] = (byte) 0xF0;
   desCipher.doFinal(diversification_data, (short) 0, (short) 8, sessionkey, (short) 0);

   // compute right 8 byte of the session key
   diversification_data[2] = (byte) 0x0F;
   desCipher.doFinal(diversification_data, (short) 0, (short) 8, sessionkey, (short) 0);

   sk.setKey(sessionkey, (short) 0);
}

Re: 3DES

Posted: Thu May 25, 2017 10:37 am
by deepanshsinghal
Thanks UNKNwYSHSA,

As per you suggested i did according to that and i was able to generate the session key. Now Can you help to find the mistake in computeAC().

Thanks in Advance,
Deepansh

Re: 3DES

Posted: Fri May 26, 2017 6:02 am
by UNKNwYSHSA
Let me have a look.

Re: 3DES

Posted: Fri May 26, 2017 8:58 am
by deepanshsinghal
Hi UNKNwYSHSA,

This is the method i'm using can you tell me the mistake that i am doing....

private void computeAC(byte cid, byte[] apduBuffer, short length, byte[] response, short offset) {

/* Collect the data to be MAC-ed in the array transaction_data */

// Copy CDOL from the APDU buffer, at offset 0:
Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short) 0, length);

// MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2
desMAC.init(sk, Signature.MODE_SIGN);
// desMAC.init(sk, Cipher.MODE_ENCRYPT);
desMAC.sign(transaction_data, (short) 0, (short) (length), response, offset);

}

public void generateFirstACReponse(APDU apdu, byte cid, byte[] apduBuffer, short length, byte[] iad, short iad_length, byte[] response,
short offset) {

setSessionKey(apdu);

response[offset] = (byte) 0x80; // Tag for Format 1 cryptogram

// Length: 1 byte CID + 2 byte ATC + 8 byte AC = 11
response[(short) (offset + 1)] = (byte) 11;

// 1 byte CID, ie the type of AC returned
response[(short) (offset + 2)] = cid;

// 2 byte ATC, at offset 3:
Util.setShort(response, (short) (offset + 3), theApplet.protocolState.getATC());

// the AC itself
computeAC(cid, apduBuffer, length, response, (short) (offset + 5));

// generateSecondACReponse(cid, apduBuffer, length, iad, iad_length, response, offset);
}

Thanks

Re: 3DES

Posted: Fri May 26, 2017 12:14 pm
by tay00000
Please use the code block to encapsulate your codes. It is hard to read.

Code: Select all

/*
 * Collect the data to be MAC-ed in the array transaction_data
 */
private void computeAC(byte cid, byte[] apduBuffer, short length, byte[] response, short offset) {
    // Copy CDOL from the APDU buffer, at offset 0:
    Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short) 0, length);

    // MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2
    desMAC.init(sk, Signature.MODE_SIGN);
   
    desMAC.sign(transaction_data, (short) 0, (short) (length), response, offset);
}

public void generateFirstACReponse(APDU apdu, byte cid, byte[] apduBuffer, short length, byte[] iad, short iad_length, byte[] response,
short offset) {

    setSessionKey(apdu);

    response[offset] = (byte) 0x80; // Tag for Format 1 cryptogram

    // Length: 1 byte CID + 2 byte ATC + 8 byte AC = 11
    response[(short) (offset + 1)] = (byte) 11;

    // 1 byte CID, ie the type of AC returned
    response[(short) (offset + 2)] = cid;

   // 2 byte ATC, at offset 3:
    Util.setShort(response, (short) (offset + 3), theApplet.protocolState.getATC());

    // the AC itself
    computeAC(cid, apduBuffer, length, response, (short) (offset + 5));

    // generateSecondACReponse(cid, apduBuffer, length, iad, iad_length, response, offset);
}

Re: 3DES

Posted: Sat May 27, 2017 1:19 am
by UNKNwYSHSA
deepanshsinghal wrote:Hi UNKNwYSHSA,

This is the method i'm using can you tell me the mistake that i am doing....

private void computeAC(byte cid, byte[] apduBuffer, short length, byte[] response, short offset) {

/* Collect the data to be MAC-ed in the array transaction_data */

// Copy CDOL from the APDU buffer, at offset 0:
Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short) 0, length);

// MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2
desMAC.init(sk, Signature.MODE_SIGN);
// desMAC.init(sk, Cipher.MODE_ENCRYPT);
desMAC.sign(transaction_data, (short) 0, (short) (length), response, offset);

}

public void generateFirstACReponse(APDU apdu, byte cid, byte[] apduBuffer, short length, byte[] iad, short iad_length, byte[] response,
short offset) {

setSessionKey(apdu);

response[offset] = (byte) 0x80; // Tag for Format 1 cryptogram

// Length: 1 byte CID + 2 byte ATC + 8 byte AC = 11
response[(short) (offset + 1)] = (byte) 11;

// 1 byte CID, ie the type of AC returned
response[(short) (offset + 2)] = cid;

// 2 byte ATC, at offset 3:
Util.setShort(response, (short) (offset + 3), theApplet.protocolState.getATC());

// the AC itself
computeAC(cid, apduBuffer, length, response, (short) (offset + 5));

// generateSecondACReponse(cid, apduBuffer, length, iad, iad_length, response, offset);
}

Thanks


The data elements for generate AC in your code is not same as specification mentioned.
Please see specification EMV 4.3 Book 2 Security and Key Management 8.1.1 for details.
And the OpenEMV applet implement it as following (same as specification):

Code: Select all

   private void computeAC(byte cid, byte[] apduBuffer, short length, 
         byte[] response, short offset){
      /* Collect the data to be MAC-ed in the array transaction_data */

      // Copy CDOL from the APDU buffer, at offset 0:
      Util.arrayCopy(apduBuffer, OFFSET_CDATA, transaction_data, (short)0, length);
      // 2 bytes AIP, at offset length:
      Util.setShort(transaction_data, length, theApplet.staticData.getAIP());
      // 2 bytes ATC, at offset length + 2:
      Util.setShort(transaction_data, (short)(length+2), theApplet.protocolState.getATC());
 
      //TODO What is the following data?
      transaction_data[(short)(length+4)] = (byte) 0x80;
      transaction_data[(short)(length+5)] = (byte) 0x0;
      transaction_data[(short)(length+6)] = (byte) 0x0;

      // MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding method 2
        desMAC.init(sk, Signature.MODE_SIGN);
       desMAC.sign(transaction_data, (short)0, (short)(length+7), response, offset);

   }

Re: 3DES

Posted: Mon May 29, 2017 10:07 am
by deepanshsinghal
I tried with openemv implementation also... but no success

Re: 3DES

Posted: Tue May 30, 2017 9:36 pm
by UNKNwYSHSA
deepanshsinghal wrote:I tried with openemv implementation also... but no success


Can you tell me, how do you verify the result? And i will have a try to resolve this problem. I have no terminate application to verify the applet functions. :?