javacryptographysmartcardemvvisa

How does "Visa2" key diversification works in Gemalto cards and in GPP tool?


I have a bunch of Gemalto java cards and as you see below, I'm okay with mutual authentication process using GlobalPlatformPro:

C:\globalPlatformPro> gp -visa2 -key 47454d5850524553534f53414d504c45 -list -debug -verbose -info

Reader: ACS ACR1281 1S Dual Reader ICC 0
ATR: 3B7D96000080318065B0831111E583009000

A>> 00A40400 00
A<< 6F198408A000000018434D00A50D9F6E061291921101009F6501FF 9000

***** Card info:
A>> 80CA9F7F 00
A<< 9F7F2A4090612812919211010041849D08192420C3033241840333418403344184000003250000000000000000 9000

***** KEY INFO
A>> 80CA00E0 00
A<< E012C00401FF8010C00402FF8010C00403FF8010 9000
VER:255 ID:1 TYPE:DES3 LEN:16
VER:255 ID:2 TYPE:DES3 LEN:16
VER:255 ID:3 TYPE:DES3 LEN:16
Key version suggests factory keys

A>> 80500000 08 2CA286A611F6CAFD 00
A<< 4D0041849D08192420C3FF0131D644E9913234DDE1F0A6A462C71805 9000
A>> 84820100 10 CC2D0CC35F6BD64F816A774D3ADB18F2
A<< 9000

//Useless lines for censored!

C:\globalPlatformPro>

As VISA documents are not publicly available, I took a look at GlobalPlatformPro source code to find out how the key diversification happens in for visa2, and I found these methods there:

public static GPKeySet diversify(GPKeySet keys, byte[] diversification_data, Diversification mode, int scp) throws GPException {
    try {
        GPKeySet result = new GPKeySet();
        Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
        for (KeyType v : KeyType.values()) {
            if (v == KeyType.RMAC)
                continue;
            byte [] kv = null;
            // shift around and fill initialize update data as required.
            if (mode == Diversification.VISA2) {
                kv = fillVisa(diversification_data, v);
            } else if (mode == Diversification.EMV) {
                kv = fillEmv(diversification_data, v);
            }

            // Encrypt with current master key
            cipher.init(Cipher.ENCRYPT_MODE, keys.getKey(v).getKey(Type.DES3));

            byte [] keybytes = cipher.doFinal(kv);
            // Replace the key, possibly changing type. G&D SCE 6.0 uses EMV 3DES and resulting keys
            // must be interpreted as AES-128
            GPKey nk = new GPKey(keybytes, scp == 3 ? Type.AES : Type.DES3);
            result.setKey(v, nk);
        }
        return result;
    } catch (BadPaddingException |InvalidKeyException | IllegalBlockSizeException e) {
        throw new GPException("Diversification failed.", e);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        throw new RuntimeException("Diversification failed.", e);
    }
}

public static byte[] fillVisa(byte[] init_update_response, KeyType key) {
    byte[] data = new byte[16];
    System.arraycopy(init_update_response, 0, data, 0, 2);
    System.arraycopy(init_update_response, 4, data, 2, 4);
    data[6] = (byte) 0xF0;
    data[7] = key.getValue();
    System.arraycopy(init_update_response, 0, data, 8, 2);
    System.arraycopy(init_update_response, 4, data, 10, 4);
    data[14] = (byte) 0x0F;
    data[15] = key.getValue();
    return data;
}

So I tried to repeat the host cryptogram generation for above communication. I have:

Master Key = 47454d5850524553534f53414d504c45

Based on GlobalPlatform v 2.3 Card Specification:

Host_Challenge = 2CA286A611F6CAFD

INITIAL UPDATE response: 4D0041849D08192420C3 FF01 31D644E9913234DD E1F0A6A462C71805

So, based on the GPP source code above:

And then the Static ENC Key is:

Static_ENC = Encrypt(MasterKey, Diversification_Data )

So, using this online tool, I have:

enter image description here

It means:

Static_ENC_KEY = 84f2a84ecdade8cacc9e7e07faebe4e6

To calculate ENC Session Key, I used GlobalPlatform Specification again:

enter image description here

So I have:

enter image description here

And so the ENC_Session_Key is:

ENC_Session_Key = b1ed5ea3f69978274d2ffe0de467ec1c

Finally, The generation and verification of the host cryptogram is performed by concatenating the 8-byte card challenge and 8-byte host challenge resulting in a 16-byte block and concatenating this 16-byte array with 80 00 00 00 00 00 00 00. Then signing this with the ENC session key in CBC mode with a zero ICV:

Data2Encrypt = 31D644E9913234DD 2CA286A611F6CAFD 8000000000000000

And I have:

enter image description here


Solution

  • Well, I tried above steps twice and each time, at the end I was faced with a wrong host_cryptogram value! But when I repeat the steps and wrote those line by line in my question, I finally noticed that the final result that I have is equal with the GPP result at the first of my question! So instead of deleting my question, I preferred to keep it here for future viewers.

    So to conclusion:

    Having key diversification schemes in a smart card, adds one step to those steps that is mentioned in GlobalPlatform Card Specification for calculating Card Cryptogram and MAC values. And that step is calculating Static Keys.

    Diversification_Data for Static Keys calculation are (source):

    enter image description here

    First two bytes of INITAL UPDATE response data is the same xxh xxh and bytes[4:8] of it are IC Serial Number.

    Encrypting Diversification data using Triple DES Algorithm in ECB mode with Master Key, returns Static Keys.