Javascript 将数字转换为ArrayBuffer

Javascript 将数字转换为ArrayBuffer,javascript,cryptography,aes,webcrypto-api,Javascript,Cryptography,Aes,Webcrypto Api,我正在尝试使用AES-CTR算法解密浏览器上的数据。要求将计数器作为传递。如何将计数器(数字)转换为预期的输入(字节数组) 我用的是全零IV,所以计数器从0开始。假设我试图解密计数器=445566的数据。如何将445566转换为ArrayBuffer const key = // retrieve decryption key const encrypted = // retrieve encrypted data const iv = new ArrayBuffer(16) // iv is

我正在尝试使用AES-CTR算法解密浏览器上的数据。要求将计数器作为传递。如何将计数器(数字)转换为预期的输入(字节数组)

我用的是全零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
}

不确定这是否有用。但只是交叉检查代码的真实性

我编写了一些测试用例,首先将数字转换为数组缓冲区,并使用数组缓冲区值将其解码为相同的值

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]
这两个结果是相同的。只是您的代码以大端格式生成结果,而我的代码以小端格式生成结果


因此,您所采用的方法是正确的。至于性能,我认为没有太大影响

您不需要做任何事情,
ArrayBuffer
被初始化为字节,所有字节的值都为零,这当然也表示在静态无符号、大端编码中使用的数值零,这是CTR模式中表示计数器的常用方式

以下是仅使用指定大小的
ArrayBuffer
返回值的说明:

指定大小的新
ArrayBuffer
对象。其内容已初始化为0

好了,你已经准备好了。我唯一肯定要做的就是评论缓冲区中的计数器已经为下一个开发人员初始化为零(可能几年后就是您)

请注意,如果同一密钥从未重复计数器,则CTR模式是安全的。为此,nonce(在左手边,最有效的一侧取未知数量的字节)通常设置为随机值,通常只需将前8个字节初始化为随机值即可。所以你也不需要做任何数字编码

如果nonce本身由32位或64位计数器组成,则只需对其进行编码。

这就是我使用的:

constbytesarray=(n)=>{
如果(!n)返回新的ArrayBuffer(0)
常数a=[]
a、 取消移位(n&255)
而(n>=256){
n=n>>>8
a、 取消移位(n&255)
}
返回新的Uint8Array(a).buffer
}

IE10+有一个单行解决方案:)


下面是我如何在nodejs上完成的

constuinttobytes=(num,size,method)=>{
const arr=新阵列缓冲区(大小)
常量视图=新数据视图(arr)
视图[方法+(大小*8)](0,个)
返回缓冲区。从(arr)
}
常数toBytes=(数据,类型)=>
类型==“u8”?uIntToBytes(数据,1,“setUint”):
类型==“u16”?uIntToBytes(数据,2,“setUint”):
类型==“u32”?uIntToBytes(数据,4,“setUint”):
类型==“u64”?uIntToBytes(BigInt(数据),8,“setBigUint”)
:Buffer.from(数据,类型)
对于ArrayBuffers,稍微更改的版本应该是:

constuinttobytes=(num,size,method)=>{
const arr=新阵列缓冲区(大小)
常量视图=新数据视图(arr)
视图[方法+(大小*8)](0,个)
返回arr
}
常数toBytes=(数据,类型)=>
类型==“u8”?uIntToBytes(数据,1,“setUint”):
类型==“u16”?uIntToBytes(数据,2,“setUint”):
类型==“u32”?uIntToBytes(数据,4,“setUint”):
类型==“u64”?uIntToBytes(BigInt(数据),8,“setBigUint”)
:`不确定类型-${type}`
用法:

toBytes(5,“u8”)

您是如何在加密过程中创建整数计数器的?就像这样,在节点:
const iv=Buffer.alloc(16)
中。我被告知,如果密钥仅用于加密单个消息,则全零iv就可以了。在客户端,我希望解密给定字节范围的数据,如243-695。所以我需要从字节范围的第一个值派生一个计数器ArrayBuffer。
new Int32Array([n]).buffer