Convert number to ArrayBuffer

别等时光非礼了梦想. 提交于 2021-02-10 12:21:19

问题


I'm trying to decrypt data on the browser using the AES-CTR algo. The WebCrypto API requires the counter to be passed as a BufferSource. How do I convert the counter (a number) to the expected input (a byte array)?

I'm using an all zero IV, so the counter starts at 0. Let's say I'm trying to decrypt data where counter = 445566. How do I convert 445566 into an 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)

EDIT: After digging around some crypto libraries, I ended up using this. It seems to do what I want, but no idea on correctness, performance, etc.

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
}

回答1:


Not sure if this is helpful. But just to cross check the authenticity of the code.

I wrote some test case to first convert the number to array buffer and use the array buffer value to decode it to the same.

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]

Both the results are same. It's just that your code is producing the result in big endian format and mine in little endian.

So the approach you have followed is correct. As for the performance i don't think there is much impact




回答2:


You don't need to do anything, the ArrayBuffer is initialized to bytes all with value zero, which of course also represents the number value zero using in statically unsigned, big endian encoding - which is the common way of representing the counter in CTR mode.

Here is the description of the return value of ArrayBuffer with just a specified size:

A new ArrayBuffer object of the specified size. Its contents are initialized to 0.

so there you go, you were ready without knowing it. The only thing I would certainly do is to comment that the counter in the buffer has been initialized to zero for the next developer (which may actually be you in a couple of years).

Note that CTR mode is secure if the counter is never repeated for the same key. For this, the nonce (which takes an unknown number of bytes to the left hand, most significant side) is commonly set to a random value, usually by simply initializing the first 8 bytes to random values. So you don't need to do any number encoding for that either.

You only need to encode the nonce if it consists of a 32 or 64 bit counter itself.




回答3:


This is what I use:

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
}


来源:https://stackoverflow.com/questions/55583037/convert-number-to-arraybuffer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!