Christmas is coming!

To celebrate the new year and thank for the support from all our dear customers, Christmas promotional activity is being held in JavaCardOS online store.

During the event, you can enjoy many promotional activities - High Discount on JavaCardOS products,Lucky Draw,Double forum Points.

Come to choose your own Christmas gift and try your luck now!

How to compute MAC

Algorithm School

Moderator: UNKNwYSHSA

User avatar
wintstar
Posts: 14
Joined: Sun Jul 26, 2015 11:06 pm
Points: 119
Contact:

How to compute MAC

Postby wintstar » Sat Aug 29, 2015 4:13 am

Hi, everyone.
I need to implement authentication process. How can I compute the MAC data?
Thanks

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

Re: How to compute MAC

Postby UNKNwYSHSA » Sat Aug 29, 2015 11:31 pm

What's the code you write for?
The specification usually describe how to calculate the MAC step by step for details.
For example, the GP specification, has figure and text description for how to calculate MAC, very clear while writing code.
sense and simplicity

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

Re: How to compute MAC

Postby UNKNwYSHSA » Sat Aug 29, 2015 11:34 pm

Like this:
gp-cmac.png
You do not have the required permissions to view the files attached to this post. Please login first.
sense and simplicity

Bob2002
Posts: 36
Joined: Wed Jul 29, 2015 10:50 pm
Points: 1216
Contact:

Re: How to compute MAC

Postby Bob2002 » Sun Aug 30, 2015 9:22 pm

Here is an example of how to do the MAC. It comes from oracle community.

Code: Select all

byte[] mac;
byte[] icv = new byte[8];
Cipher desedeCBCCipher = Cipher.getInstance("DESede/CBC/NoPadding");
Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");

IvParameterSpec ivSpec = new IvParameterSpec(icv);

if (data.length % 8 != 0)
    throw new Exception("data block size must be multiple of 8");

int blocks = data.length / 8;

for (int i = 0; i < blocks - 1; i++) {
    desCipher.init(Cipher.ENCRYPT_MODE, singledesCMAC, ivSpec);
    byte[] block = desCipher.doFinal(data, i * 8, 8);
    ivSpec = new IvParameterSpec(block);
}

int offset = (blocks - 1) * 8;

desedeCBCCipher.init(Cipher.ENCRYPT_MODE, sessionCMAC, ivSpec);
mac = desedeCBCCipher.doFinal(data, offset, 8);

ivSpec = new IvParameterSpec(new byte[8]);
desCipher.init(Cipher.ENCRYPT_MODE, singledesCMAC, ivSpec);
icv = desCipher.doFinal(data);

Note:
icv is set to 00:00:00:00:00:00:00:00 for the external authenticate call and the resulting icv from each command is used as the ICV for the next command.
sessionCMAC is the session MAC key
singledesCMAC is left half (8 bytes) of the session MAC key.

Here is some code to derive a key from derivation data.

Code: Select all

private SecretKey getSecretKey(byte[] keyData) throws GeneralSecurityException {
    if (keyData.length == 16) {
        byte[] temp = (byte[]) keyData.clone();
        keyData = new byte[24];
        System.arraycopy(temp, 0, keyData, 0, temp.length);
        System.arraycopy(temp, 0, keyData, 16, 8);
    }

    DESedeKeySpec keySpec = new DESedeKeySpec(keyData);
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
    SecretKey key = secretKeyFactory.generateSecret(keySpec);

    return key;
}

private Key deriveKey(byte[] keyData, byte[] data) throws GeneralSecurityException {
    Key key = getSecretKey(keyData);
    IvParameterSpec dps = new IvParameterSpec(DEFAULT_ICV);
    desedeCBCCipher.init(Cipher.ENCRYPT_MODE, key, dps);

    byte[] result = desedeCBCCipher.doFinal(data);
    adjustParity(result);

    return getSecretKey(result);
}


/**
 * Adjust a DES key to odd parity
 *
 * @param key
 *            to be adjusted
 */
private static void adjustParity(byte[] key) {
    for (int i = 0; i < key.length; i++) {
        int akku = (key[i] & 0xFF) | 1;

        for (int c = 7; c > 0; c--) {
            akku = (akku & 1) ^ (akku >> 1);
        }
        key[i] = (byte) ((key[i] & 0xFE) | akku);
    }
}


The MAC method for verifying the card and host cryptogram is different to the retail MAC used for EXTERNAL AUTHENTICATE. Here is some code to generate the signature for host and card cryptograms.

Code: Select all

 /**
     * Calculate the DES CBC MAC using the standard cipher algorithms
     *
     * @param key
     *            Key used for MAC calculation
     * @param data
     *            Data to calculate the MAC for
     * @param iv
     *            ICV
     *
     * @returns CBC MAC
     */
    public byte[] cbcMac(byte[] data) throws AuthenticationException {

        byte[] temp;
        try {
            Cipher cbcDES = Cipher.getInstance("DESede/CBC/NoPadding");
            IvParameterSpec params = new IvParameterSpec(DEFAULT_ICV);
            cbcDES.init(Cipher.ENCRYPT_MODE, sessionSENC, params);

            temp = cbcDES.doFinal(data);
        } catch (GeneralSecurityException e) {
            throw new AuthenticationException("Error performing CBC MAC", e);
        }

        byte[] signature = new byte[8];
        System.arraycopy(temp, temp.length - 8, signature, 0, signature.length);
        return signature;
    }

simplyi
Posts: 2
Joined: Fri Mar 03, 2017 1:58 pm
Points: 16
Contact:

Re: How to compute MAC

Postby simplyi » Fri Mar 03, 2017 2:08 pm

Hello!

Thank you very much for these code examples. Please allow me ask a couple of questions regarding these code examples:

1. Is the sessionCMAC calculated using the KeyGenerator.getInstance("DESede") ?
2. I am not very sure how to calculate the singledesCMAC out of sessionCMAC...Can I do it this way?

private static byte[] getHalfKey(byte[] doubleDesKey)
{
byte[] singledesCMAC = new byte[8];
System.arraycopy(doubleDesKey, doubleDesKey.length - 8, singledesCMAC, 0, singledesCMAC.length);
return singledesCMAC;
}

and then convert these bytes to a secret key this way?

byte[] halfAKeyBytes = getHalfKey(master_mac_key.getEncoded());
KeySpec halfKeySpec = new DESedeKeySpec(halfAKeyBytes);
SecretKey halfAKey = mySecretKeyFactory.generateSecret(myKeySpec);

Also, in the method: private SecretKey getSecretKey(byte[] keyData), what exactly is derivation data? Is it another key? or is it how we actually derive the singledesCMAC out of sessionCMAC?

Thank you very much!

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

Re: How to compute MAC

Postby UNKNwYSHSA » Fri Mar 03, 2017 10:53 pm

Are you talking about MAC calculation for GP SCP02?
sense and simplicity

simplyi
Posts: 2
Joined: Fri Mar 03, 2017 1:58 pm
Points: 16
Contact:

Re: How to compute MAC

Postby simplyi » Sat Mar 04, 2017 1:45 am

I was looking for Retail MAC Calculation when I came across this discussion.

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

Re: How to compute MAC

Postby UNKNwYSHSA » Sun Mar 05, 2017 10:54 pm

You can refer source code of bouncycastle. Refer to implementation of class org.bouncycastle.crypto.macs.ISO9797Alg3Mac.
That can resolve all your questions.

For your 1st question: The DESede algorithm can only be used on the output transformation (last transformation).
sense and simplicity


Return to “Algorithm School”

Who is online

Users browsing this forum: No registered users and 3 guests

JavaCard OS : Disclaimer