Java “怎么做?”;Visa2“;关键多样化在Gemalto卡和GPP工具中起作用?

Java “怎么做?”;Visa2“;关键多样化在Gemalto卡和GPP工具中起作用?,java,cryptography,smartcard,emv,visa,Java,Cryptography,Smartcard,Emv,Visa,我有一堆Gemalto java卡,正如您在下面看到的,我同意使用以下方式进行相互身份验证: 因此,我尝试为上述通信重复主机密码生成。我有: 主钥匙=47454D58505245534F53414D504C45 基于: 主机挑战=2CA286A611F6CAFD 初始更新响应:4D00041849D08192420C3 FF01 31D644E9913234DD E1F0A6A462C71805 关键多元化数据=4D004184D08192420C3 密钥信息=FF01:因此使用了SCP01

我有一堆Gemalto java卡,正如您在下面看到的,我同意使用以下方式进行相互身份验证:

因此,我尝试为上述通信重复主机密码生成。我有:

主钥匙=
47454D58505245534F53414D504C45

基于:

主机挑战=
2CA286A611F6CAFD

初始更新响应:
4D00041849D08192420C3 FF01 31D644E9913234DD E1F0A6A462C71805

  • 关键多元化数据=
    4D004184D08192420C3
  • 密钥信息=
    FF01
    :因此使用了SCP01
  • 卡片质询=
    31D644E9913234DD
  • 卡密码=
    E1F0A6A462C71805
因此,基于上面的GPP源代码:

  • 数据=
    4D00 9D081924 F001 4D00 9D081924 0F01
然后静态ENC键为:

Static_ENC = Encrypt(MasterKey, Diversification_Data )
因此,使用,我有:

这意味着:

静态加密键=
84f2a84ecdade8cacc9e7e07faebe4e6

为了计算ENC会话密钥,我再次使用了GlobalPlatform规范:

因此,我:

  • 派生数据=
    913234DD 2CA286A6 31D644E9 11F6CAFD

因此,
ENC_Session_键
是:

ENC\u Session\u Key=
b1ed5ea3f69978274d2ffe0de467ec1c

最后,主机密码的生成和验证是通过将8字节卡质询和8字节主机质询串联在一起,形成一个16字节的块,并将该16字节数组与
80 00
串联在一起来执行的。然后在CBC模式下使用ENC会话密钥以零ICV对此进行签名:

数据加密=
31D644E9913234DD 2CA286A611F6CAFD 80000000000000

我有:


好吧,我试了两次以上步骤,每次都遇到错误的主机密码值!但是当我重复这些步骤并在我的问题中逐行写下这些步骤时,我终于注意到我的最终结果与我第一个问题的GPP结果相等!因此,我不想删除我的问题,而是把它保留在这里,供未来的观众观看

综上所述:

在智能卡中加入密钥多样化方案,在GlobalPlatform卡规范中提到的用于计算卡密码和MAC值的步骤上增加了一个步骤。这一步就是计算静态键

用于静态键计算的U数据为():

初始更新响应数据的前两个字节是相同的
xxh xxh
,其字节[4:8]是
IC序列号


使用主密钥在ECB模式下使用三重DES算法加密多样化数据,返回静态密钥。

要检查卡密码,必须将主机质询的8字节与卡质询的8字节和“80000000000000”连接起来。 生成字符串后,然后在CBC模式下使用ENC会话密钥以零ICV对此进行签名

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;
}
Static_ENC = Encrypt(MasterKey, Diversification_Data )