使用 crypto js AES ECB 算法在 JavaScript 中加密字节数组

Mar*_*tos 3 javascript arrays encryption iot react-native

我正在使用 React Native 应用程序与我的 miband 3 进行通信,其身份验证过程的一部分是使用 AES/ECB/NoPadding 算法加密字节数组。我目前正在使用此代码作为参考

由于我是物联网和加密领域的新手,我认为其身份验证的最后一步是不正确的,因为在将加密字节数组写入 miband 3 后,我没有得到正确的身份验证。

目前最后一步看起来像这样:

const base_key = [0x01,0x23,0x45,0x67,0x89,0x01,0x22,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90,0x02]
console.warn('Getting random number...')
const random_number = bytesToString(notification.filter((byte, index) => index > 3))

// Encrypting the key
const key = bytesToString(base_key)
const cipher = CryptoJS.AES.encrypt(random_number,key).toString()

// Step 5) Sending encrypted random number
console.warn('sending encrypted random number...')
const request_send_encrypted_key = [0x03,0x00, ...stringToBytes(cipher)]
await BleManager.writeWithoutResponse(miband3, service_uuid, characteristic_uuid, request_send_encrypted_key)
Run Code Online (Sandbox Code Playgroud)

通知被过滤,因为前 3 个字节用于告知正在发生哪个通知,所以我不需要它们。

我必须将以下内容发送到 miband 3 才能正确进行身份验证:

const byteArrayToSend = [0x03,0x00, ...encryptedByteArray]
Run Code Online (Sandbox Code Playgroud)

cryptoByteArray是我从 miband 通知返回的随机数(没有前 3 个字节)并正确加密。

我在代码中使用“crypto-js”和“react-native-ble-manager” 。

如何使用 AES 算法正确加密该字节数组以便发送它?

Top*_*aco 5

使用 AES 加密时必须考虑以下因素CryptoJS

  • 在发布的代码中,要加密的密钥和数据(random_number)显然被指定为数组。CryptoJS使用WordArray-objects,因此需要进行转换。使用这些函数和编码器可以轻松地将十六进制字符串转换为数组WordArray,反之亦然。另一种可能性是使用这些函数直接转换(未测试)。CryptoJS

  • 由于数组包含任意字节序列(从某种意义上说,它们通常不对应于任何可读字符),因此此处只能使用合适的编码(Base64 或十六进制)。方法bytesToStringstringToBytes没有贴出来,所以不清楚是否有问题。CryptoJS允许将数据作为字符串或 传递WordArray,其中后者在下面使用。

  • 如果 in 中的第二个参数CryptoJS.AES.encrypt作为字符串传递,则它将被解释为根据定义的算法生成实际密钥的密码短语(此处 )。如果要将第二个参数解释为键(参考代码中似乎就是这种情况),那么它必须作为WordArray.

  • AES/ECB/NoPadding根据链接的Medium-article用于加密。禁用填充是唯一可能的,因为要加密的数据(random_number根据文章长度为 16 字节)对应于 AES 块大小(16 字节)的整数倍(如果不是这种情况,填充将具有为强制性的)。

  • 加密的结果是一个CipherParams对象,其ciphertext属性包含加密数据WordArray此处为

考虑到这些点,可以按如下方式执行加密:

var CryptoJS = require("crypto-js");

// Key and random number as arrays, e.g.:
var random_numberBA = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f];
var keyBA = [0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x22, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x90, 0x02];

// Conversion to WordArrays
var random_numberWA = CryptoJS.enc.Hex.parse(bytesToHex(random_numberBA));
var keyWA = CryptoJS.enc.Hex.parse(bytesToHex(keyBA));

// Encryption
// - random_number as WordArray
// - Key as WordArray
// - ECB-Mode (default: CBC), No-Padding (default: Pkcs7-Padding)
var encryptedCP = CryptoJS.AES.encrypt(random_numberWA, keyWA, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });

// Encrypted data as WordArray
var encryptedWA = encryptedCP.ciphertext;

// Conversion to array
var encryptedBA = hexToBytes(CryptoJS.enc.Hex.stringify(encryptedWA));

// Consume encryptedBA 
// ...

// Helper: from /sf/answers/2404944601/
function hexToBytes(hex) {
    for (var bytes = [], c = 0; c < hex.length; c += 2)
        bytes.push(parseInt(hex.substr(c, 2), 16));
    return bytes;
}

function bytesToHex(bytes) {
    for (var hex = [], i = 0; i < bytes.length; i++) {
        var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
        hex.push((current >>> 4).toString(16));
        hex.push((current & 0xF).toString(16));
    }
    return hex.join("");
}
Run Code Online (Sandbox Code Playgroud)

结果可以在此处进行验证。