将数字转换为ArrayBuffer

时间:2019-04-08 23:16:52

标签: javascript cryptography aes webcryptoapi

我正在尝试使用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
}

5 个答案:

答案 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")