Changeset View
Changeset View
Standalone View
Standalone View
lib/utils/pkcs7-padding.test.js
// @flow | // @flow | ||||
import { pkcs7pad, pkcs7unpad } from './pkcs7-padding.js'; | import { | ||||
pkcs7pad, | |||||
pkcs7unpad, | |||||
superblockPad, | |||||
superblockUnpad, | |||||
} from './pkcs7-padding.js'; | |||||
describe('PKCS#7 Padding', () => { | describe('PKCS#7 Padding', () => { | ||||
it('should pad data to a multiple of blockSize bytes', () => { | it('should pad data to a multiple of blockSize bytes', () => { | ||||
const blockSize = 16; | const blockSize = 16; | ||||
const data = generateRandomData(100); | const data = generateRandomData(100); | ||||
const expectedPadding = 16 - (data.length % blockSize); | const expectedPadding = 16 - (data.length % blockSize); | ||||
const padded = pkcs7pad(data, blockSize); | const padded = pkcs7pad(data, blockSize); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | it('pkcs7pad and pkcs7unpad should be inverses', () => { | ||||
const data = generateRandomData(100); | const data = generateRandomData(100); | ||||
const padded = pkcs7pad(data, blockSize); | const padded = pkcs7pad(data, blockSize); | ||||
const unpadded = pkcs7unpad(padded); | const unpadded = pkcs7unpad(padded); | ||||
expect(unpadded.length).toBe(data.length); | expect(unpadded.length).toBe(data.length); | ||||
expect(unpadded).toEqual(data); | expect(unpadded).toEqual(data); | ||||
}); | }); | ||||
}); | }); | ||||
describe('superblock padding', () => { | |||||
it('should pad data to a multiple of superblockSize blocks', () => { | |||||
const blockSizeBytes = 16; | |||||
const superblockSizeBlocks = 4; | |||||
const dataLengthBytes = 3 * 16; | |||||
const expectedPaddedLength = 4 * 16; | |||||
const expectedBlockPadding = 1; | |||||
const data = generateRandomData(dataLengthBytes); | |||||
const padded = superblockPad(data, blockSizeBytes, superblockSizeBlocks); | |||||
expect(padded.length % expectedPaddedLength).toBe(0); | |||||
expect(padded[padded.length - 1]).toBe(expectedBlockPadding); | |||||
}); | |||||
it('pad should add a full superblock if input is a multiple of superblockSize blocks', () => { | |||||
const blockSizeBytes = 16; | |||||
const superblockSizeBlocks = 4; | |||||
const dataLengthBytes = 4 * 16; | |||||
const expectedPaddedLength = 8 * 16; | |||||
const expectedBlockPadding = 4; | |||||
const data = generateRandomData(dataLengthBytes); | |||||
const padded = superblockPad(data, blockSizeBytes, superblockSizeBlocks); | |||||
expect(padded.length % expectedPaddedLength).toBe(0); | |||||
expect(padded[padded.length - 1]).toBe(expectedBlockPadding); | |||||
}); | |||||
it('superblockUnpad should unpad data', () => { | |||||
const blockSizeBytes = 16; | |||||
// 2 blocks of data + 2 blocks of padding = 4 blocks total (1 superblock) | |||||
const padded = new Uint8Array([ | |||||
...generateRandomArray(2 * 16), | |||||
...new Array(2 * 16).fill(2), | |||||
]); | |||||
const unpadded = superblockUnpad(padded, blockSizeBytes); | |||||
expect(unpadded.length).toBe(32); | |||||
expect(unpadded).toEqual(padded.subarray(0, 32)); | |||||
}); | |||||
it('superblockUnpad should throw if the padding length is 0', () => { | |||||
const blockSizeBytes = 16; | |||||
const padded = new Uint8Array([ | |||||
...generateRandomArray(2 * 16), | |||||
...new Array(2 * 16).fill(0), | |||||
]); | |||||
expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow(); | |||||
}); | |||||
it('superblockUnpad should throw if the padding length is > num blocks', () => { | |||||
const blockSizeBytes = 16; | |||||
// 4 blocks total, but filled with 5s | |||||
const padded = new Uint8Array([ | |||||
...generateRandomArray(2 * 16), | |||||
...new Array(2 * 16).fill(5), | |||||
]); | |||||
expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow(); | |||||
}); | |||||
it('superblockUnpad should throw if the padding is invalid', () => { | |||||
const blockSizeBytes = 16; | |||||
const padded = new Uint8Array([ | |||||
...generateRandomArray(2 * 16), | |||||
...generateRandomArray(2 * 15), | |||||
...[1], | |||||
]); | |||||
expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow(); | |||||
}); | |||||
}); | |||||
function generateRandomData(length: number): Uint8Array { | function generateRandomData(length: number): Uint8Array { | ||||
const data = new Uint8Array(length); | const data = new Uint8Array(length); | ||||
for (let i = 0; i < length; i++) { | for (let i = 0; i < length; i++) { | ||||
data[i] = Math.floor(Math.random() * 256); | data[i] = Math.floor(Math.random() * 256); | ||||
} | } | ||||
return data; | return data; | ||||
} | } | ||||
function generateRandomArray(length: number): Array<number> { | function generateRandomArray(length: number): Array<number> { | ||||
return new Array(length).map(() => Math.floor(Math.random() * 256)); | return new Array(length).map(() => Math.floor(Math.random() * 256)); | ||||
} | } |