Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3406385
D7061.id23693.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D7061.id23693.diff
View Options
diff --git a/lib/utils/pkcs7-padding.js b/lib/utils/pkcs7-padding.js
--- a/lib/utils/pkcs7-padding.js
+++ b/lib/utils/pkcs7-padding.js
@@ -16,6 +16,56 @@
import invariant from 'invariant';
+export type PaddingConfiguration = {
+ +blockSizeBytes: number,
+ +superblockSizeBlocks: number,
+};
+
+/**
+ * The padding configuration for 10KB superblocks.
+ * The block size is 250 bytes, and the superblock size is 40 blocks.
+ */
+export const PKCS7_10KB: PaddingConfiguration = {
+ blockSizeBytes: 250,
+ superblockSizeBlocks: 40,
+};
+
+/**
+ * Pads the input using the extended PKCS#7 padding (superblock padding).
+ * The input is first padded using the standard PKCS#7 padding, and then
+ * padded to the nearest multiple of superblocks (blocks of blocks).
+ *
+ * @param {Uint8Array} data - The input to be padded.
+ * @param {PaddingConfiguration} paddingConfiguration - The padding
+ * configuration. Defaults to multiple of 10KB. See {@link PKCS7_10KB}.
+ * @returns {Uint8Array} The padded input.
+ */
+export function pad(
+ data: Uint8Array,
+ { blockSizeBytes, superblockSizeBlocks }: PaddingConfiguration = PKCS7_10KB,
+): Uint8Array {
+ const pkcs7Padded = pkcs7pad(data, blockSizeBytes);
+ return superblockPad(pkcs7Padded, blockSizeBytes, superblockSizeBlocks);
+}
+
+/**
+ * Unpads the input using the extended PKCS#7 padding (superblock padding).
+ * The input is first unpadded on the block basis, and then unpadded using
+ * the standard PKCS#7 padding.
+ *
+ * @param {Uint8Array} data - The input to be unpadded.
+ * @param {PaddingConfiguration} paddingConfiguration - The padding
+ * configuration. Defaults to multiple of 10KB. See {@link PKCS7_10KB}.
+ * @returns {Uint8Array} The unpadded input.
+ */
+export function unpad(
+ data: Uint8Array,
+ { blockSizeBytes }: PaddingConfiguration = PKCS7_10KB,
+): Uint8Array {
+ const blockUnpadded = superblockUnpad(data, blockSizeBytes);
+ return pkcs7unpad(blockUnpadded);
+}
+
/**
* PKCS#7 padding function for `Uint8Array` data.
*
@@ -23,7 +73,7 @@
* @param {number} blockSizeBytes - The block size in bytes.
* @returns {Uint8Array} The padded data as a new Uint8Array.
*/
-export function pkcs7pad(data: Uint8Array, blockSizeBytes: number): Uint8Array {
+function pkcs7pad(data: Uint8Array, blockSizeBytes: number): Uint8Array {
invariant(blockSizeBytes > 0, 'block size must be positive');
invariant(blockSizeBytes < 256, 'block size must be less than 256');
const padding = blockSizeBytes - (data.length % blockSizeBytes);
@@ -40,7 +90,7 @@
* @returns {Uint8Array} The unpadded data as a new Uint8Array.
* @throws {Error} If the padding is invalid.
*/
-export function pkcs7unpad(data: Uint8Array): Uint8Array {
+function pkcs7unpad(data: Uint8Array): Uint8Array {
const padding = data[data.length - 1];
invariant(padding > 0, 'padding must be positive');
invariant(data.length >= padding, 'data length must be at least padding');
@@ -63,7 +113,7 @@
* @param {number} superblockSize - The superblock size in blocks.
* @returns {Uint8Array} The block-padded data as a new Uint8Array.
*/
-export function superblockPad(
+function superblockPad(
data: Uint8Array,
blockSizeBytes: number,
superblockSize: number,
@@ -96,10 +146,7 @@
* @param {number} blockSizeBytes - The block size in bytes.
* @returns {Uint8Array} - The unpadded data as a new Uint8Array.
*/
-export function superblockUnpad(
- data: Uint8Array,
- blockSizeBytes: number,
-): Uint8Array {
+function superblockUnpad(data: Uint8Array, blockSizeBytes: number): Uint8Array {
invariant(blockSizeBytes > 0, 'block size must be positive');
invariant(blockSizeBytes <= 255, 'block size must be less than 256');
invariant(
@@ -121,3 +168,11 @@
const unpaddedData = data.subarray(0, unpaddedLengthBytes);
return unpaddedData;
}
+
+// exported for testing purposes only
+export const testing = {
+ pkcs7pad,
+ pkcs7unpad,
+ superblockPad,
+ superblockUnpad,
+};
diff --git a/lib/utils/pkcs7-padding.test.js b/lib/utils/pkcs7-padding.test.js
--- a/lib/utils/pkcs7-padding.test.js
+++ b/lib/utils/pkcs7-padding.test.js
@@ -1,11 +1,7 @@
// @flow
-import {
- pkcs7pad,
- pkcs7unpad,
- superblockPad,
- superblockUnpad,
-} from './pkcs7-padding.js';
+import type { PaddingConfiguration } from './pkcs7-padding';
+import { pad, unpad, testing } from './pkcs7-padding.js';
describe('PKCS#7 Padding', () => {
it('should pad data to a multiple of blockSize bytes', () => {
@@ -13,7 +9,7 @@
const data = generateRandomData(100);
const expectedPadding = 16 - (data.length % blockSize);
- const padded = pkcs7pad(data, blockSize);
+ const padded = testing.pkcs7pad(data, blockSize);
expect(padded.length % 16).toBe(0);
expect(padded[padded.length - 1]).toBe(expectedPadding);
});
@@ -23,15 +19,15 @@
const data = generateRandomData(16);
const expectedPadding = 16;
- const padded = pkcs7pad(data, blockSize);
+ const padded = testing.pkcs7pad(data, blockSize);
expect(padded.length % 16).toBe(0);
expect(padded[padded.length - 1]).toBe(expectedPadding);
});
it('pkcs7pad should fail if blockSize is out of 1-255 range', () => {
const data = generateRandomData(16);
- expect(() => pkcs7pad(data, 0)).toThrow();
- expect(() => pkcs7pad(data, 256)).toThrow();
+ expect(() => testing.pkcs7pad(data, 0)).toThrow();
+ expect(() => testing.pkcs7pad(data, 256)).toThrow();
});
it('pkcs7unpad should unpad data', () => {
@@ -41,7 +37,7 @@
...[6, 6, 6, 6, 6, 6],
]);
- const unpadded = pkcs7unpad(padded);
+ const unpadded = testing.pkcs7unpad(padded);
expect(unpadded.length).toBe(10);
});
@@ -51,7 +47,7 @@
...generateRandomArray(10),
...[0, 0, 0, 0, 0, 0],
]);
- expect(() => pkcs7unpad(padded)).toThrow();
+ expect(() => testing.pkcs7unpad(padded)).toThrow();
});
it('pkcs7unpad should throw if the padding length is > blockSize', () => {
@@ -60,7 +56,7 @@
...generateRandomArray(10),
...[17, 17, 17, 17, 17, 17],
]);
- expect(() => pkcs7unpad(padded)).toThrow();
+ expect(() => testing.pkcs7unpad(padded)).toThrow();
});
it('pkcs7unpad should throw if the padding is invalid', () => {
@@ -69,14 +65,14 @@
...generateRandomArray(10),
...[6, 1, 2, 3, 4, 6],
]);
- expect(() => pkcs7unpad(padded)).toThrow();
+ expect(() => testing.pkcs7unpad(padded)).toThrow();
});
it('pkcs7pad and pkcs7unpad should be inverses', () => {
const blockSize = 16;
const data = generateRandomData(100);
- const padded = pkcs7pad(data, blockSize);
- const unpadded = pkcs7unpad(padded);
+ const padded = testing.pkcs7pad(data, blockSize);
+ const unpadded = testing.pkcs7unpad(padded);
expect(unpadded.length).toBe(data.length);
expect(unpadded).toEqual(data);
});
@@ -91,7 +87,11 @@
const expectedBlockPadding = 1;
const data = generateRandomData(dataLengthBytes);
- const padded = superblockPad(data, blockSizeBytes, superblockSizeBlocks);
+ const padded = testing.superblockPad(
+ data,
+ blockSizeBytes,
+ superblockSizeBlocks,
+ );
expect(padded.length % expectedPaddedLength).toBe(0);
expect(padded[padded.length - 1]).toBe(expectedBlockPadding);
@@ -105,7 +105,11 @@
const expectedBlockPadding = 4;
const data = generateRandomData(dataLengthBytes);
- const padded = superblockPad(data, blockSizeBytes, superblockSizeBlocks);
+ const padded = testing.superblockPad(
+ data,
+ blockSizeBytes,
+ superblockSizeBlocks,
+ );
expect(padded.length % expectedPaddedLength).toBe(0);
expect(padded[padded.length - 1]).toBe(expectedBlockPadding);
@@ -120,7 +124,7 @@
...new Array(2 * 16).fill(2),
]);
- const unpadded = superblockUnpad(padded, blockSizeBytes);
+ const unpadded = testing.superblockUnpad(padded, blockSizeBytes);
expect(unpadded.length).toBe(32);
expect(unpadded).toEqual(padded.subarray(0, 32));
@@ -132,7 +136,7 @@
...generateRandomArray(2 * 16),
...new Array(2 * 16).fill(0),
]);
- expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow();
+ expect(() => testing.superblockUnpad(padded, blockSizeBytes)).toThrow();
});
it('superblockUnpad should throw if the padding length is > num blocks', () => {
@@ -142,7 +146,7 @@
...generateRandomArray(2 * 16),
...new Array(2 * 16).fill(5),
]);
- expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow();
+ expect(() => testing.superblockUnpad(padded, blockSizeBytes)).toThrow();
});
it('superblockUnpad should throw if the padding is invalid', () => {
@@ -152,7 +156,67 @@
...generateRandomArray(2 * 15),
...[1],
]);
- expect(() => superblockUnpad(padded, blockSizeBytes)).toThrow();
+ expect(() => testing.superblockUnpad(padded, blockSizeBytes)).toThrow();
+ });
+});
+
+describe('padding integration tests (pad and unpad)', () => {
+ it('should pad data to a multiple of superblockSize blocks', () => {
+ const config: PaddingConfiguration = {
+ blockSizeBytes: 16,
+ superblockSizeBlocks: 4,
+ };
+
+ // 20 bytes of data - expected 4 blocks total (1 superblock):
+ // - block 1 (16 bytes) = 16 bytes of data
+ // - block 2 (16 bytes) = 4 bytes of data (remaining 12 bytes of padding)
+ // - block 3 (16 bytes) = full padding (filled with 2s)
+ // - block 4 (16 bytes) = full padding (filled with 2s)
+ const dataLengthBytes = 20;
+ const expectedPkcs7Padding = 12;
+ const expectedBlockPadding = 2;
+ const expectedPaddedLength = 4 * 16;
+
+ const data = generateRandomData(dataLengthBytes);
+ const padded = pad(data, config);
+
+ expect(padded.length % expectedPaddedLength).toBe(0);
+ expect(padded[padded.length - 1]).toBe(expectedBlockPadding);
+ expect(padded[2 * 16 - 1]).toBe(expectedPkcs7Padding);
+ });
+
+ it('pad should add a full superblock if pkcs7-padded input is a multiple of superblockSize blocks', () => {
+ const config: PaddingConfiguration = {
+ blockSizeBytes: 16,
+ superblockSizeBlocks: 4,
+ };
+
+ // 5 bytes less so pkcs7 padding is 5 bytes and pads equally to superblock
+ // size
+ const pkcs7paddingLength = 5;
+ const dataLengthBytes = 4 * 16 - pkcs7paddingLength;
+
+ const expectedPaddedLength = 8 * 16;
+ const expectedBlockPadding = 4;
+
+ const data = generateRandomData(dataLengthBytes);
+ const padded = pad(data, config);
+
+ expect(padded.length % expectedPaddedLength).toBe(0);
+ expect(padded[padded.length - 1]).toBe(expectedBlockPadding);
+ });
+
+ it('pad and unpad should be inverses', () => {
+ const config: PaddingConfiguration = {
+ blockSizeBytes: 16,
+ superblockSizeBlocks: 4,
+ };
+
+ const data = generateRandomData(100);
+ const padded = pad(data, config);
+ const unpadded = unpad(padded, config);
+ expect(unpadded.length).toBe(data.length);
+ expect(unpadded).toEqual(data);
});
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Dec 5, 1:32 AM (13 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2615489
Default Alt Text
D7061.id23693.diff (10 KB)
Attached To
Mode
D7061: [lib] Introduce combined padding interface
Attached
Detach File
Event Timeline
Log In to Comment