Page 1 of 2

How to compute MAC

Posted: Sat Aug 29, 2015 4:13 am
by wintstar
Hi, everyone.
I need to implement authentication process. How can I compute the MAC data?
Thanks

Re: How to compute MAC

Posted: Sat Aug 29, 2015 11:31 pm
by UNKNwYSHSA
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.

Re: How to compute MAC

Posted: Sat Aug 29, 2015 11:34 pm
by UNKNwYSHSA
Like this:

Re: How to compute MAC

Posted: Sun Aug 30, 2015 9:22 pm
by Bob2002
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;
    }

Re: How to compute MAC

Posted: Fri Mar 03, 2017 2:08 pm
by simplyi
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!

Re: How to compute MAC

Posted: Fri Mar 03, 2017 10:53 pm
by UNKNwYSHSA
Are you talking about MAC calculation for GP SCP02?

Re: How to compute MAC

Posted: Sat Mar 04, 2017 1:45 am
by simplyi
I was looking for Retail MAC Calculation when I came across this discussion.

Re: How to compute MAC

Posted: Sun Mar 05, 2017 10:54 pm
by UNKNwYSHSA
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).

Re: How to compute MAC

Posted: Thu Jan 18, 2018 1:03 pm
by stanneraustin
Hello
i need some clarification on C-MAC if any one can guide.
my init update and ext auth work ok
after external auth i got ICV last verified with ext auth in output of external auth
now on next i plan to implement delete AID
i have to use same ICV where for next msg ?
i am testing on JCIDE with exmple
data = "84E400800A4F" + "08" + aiddata
results1 = des(data,S_MAChalf ) question is ICV use on this or next one ?
results2 = 3des(data+8,S_MAC)
my output return 69 82 i know i made mistake some where on C-MAC but documents do not explain perfectly nor any sample to understand this.

Re: How to compute MAC

Posted: Fri Jan 19, 2018 1:47 am
by BirdKing
According to GPC_Specification_v2.2.1, the ICV should be the MAC of the EXTERNAL AUTHENTICATE command.
The description from GPC_Specification_v2.2.1 is :
E.3.2 Message Integrity ICV using Explicit Secure Channel Initiation
When using explicit Secure Channel initiation, SCP02 mandates the use of a MAC on the EXTERNAL AUTHENTICATE command.
For the EXTERNAL AUTHENTICATE command MAC verification, the ICV is set to zero.
Once successfully verified, the MAC of the EXTERNAL AUTHENTICATE command becomes the ICV for the subsequent C-MAC verification and/or R-MAC generation.


I hole that would be useful for you.