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 @@ -30,6 +30,27 @@ superblockSizeBlocks: 40, }; +/** + * Calculates length of the data padded with given padding configuration. + * + * @param {number} inputLength length of the unpadded input (in bytes) + * @param {*} configuration padding configuration + * @returns length of the padded input (in bytes) + */ +function calculatePaddedLength( + inputLength: number, + { blockSizeBytes, superblockSizeBlocks }: PaddingConfiguration = PKCS7_10KB, +): number { + const pkcs7padding = blockSizeBytes - (inputLength % blockSizeBytes); + const pkcs7PaddedLen = inputLength + pkcs7padding; + + const numBlocks = pkcs7PaddedLen / blockSizeBytes; + const paddingBlocks = + superblockSizeBlocks - (numBlocks % superblockSizeBlocks); + + return pkcs7PaddedLen + paddingBlocks * blockSizeBytes; +} + /** * Pads the input using the extended PKCS#7 padding (superblock padding). * The input is first padded using the standard PKCS#7 padding, and then @@ -169,7 +190,7 @@ return unpaddedData; } -export { PKCS7_10KB, pad, unpad }; +export { PKCS7_10KB, pad, unpad, calculatePaddedLength }; // exported for testing purposes only export const testing = { 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,7 +1,7 @@ // @flow import type { PaddingConfiguration } from './pkcs7-padding'; -import { pad, unpad, testing } from './pkcs7-padding.js'; +import { pad, unpad, testing, calculatePaddedLength } from './pkcs7-padding.js'; const { pkcs7pad, pkcs7unpad, superblockPad, superblockUnpad } = testing; @@ -213,6 +213,27 @@ }); }); +describe('calculatePaddingLength', () => { + it('should calculate the correct padding length', () => { + // we're using a 16 byte block size and 4 block superblocks (64 bytes total) + // let's say our data is 83 bytes long (1 full superblock + 19 bytes) + // we need to pad it to be equal to 2 superblocks (2 * 64 = 128 bytes) + // expected padding length is 128-83 = 45 bytes + const blockSizeBytes = 16; + const superblockSizeBlocks = 4; + + const inputLength = 83; + const expectedPaddedLength = 128; + + const calculatedLength = calculatePaddedLength(inputLength, { + blockSizeBytes, + superblockSizeBlocks, + }); + + expect(calculatedLength).toBe(expectedPaddedLength); + }); +}); + function generateRandomData(length: number): Uint8Array { const data = new Uint8Array(length); for (let i = 0; i < length; i++) {