通过蓝牙对 ACR1255U-J1 reader 进行身份验证
Authentication to ACR1255U-J1 reader via bluetooth
要与 ACR1255U-J1 NFC 进行通信 Reader,需要进行身份验证。使用十六进制字符串通过蓝牙连接。
这是我加解密的两种方法:
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();
}
随着 reader 出现了一个演示应用程序,我从中记录了身份验证期间的蓝牙流量。我用 Wireshark 检查了这个。基于在 Wireshark 中看到的通信,我尝试在我的应用程序中证明我对身份验证过程的编码。
ACR1255 文档说:
在步骤 1 中:我从 ACR reader 收到使用客户主密钥加密的 16 字节随机数序列。我应该使用正确的方式解密它
客户主密钥 (41435231323535552d4a312041757468)。
根据 Wireshark,这是我在第一步中从 ACR1255 reader(关键部分以粗体显示)收到的信息:
83001500000021E1000045005ff58680541c5a5903f4833dfaa428bf1c0a
decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
=> Result is 6064a82b7edf62986b0a2ec79e922aad
在第 2 步:根据文档,我必须发送以下内容。
abAuthData[0:15] – 由我生成的 16 字节随机数
abAuthData[16:31] – 从 ACR1255U-J1 收到的 16 字节解密随机数(我猜这是第一步 6064a82b7edf62986b0a2ec79e922aad 的结果)
全部 32 字节随机数将使用客户主密钥解密并返回到 ACR1255U-J1 reader。
根据 Wireshark,这是演示应用程序现在发送到 ACR1255 的内容 reader(关键部分以粗体显示):
6B0025000000EAE0000046007088e66af57bf04e66a8b2e83614f288 c8ed5005b914b51e50285a93408e14922c0a
当然,这是已经解密的密钥。为了证明我对工作流程的理解,我对其进行了加密,并希望看到步骤 1 的结果作为密钥的第二部分。但事实并非如此。
encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
=> Result is 493aa0c5476f551d3b2bce664cfe4305*3b61bce6e4c0837be30453ddad165180*
我对文档中描述的工作流程有什么误解?是否可以用与文档不同的方式来描述它?
还可以找到文档 here。第 32 至 35 页。
Ps。我知道,文档说 AES CBC 模式。但是没有使用 IV,据我所知,ECB 模式的用法是一样的。
为了完整起见,我想添加解决方案。
根据@Topaco 的评论,我对 ECB 模式的看法是错误的。我将其更改为 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))
要与 ACR1255U-J1 NFC 进行通信 Reader,需要进行身份验证。使用十六进制字符串通过蓝牙连接。
这是我加解密的两种方法:
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();
}
随着 reader 出现了一个演示应用程序,我从中记录了身份验证期间的蓝牙流量。我用 Wireshark 检查了这个。基于在 Wireshark 中看到的通信,我尝试在我的应用程序中证明我对身份验证过程的编码。
ACR1255 文档说:
在步骤 1 中:我从 ACR reader 收到使用客户主密钥加密的 16 字节随机数序列。我应该使用正确的方式解密它
客户主密钥 (41435231323535552d4a312041757468)。
根据 Wireshark,这是我在第一步中从 ACR1255 reader(关键部分以粗体显示)收到的信息: 83001500000021E1000045005ff58680541c5a5903f4833dfaa428bf1c0a
decrypt('5ff58680541c5a5903f4833dfaa428bf', '41435231323535552d4a312041757468')
=> Result is 6064a82b7edf62986b0a2ec79e922aad
在第 2 步:根据文档,我必须发送以下内容。
abAuthData[0:15] – 由我生成的 16 字节随机数
abAuthData[16:31] – 从 ACR1255U-J1 收到的 16 字节解密随机数(我猜这是第一步 6064a82b7edf62986b0a2ec79e922aad 的结果)
全部 32 字节随机数将使用客户主密钥解密并返回到 ACR1255U-J1 reader。
根据 Wireshark,这是演示应用程序现在发送到 ACR1255 的内容 reader(关键部分以粗体显示):
6B0025000000EAE0000046007088e66af57bf04e66a8b2e83614f288 c8ed5005b914b51e50285a93408e14922c0a
当然,这是已经解密的密钥。为了证明我对工作流程的理解,我对其进行了加密,并希望看到步骤 1 的结果作为密钥的第二部分。但事实并非如此。
encrypt('7088e66af57bf04e66a8b2e83614f288c8ed5005b914b51e50285a93408e1492', '41435231323535552d4a312041757468')
=> Result is 493aa0c5476f551d3b2bce664cfe4305*3b61bce6e4c0837be30453ddad165180*
我对文档中描述的工作流程有什么误解?是否可以用与文档不同的方式来描述它?
还可以找到文档 here。第 32 至 35 页。
Ps。我知道,文档说 AES CBC 模式。但是没有使用 IV,据我所知,ECB 模式的用法是一样的。
为了完整起见,我想添加解决方案。
根据@Topaco 的评论,我对 ECB 模式的看法是错误的。我将其更改为 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))