java - "Visa2" key 多样化在金雅拓卡和 GPP 工具中如何工作?

标签 java cryptography smartcard emv visa

我有一堆金雅拓 java 卡,如下所示,我可以使用 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>

由于 VISA 文档不公开,我查看了 GlobalPlatformPro 源代码,以了解 visa2 的关键多样化是如何发生的,并在那里找到了这些方法:

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

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

主 key = 47454d5850524553534f53414d504c45

基于GlobalPlatform v 2.3 Card Specification :

Host_Challenge = 2CA286A611F6CAFD

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

  • 关键多元化数据 = 4D0041849D08192420C3
  • 关键信息= FF01:因此使用SCP01
  • 卡片挑战 = 31D644E9913234DD
  • 卡密码 = E1F0A6A462C71805

因此,基于上面的 GPP 源代码:

  • Diversification_Data = 4D00 9D081924 F001 4D00 9D081924 0F01

然后静态 ENC key 为:

Static_ENC = Encrypt(MasterKey, Diversification_Data )

所以,使用 this online tool ,我有:

enter image description here

这意味着:

Static_ENC_KEY = 84f2a84ecdade8cacc9e7e07faebe4e6

为了计算 ENC session key ,我再次使用 GlobalPlatform 规范:

enter image description here

所以我有:

  • Derivation_Data = 913234DD 2CA286A6 31D644E9 11F6CAFD

enter image description here

因此 ENC_Session_Key 是:

ENC_Session_Key = b1ed5ea3f69978274d2ffe0de467ec1c

最后,主机密码的生成和验证是通过连接 8 字节卡质询和 8 字节主机质询产生 16 字节 block 并将该 16 字节数组与 80 00 00 连接来执行的00 00 00 00 00 。然后使用 CBC 模式下的 ENC session key 和零 ICV 对此进行签名:

Data2Encrypt = 31D644E9913234DD 2CA286A611F6CAFD 8000000000000000

我有:

enter image description here

最佳答案

好吧,我尝试了两次上述步骤,每次最后我都遇到了错误的 host_cryptogram 值!但是当我重复这些步骤并在我的问题中逐行写下这些步骤时,我终于注意到我得到的最终结果与我问题的第一个问题中的 GPP 结果相同!因此,我没有删除我的问题,而是更愿意将其保留在这里以供将来的观众使用。

得出结论:

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

用于静态 key 计算的 Diversification_Data 为 ( source ):

enter image description here

INITAL UPDATE响应数据的前两个字节是相同的xxh xxh,其中的字节[4:8]是IC Serial Number

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

关于java - "Visa2" key 多样化在金雅拓卡和 GPP 工具中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37907039/

相关文章:

java - 无法使用 Firebase 云消息传递发送通知

ssl - 通过ssl在客户端和服务器之间解密和加密

c++ - 不使用 pin 列出来自 CAC 的证书

asp.net - 远程站点和客户端私钥

java - 如何比较java中的两个字符串并按字母顺序定义其中一个比另一个小?

java - 处理JSP中复杂的HashMap显示

Java:在 Calendar 对象中设置日期时,我可以使用日/月/年引用吗?

java - 如何使用 Java 使用 RSA 私钥

java - 在Java中生成有效的ES256签名

java - 使用 iText 访问智能卡