In order to thank you for all members' support of our website, we are holding new events - Getting Free Samples by Paying Freight only.
Want to get free samples? Please check this post for more details.

3DES

JavaCard Applet Development Related Questions and Answers.
deepanshsinghal
Posts: 44
Joined: Thu Apr 06, 2017 8:01 am
Points :456
Contact:

3DES

Post by deepanshsinghal » Sat Apr 29, 2017 1:36 am

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

User avatar
UNKNwYSHSA
Posts: 630
Joined: Thu May 21, 2015 4:05 am
Points :3021
Contact:

Re: 3DES

Post by UNKNwYSHSA » Tue May 02, 2017 2:39 am

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
sense and simplicity

User avatar
UNKNwYSHSA
Posts: 630
Joined: Thu May 21, 2015 4:05 am
Points :3021
Contact:

Re: 3DES

Post by UNKNwYSHSA » Tue May 02, 2017 2:53 am

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);
}
sense and simplicity

deepanshsinghal
Posts: 44
Joined: Thu Apr 06, 2017 8:01 am
Points :456
Contact:

Re: 3DES

Post by deepanshsinghal » Thu May 25, 2017 10:37 am

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

User avatar
UNKNwYSHSA
Posts: 630
Joined: Thu May 21, 2015 4:05 am
Points :3021
Contact:

Re: 3DES

Post by UNKNwYSHSA » Fri May 26, 2017 6:02 am

Let me have a look.
sense and simplicity

deepanshsinghal
Posts: 44
Joined: Thu Apr 06, 2017 8:01 am
Points :456
Contact:

Re: 3DES

Post by deepanshsinghal » Fri May 26, 2017 8:58 am

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

tay00000
Posts: 112
Joined: Tue Sep 27, 2016 10:58 am
Points :1486
Contact:

Re: 3DES

Post by tay00000 » Fri May 26, 2017 12:14 pm

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

User avatar
UNKNwYSHSA
Posts: 630
Joined: Thu May 21, 2015 4:05 am
Points :3021
Contact:

Re: 3DES

Post by UNKNwYSHSA » Sat May 27, 2017 1:19 am

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

   }
sense and simplicity

deepanshsinghal
Posts: 44
Joined: Thu Apr 06, 2017 8:01 am
Points :456
Contact:

Re: 3DES

Post by deepanshsinghal » Mon May 29, 2017 10:07 am

I tried with openemv implementation also... but no success

User avatar
UNKNwYSHSA
Posts: 630
Joined: Thu May 21, 2015 4:05 am
Points :3021
Contact:

Re: 3DES

Post by UNKNwYSHSA » Tue May 30, 2017 9:36 pm

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. :?
sense and simplicity

Post Reply Previous topicNext topic

Who is online

Users browsing this forum: No registered users and 3 guests

JavaCard OS : Disclaimer