Last active
November 23, 2024 20:14
-
-
Save Rychu-Pawel/b8e944db7534342931e78c1c039633c3 to your computer and use it in GitHub Desktop.
NodeJS AES-256-CTR IV counter increment functions test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is a comparison-test of multiple IV counter increment functions I found on the internet and created myself. | |
The goal here was to pick the most reliable one. | |
`incrementIVOriginal` comes from https://stackoverflow.com/questions/49954020/is-it-possible-to-decipher-at-random-position-with-nodejs-crypto | |
Run with: | |
> npx ava | |
Output: | |
$ npx ava --timeout=10m | |
- [skip] incrementIVOpenSSL - Increment by maximum possible value | |
✔ ORIGINAL - Increment by 1 (6m 58.1s) | |
✔ ORIGINAL - Incrementation causing transfer between segments (6m 58.1s) | |
✘ [fail]: ORIGINAL - Increment by MAX_UINT32 Error thrown in test | |
✔ ORIGINAL - Increment over 64 bits (6m 58s) | |
✘ [fail]: ORIGINAL - Increment by a big value Error thrown in test | |
✔ ORIGINAL - Increment causing overflow of entire IV (6m 58s) | |
✘ [fail]: ORIGINAL - Increment by maximum possible value | |
✔ incrementIVFixed - Increment by 1 (6m 58s) | |
✔ incrementIVFixed - Incrementation causing transfer between segments (6m 58s) | |
✔ incrementIVFixed - Increment by MAX_UINT32 (6m 58s) | |
✔ incrementIVFixed - Increment over 64 bits (6m 58s) | |
✔ incrementIVFixed - Increment by a big value (6m 58s) | |
✔ incrementIVFixed - Increment causing overflow of entire IV (6m 58s) | |
✘ [fail]: incrementIVFixed - Increment by maximum possible value | |
✔ incrementIVBigInt - Increment by 1 (6m 58s) | |
✔ incrementIVBigInt - Incrementation causing transfer between segments (6m 58s) | |
✔ incrementIVBigInt - Increment by MAX_UINT32 (6m 58s) | |
✔ incrementIVBigInt - Increment over 64 bits (6m 58s) | |
✔ incrementIVBigInt - Increment by a big value (6m 58s) | |
✔ incrementIVBigInt - Increment causing overflow of entire IV (6m 58s) | |
✔ incrementIVBigInt - Increment by maximum possible value (6m 58s) | |
✔ incrementIVOpenSSL - Increment by 1 (6m 58s) | |
✔ incrementIVOpenSSL - Incrementation causing transfer between segments (6m 58s) | |
✔ incrementIVOpenSSL - Increment by MAX_UINT32 (6m 58s) | |
✔ incrementIVOpenSSL - Increment over 64 bits (5m 13.4s) | |
✔ incrementIVOpenSSL - Increment by a big value (3m 29.5s) | |
✔ incrementIVOpenSSL - Increment causing overflow of entire IV | |
✔ incrementIVCryptoAesCtr - Increment by 1 | |
✔ incrementIVCryptoAesCtr - Incrementation causing transfer between segments | |
✔ incrementIVCryptoAesCtr - Increment by MAX_UINT32 | |
✔ incrementIVCryptoAesCtr - Increment over 64 bits | |
✔ incrementIVCryptoAesCtr - Increment by a big value | |
✘ [fail]: incrementIVCryptoAesCtr - Increment causing overflow of entire IV | |
✘ [fail]: incrementIVCryptoAesCtr - Increment by maximum possible value | |
─ | |
ORIGINAL - Increment by MAX_UINT32 | |
Error thrown in test: | |
RangeError { | |
code: 'ERR_OUT_OF_RANGE', | |
message: 'The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -1', | |
} | |
RangeError [ERR_OUT_OF_RANGE]: The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -1 | |
at checkInt (node:internal/buffer:74:11) | |
at writeU_Int32BE (node:internal/buffer:804:3) | |
at Buffer.writeUInt32BE (node:internal/buffer:817:10) | |
at incrementIVOriginal (file:///C:/Users/Rychu/Desktop/Temp/aes/test.spec.mjs:502:12) | |
at file:///C:/Users/Rychu/Desktop/Temp/aes/test.spec.mjs:39:5 | |
at Test.callFn (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/test.js:525:26) | |
at Test.run (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/test.js:534:33) | |
at Runner.runSingle (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/runner.js:281:33) | |
at Runner.runTest (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/runner.js:363:30) | |
at process.processTicksAndRejections (node:internal/process/task_queues:105:5) | |
ORIGINAL - Increment by a big value | |
Error thrown in test: | |
RangeError { | |
code: 'ERR_OUT_OF_RANGE', | |
message: 'The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -1', | |
} | |
RangeError [ERR_OUT_OF_RANGE]: The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -1 | |
at checkInt (node:internal/buffer:74:11) | |
at writeU_Int32BE (node:internal/buffer:804:3) | |
at Buffer.writeUInt32BE (node:internal/buffer:817:10) | |
at incrementIVOriginal (file:///C:/Users/Rychu/Desktop/Temp/aes/test.spec.mjs:502:12) | |
at file:///C:/Users/Rychu/Desktop/Temp/aes/test.spec.mjs:67:5 | |
at Test.callFn (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/test.js:525:26) | |
at Test.run (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/test.js:534:33) | |
at Runner.runSingle (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/runner.js:281:33) | |
at Runner.runTest (file:///C:/Users/Rychu/Desktop/Temp/aes/node_modules/ava/lib/runner.js:363:30) | |
at process.processTicksAndRejections (node:internal/process/task_queues:105:5) | |
ORIGINAL - Increment by maximum possible value | |
test.spec.mjs:92 | |
91: | |
92: t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
93: }); | |
Difference (- actual, + expected): | |
- '00000000000000000000000000000001' | |
+ 'ffffffffffffffffffffffffffffffff' | |
› file:///test.spec.mjs:92:7 | |
incrementIVFixed - Increment by maximum possible value | |
test.spec.mjs:188 | |
187: | |
188: t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
189: }); | |
Difference (- actual, + expected): | |
- '00000000000000010000000000000000' | |
+ 'ffffffffffffffffffffffffffffffff' | |
› file:///test.spec.mjs:188:7 | |
incrementIVCryptoAesCtr - Increment causing overflow of entire IV | |
test.spec.mjs:466 | |
465: | |
466: t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
467: }); | |
Difference (- actual, + expected): | |
- '00000000000000000000000000000003' | |
+ '00000000000000000000000000000002' | |
› file:///test.spec.mjs:466:7 | |
incrementIVCryptoAesCtr - Increment by maximum possible value | |
test.spec.mjs:477 | |
476: | |
477: t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
478: }); | |
Difference (- actual, + expected): | |
- '00000000000000000000000000000001' | |
+ 'ffffffffffffffffffffffffffffffff' | |
› file:///test.spec.mjs:477:7 | |
─ | |
6 tests failed | |
1 test skipped | |
*/ | |
import test from "ava"; | |
test(`ORIGINAL - Increment by 1`, t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000000000000000000000000000001', 'hex'); | |
// Act | |
incrementIVOriginal(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Incrementation causing transfer between segments ', t => { | |
// Arrange | |
const originalIV = Buffer.from('00000000FFFFFFFFFFFFFFFFFFFFFFFF', 'hex'); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000001000000000000000000000000', 'hex'); | |
// Act | |
incrementIVOriginal(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Increment by MAX_UINT32', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0xFFFFFFFF; | |
const expectedIV = Buffer.from('000000000000000000000000FFFFFFFF', 'hex'); | |
// Act | |
incrementIVOriginal(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Increment over 64 bits', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1_00000000; // 2^32 | |
const expectedIV = Buffer.from('00000000000000000000000100000000', 'hex'); | |
// Act | |
incrementIVOriginal(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Increment by a big value', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1FFFFFFFF; // 2^33 - 1 | |
const expectedIV = Buffer.from('000000000000000000000001FFFFFFFF', 'hex'); | |
// Act | |
incrementIVOriginal(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Increment causing overflow of entire IV', t => { | |
const originalIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
const increment = 3; | |
const expectedIV = Buffer.from('00000000000000000000000000000002', 'hex'); | |
incrementIVOriginal(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('ORIGINAL - Increment by maximum possible value', t => { | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0xffffffffffffffffffffffffffffffff; // 2^128 - 1 | |
const expectedIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
incrementIVOriginal(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
/////////////////// | |
// Fixed below | |
/////////////////// | |
test(`incrementIVFixed - Increment by 1`, t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000000000000000000000000000001', 'hex'); | |
// Act | |
incrementIVFixed(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Incrementation causing transfer between segments ', t => { | |
// Arrange | |
const originalIV = Buffer.from('00000000FFFFFFFFFFFFFFFFFFFFFFFF', 'hex'); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000001000000000000000000000000', 'hex'); | |
// Act | |
incrementIVFixed(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Increment by MAX_UINT32', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0xFFFFFFFF; | |
const expectedIV = Buffer.from('000000000000000000000000FFFFFFFF', 'hex'); | |
// Act | |
incrementIVFixed(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Increment over 64 bits', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1_00000000; // 2^32 | |
const expectedIV = Buffer.from('00000000000000000000000100000000', 'hex'); | |
// Act | |
incrementIVFixed(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Increment by a big value', t => { | |
// Arrange | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1FFFFFFFF; // 2^33 - 1 | |
const expectedIV = Buffer.from('000000000000000000000001FFFFFFFF', 'hex'); | |
// Act | |
incrementIVFixed(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Increment causing overflow of entire IV', t => { | |
const originalIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
const increment = 3; | |
const expectedIV = Buffer.from('00000000000000000000000000000002', 'hex'); | |
incrementIVFixed(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVFixed - Increment by maximum possible value', t => { | |
const originalIV = Buffer.alloc(16, 0); | |
const increment = 0xffffffffffffffffffffffffffffffff; // 2^128 - 1 | |
const expectedIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
incrementIVFixed(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
/////////////////// | |
// BigInt below | |
/////////////////// | |
test(`incrementIVBigInt - Increment by 1`, t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000000000000000000000000000001', 'hex'); | |
// Act | |
originalIV = incrementIVBigInt(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Incrementation causing transfer between segments ', t => { | |
// Arrange | |
let originalIV = Buffer.from('00000000FFFFFFFFFFFFFFFFFFFFFFFF', 'hex'); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000001000000000000000000000000', 'hex'); | |
// Act | |
originalIV = incrementIVBigInt(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Increment by MAX_UINT32', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0xFFFFFFFF; | |
const expectedIV = Buffer.from('000000000000000000000000FFFFFFFF', 'hex'); | |
// Act | |
originalIV = incrementIVBigInt(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Increment over 64 bits', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1_00000000; // 2^32 | |
const expectedIV = Buffer.from('00000000000000000000000100000000', 'hex'); | |
// Act | |
originalIV = incrementIVBigInt(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Increment by a big value', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1FFFFFFFF; // 2^33 - 1 | |
const expectedIV = Buffer.from('000000000000000000000001FFFFFFFF', 'hex'); | |
// Act | |
originalIV = incrementIVBigInt(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Increment causing overflow of entire IV', t => { | |
let originalIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
const increment = 3; | |
const expectedIV = Buffer.from('00000000000000000000000000000002', 'hex'); | |
originalIV = incrementIVBigInt(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVBigInt - Increment by maximum possible value', t => { | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = BigInt('0xffffffffffffffffffffffffffffffff'); // 2^128 - 1 | |
const expectedIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
originalIV = incrementIVBigInt(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
/////////////////// | |
// OpenSSL below - these takes dozen of minutes. Uncomment if you have a lot of time | |
/////////////////// | |
// test(`incrementIVOpenSSL - Increment by 1`, t => { | |
// // Arrange | |
// const originalIV = Buffer.alloc(16, 0); | |
// const increment = 1; | |
// const expectedIV = Buffer.from('00000000000000000000000000000001', 'hex'); | |
// // Act | |
// incrementIVOpenSSL(originalIV, increment); | |
// // Assert | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// test('incrementIVOpenSSL - Incrementation causing transfer between segments ', t => { | |
// // Arrange | |
// const originalIV = Buffer.from('00000000FFFFFFFFFFFFFFFFFFFFFFFF', 'hex'); | |
// const increment = 1; | |
// const expectedIV = Buffer.from('00000001000000000000000000000000', 'hex'); | |
// // Act | |
// incrementIVOpenSSL(originalIV, increment); | |
// // Assert | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// test('incrementIVOpenSSL - Increment by MAX_UINT32', t => { | |
// // Arrange | |
// const originalIV = Buffer.alloc(16, 0); | |
// const increment = 0xFFFFFFFF; | |
// const expectedIV = Buffer.from('000000000000000000000000FFFFFFFF', 'hex'); | |
// // Act | |
// incrementIVOpenSSL(originalIV, increment); | |
// // Assert | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// test('incrementIVOpenSSL - Increment over 64 bits', t => { | |
// // Arrange | |
// const originalIV = Buffer.alloc(16, 0); | |
// const increment = 0x1_00000000; // 2^32 | |
// const expectedIV = Buffer.from('00000000000000000000000100000000', 'hex'); | |
// // Act | |
// incrementIVOpenSSL(originalIV, increment); | |
// // Assert | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// test('incrementIVOpenSSL - Increment by a big value', t => { | |
// // Arrange | |
// const originalIV = Buffer.alloc(16, 0); | |
// const increment = 0x1FFFFFFFF; // 2^33 - 1 | |
// const expectedIV = Buffer.from('000000000000000000000001FFFFFFFF', 'hex'); | |
// // Act | |
// incrementIVOpenSSL(originalIV, increment); | |
// // Assert | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// test('incrementIVOpenSSL - Increment causing overflow of entire IV', t => { | |
// const originalIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
// const increment = 3; | |
// const expectedIV = Buffer.from('00000000000000000000000000000002', 'hex'); | |
// incrementIVOpenSSL(originalIV, increment); | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
// // The below is not possible to test because it requires significant amount of time | |
// test.skip('incrementIVOpenSSL - Increment by maximum possible value', t => { | |
// const originalIV = Buffer.alloc(16, 0); | |
// const increment = BigInt('0xffffffffffffffffffffffffffffffff'); // 2^128 - 1 | |
// const expectedIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
// incrementIVOpenSSL(originalIV, increment); | |
// t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
// }); | |
/////////////////// | |
// incrementIVCryptoAesCtr below | |
/////////////////// | |
test(`incrementIVCryptoAesCtr - Increment by 1`, t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000000000000000000000000000001', 'hex'); | |
// Act | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Incrementation causing transfer between segments ', t => { | |
// Arrange | |
let originalIV = Buffer.from('00000000FFFFFFFFFFFFFFFFFFFFFFFF', 'hex'); | |
const increment = 1; | |
const expectedIV = Buffer.from('00000001000000000000000000000000', 'hex'); | |
// Act | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Increment by MAX_UINT32', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0xFFFFFFFF; | |
const expectedIV = Buffer.from('000000000000000000000000FFFFFFFF', 'hex'); | |
// Act | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Increment over 64 bits', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1_00000000; // 2^32 | |
const expectedIV = Buffer.from('00000000000000000000000100000000', 'hex'); | |
// Act | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Increment by a big value', t => { | |
// Arrange | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0x1FFFFFFFF; // 2^33 - 1 | |
const expectedIV = Buffer.from('000000000000000000000001FFFFFFFF', 'hex'); | |
// Act | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
// Assert | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Increment causing overflow of entire IV', t => { | |
let originalIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
const increment = 3; | |
const expectedIV = Buffer.from('00000000000000000000000000000002', 'hex'); | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
test('incrementIVCryptoAesCtr - Increment by maximum possible value', t => { | |
let originalIV = Buffer.alloc(16, 0); | |
const increment = 0xffffffffffffffffffffffffffffffff; // 2^128 - 1 | |
const expectedIV = Buffer.from('ffffffffffffffffffffffffffffffff', 'hex'); | |
originalIV = incrementIVCryptoAesCtr(originalIV, increment); | |
t.is(originalIV.toString('hex'), expectedIV.toString('hex')); | |
}); | |
function incrementIVOriginal(iv, increment) { | |
if (iv.length !== 16) throw new Error('Only implemented for 16 bytes IV'); | |
const MAX_UINT32 = 0xFFFFFFFF; | |
let incrementBig = ~~(increment / MAX_UINT32); | |
let incrementLittle = (increment % MAX_UINT32) - incrementBig; | |
// split the 128bits IV in 4 numbers, 32bits each | |
let overflow = 0; | |
for (let idx = 0; idx < 4; ++idx) { | |
let num = iv.readUInt32BE(12 - idx * 4); | |
let inc = overflow; | |
if (idx == 0) inc += incrementLittle; | |
if (idx == 1) inc += incrementBig; | |
num += inc; | |
let numBig = ~~(num / MAX_UINT32); | |
let numLittle = (num % MAX_UINT32) - numBig; | |
overflow = numBig; | |
iv.writeUInt32BE(numLittle, 12 - idx * 4); | |
} | |
} | |
function incrementIVFixed(iv, increment) { | |
if (iv.length !== 16) throw new Error('Only implemented for 16 bytes IV'); | |
const MAX_UINT32 = 0xFFFFFFFF; | |
let incrementHigh = Math.floor(increment / (MAX_UINT32 + 1)); | |
let incrementLow = increment % (MAX_UINT32 + 1); | |
let overflow = 0; | |
for (let idx = 3; idx >= 0; --idx) { | |
let num = iv.readUInt32BE(idx * 4); | |
let inc = overflow; | |
if (idx === 3) inc += incrementLow; | |
if (idx === 2) inc += incrementHigh; | |
num += inc; | |
overflow = num > MAX_UINT32 ? 1 : 0; | |
num = num >>> 0; // Convert to unsigned 32-bit integer | |
iv.writeUInt32BE(num, idx * 4); | |
} | |
} | |
function incrementIVBigInt(iv, increment) { | |
// Convert IV to BigInt | |
let ivBigInt = BigInt('0x' + iv.toString('hex')); | |
// Increment | |
ivBigInt += BigInt(increment); | |
// Modulo 2^128 to ensure 128-bit range | |
ivBigInt = ivBigInt % (BigInt(1) << BigInt(128)); | |
// Convert back to buffer | |
let incrementedIVHex = ivBigInt.toString(16).padStart(32, '0'); | |
return Buffer.from(incrementedIVHex, 'hex'); | |
} | |
function incrementIVOpenSSL(iv, increment) { | |
for (let i = 0; i < increment; i++) | |
ctr128Inc(iv) | |
} | |
function ctr128Inc(counter) { | |
let c = 1; | |
let n = 16; | |
do { | |
n -= 1; | |
c += counter[n]; | |
counter[n] = c & 0xFF; | |
c = c >> 8; | |
} while (n); | |
} | |
function incrementIVCryptoAesCtr(iv, increment) { | |
var i, len, mod; | |
len = iv.length; | |
i = len - 1; | |
while (increment !== 0) { | |
mod = (increment + iv[i]) % 256; | |
increment = Math.floor((increment + iv[i]) / 256); | |
iv[i] = mod; | |
i -= 1; | |
if (i < 0) { | |
i = len - 1; | |
} | |
} | |
return iv; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment