我正在尝试使用AES-CTR算法在浏览器上解密数据。 WebCrypto API要求计数器作为BufferSource传递。如何将计数器(数字)转换为预期的输入(字节数组)?
我正在使用全零的IV,因此计数器从0开始。假设我正在尝试解密计数器= 445566的数据。如何将445566转换为ArrayBuffer?
const key = // retrieve decryption key
const encrypted = // retrieve encrypted data
const iv = new ArrayBuffer(16)
// iv is all zeros. I need it to represent 445566, how?
const algo = {
name: 'AES-CTR',
counter: iv,
length: 128
}
const decrypted = await crypto.subtle.decrypt(algo, key, encrypted)
编辑:在研究了一些加密库之后,我最终使用了它。它似乎可以满足我的要求,但对正确性,性能等却一无所知。
function numberToArrayBuffer(value) {
const view = new DataView(new ArrayBuffer(16))
for (var index = 15; index >= 0; --index) {
view.setUint8(index, value % 256)
value = value >> 8;
}
return view.buffer
}
答案 0 :(得分:1)
有一种适用于 IE10+ 的单行解决方案 :)
new Int32Array([n]).buffer
答案 1 :(得分:0)
不确定这是否有帮助。但只是要交叉检查代码的真实性。
我写了一些测试用例,首先将数字转换为数组缓冲区,然后使用数组缓冲区值将其解码为相同的值。
var hex = 445566..toString(16);
var buffer = new ArrayBuffer(16);
var dataView = new DataView(buffer);
dataView.setInt32(0, '0x'+ hex);
console.log(dataView.getInt32(0)); //445566
//Using the uint16array data generated by the above code
var data = [0, 6, 204, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var buf = new ArrayBuffer(16);
var view = new DataView(buf);
data.forEach(function (b, i) {
view.setUint8(i, b % 256);
});
var num = view.getInt32(0);
console.log(num);//445566
function numberToArrayBuffer(value) {
const view = new DataView(new ArrayBuffer(16))
for (var index = 15; index >= 0; --index) {
view.setUint8(index, value % 256)
value = value >> 8;
}
return view.buffer
}
console.log(numberToArrayBuffer(445566)) // Uint8Array(16) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 204, 126]
结果都是一样的。只是您的代码以大字节序格式产生结果,而我的代码则以小字节序产生结果。
所以您遵循的方法是正确的。至于性能,我认为影响不大
答案 2 :(得分:0)
您无需执行任何操作,ArrayBuffer
会初始化为全部为零值的字节,当然,它也使用静态无符号大尾数编码表示数字值零(这是常见的方式)以CTR模式表示计数器的方法。
这是ArrayBuffer
的返回值的描述,它仅具有指定的大小:
具有指定大小的新
ArrayBuffer
对象。其内容初始化为0。
因此,您去那里时,您就已经准备好了,什么都不知道。我肯定会做的唯一一件事就是注释,该缓冲区中的计数器已为下一个开发人员(可能实际上是您几年)初始化为零。
请注意,如果从不为同一密钥重复计数器,则CTR模式是安全的。为此,通常将随机数(将<8>左手边的字节数未知,最高有效位)设为随机值,通常只需将前8个字节初始化为随机值即可。因此,您也不需要为此进行任何数字编码。
仅当随机数由32位或64位计数器本身组成时,才需要对其进行编码。
答案 3 :(得分:0)
这是我使用的:
const bytesArray = (n) => {
if (!n) return new ArrayBuffer(0)
const a = []
a.unshift(n & 255)
while (n >= 256) {
n = n >>> 8
a.unshift(n & 255)
}
return new Uint8Array(a).buffer
}
答案 4 :(得分:0)
const uIntToBytes = (num, size, method) => {
const arr = new ArrayBuffer(size)
const view = new DataView(arr)
view[method + (size * 8)](0, num)
return arr
}
const toBytes = (data, type) =>
type == "u8" ? uIntToBytes(data, 1, "setUint") :
type == "u16" ? uIntToBytes(data, 2, "setUint") :
type == "u32" ? uIntToBytes(data, 4, "setUint") :
type == "u64" ? uIntToBytes(BigInt(data), 8, "setBigUint")
: `Not Sure about type - ${type}`
用法:
toBytes(5, "u8")