【问题标题】:Authentication to ACR1255U-J1 reader via bluetooth通过蓝牙对 ACR1255U-J1 读卡器进行身份验证
【发布时间】:2020-05-17 14:28:06
【问题描述】:

为了与 ACR1255U-J1 NFC 阅读器进行通信,需要进行身份验证。使用十六进制字符串通过蓝牙连接。

这是我的两种加解密方法:

encrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value =  CryptoJS.enc.Hex.parse(valueStringHex);
    const key  = CryptoJS.enc.Hex.parse(keyStringHex);
    const encryptedStringHex = CryptoJS.AES.encrypt(value, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.ZeroPadding}).ciphertext.toString();
    return encryptedStringHex;
    }

decrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value = CryptoJS.enc.Hex.parse(valueStringHex);
    const key = CryptoJS.enc.Hex.parse(keyStringHex);
    const decryptedStringHex = CryptoJS.AES.decrypt({ciphertext: value}, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding});
    return decryptedStringHex.toString();
    }

阅读器附带了一个演示应用程序,我在该应用程序中记录了身份验证期间的蓝牙流量。我用 Wireshark 检查了这个。根据在 Wireshark 中看到的通信,我尝试在我的应用中证明我对身份验证过程的编码。

ACR1255 文档说:
第 1 步中:我从 ACR 阅读器收到一个使用客户主密钥加密的 16 字节随机数序列。我应该使用正确的解密它 客户主密钥 (41435231323535552d4a312041757468)。

根据 Wireshark 的说法,这是我在第一步从 ACR1255 阅读器(关键部分以粗体显示)收到的信息: 83001500000021E1000045005ff58680541c5a5903f4833dfaa428bf1c0a

decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
=> Result is 6064a82b7edf62986b0a2ec79e922aad

第 2 步:根据文档,我必须发送以下内容。
abAuthData[0:15] – 我生成的 16 个字节的随机数
abAuthData[16:31] – 从 ACR1255U-J1 接收到的 16 个字节的解密随机数(我猜这将是第一步 6064a82b7edf62986b0a2ec79e922aad 的结果)
总体32 字节随机数将使用客户主密钥解密并返回给 ACR1255U-J1 阅读器。

根据 Wireshark 的说法,这是演示应用程序现在发送到 ACR1255 阅读器的内容(关键部分以粗体显示):
6B0025000000EAE0000046007088e66af57bf04e66a8b2e83614f288 c8ed5005b914b51e50285a93408e14922c0a

当然,这是已经解密的密钥。为了证明我对工作流程的理解,我对其进行了加密,并希望将步骤 1 的结果作为密钥的第二部分。但事实并非如此。

encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
=> Result is 493aa0c5476f551d3b2bce664cfe4305*3b61bce6e4c0837be30453ddad165180*

我对文档中描述的工作流程有什么误解?是否能够以与文档不同的方式描述它?

文档也可以在here 找到。第 32 至 35 页。

附言。我知道,文档说 AES CBC 模式。但是没有使用IV,据我所知ECB模式的用法是一样的。

【问题讨论】:

  • CBC 与0-IV 和 ECB 的等价仅适用于密文的 first 块(AES 为 16 个字节)。第二步中使用的明文长度为 2 个块(AES 为 32 个字节),并生成一个 2 块密文(假设没有填充)。在这种情况下,带有0-IV 的 CBC 因此必须被 ECB 替换,因为第二个块的加密方式不同。顺便说一句,NoPadding 而不是ZeroPadding 应该在encrypt 中使用,不是吗(尽管这对长度是块大小整数倍的明文没有影响)?
  • @Topaco 视情况而定,一些基于零的填充实现(例如 Java 的 Bouncy Castle)总是 填充,就像 PKCS#5/7 一样。我不希望这是一般默认值,大多数只会在必要时填充(也是因为加密文本的通用用例,对于 C 环境,它本身已经是零填充)。虽然这里似乎不是这种情况,但值得关注。
  • @MaartenBodewes - 没错,有不同的零填充变体,必须小心。在我的评论中(CryptoJS.pad.ZeroPadding 表示 CryptoJS 实现,如果明文的长度已经是块大小的整数倍,则 not 填充。

标签: authentication encryption acr


【解决方案1】:

为了完整起见,我想添加解决方案。
根据@Topaco 的评论,我对欧洲央行模式有误。我将其更改为 CBC 并添加了 0-IV,它现在可以工作了。

decrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value = CryptoJS.enc.Hex.parse(valueStringHex);
    const key = CryptoJS.enc.Hex.parse(keyStringHex);
    const ivvar   = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
    const decryptedStringHex = CryptoJS.AES.decrypt({ciphertext: value}, key, {iv: ivvar, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding});
    return decryptedStringHex.toString();
    }

// in Step 1: 
// decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
// returns 6064a82b7edf62986b0a2ec79e922aad
encrypt(valueStringHex, keyStringHex) {
    const CryptoJS = require('crypto-js');
    const value =  CryptoJS.enc.Hex.parse(valueStringHex);
    const key  = CryptoJS.enc.Hex.parse(keyStringHex);
    const ivvar   = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
    const encryptedStringHex = CryptoJS.AES.encrypt(value, key, {iv: ivvar, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.NoPadding}).ciphertext.toString();
    return encryptedStringHex;
    }

// in Step 2:
// encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
// this is the decrypted string sent to the reader, which has to be encrypted here to proof that the key contains the result of step 1 in second 16 Byte block
// returns => 493aa0c5476f551d3b2bce664cfe43056064a82b7edf62986b0a2ec79e922aad (which is the return of Step 1 (in the second half))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-19
    • 2016-06-17
    • 2017-09-18
    • 2017-04-07
    • 2015-12-08
    • 2011-06-25
    • 2012-06-13
    • 1970-01-01
    相关资源
    最近更新 更多