diff --git a/lib/utils/ascii85.test.ts b/lib/utils/ascii85.test.ts new file mode 100644 index 0000000..b643c87 --- /dev/null +++ b/lib/utils/ascii85.test.ts @@ -0,0 +1,16 @@ +import { ascii85Decode } from './ascii85'; + +describe('ascii85Decode', () => { + it('decodes a full 5-character group', () => { + expect(ascii85Decode('<~9jqo^~>')).toEqual( + new Uint8Array([0x4d, 0x61, 0x6e, 0x20]), + ); + }); + + it.each(['<~uu~>', '<~uuu~>', '<~uuuu~>'])( + 'rejects the short tail group %s whose padded value overflows uint32', + (input) => { + expect(ascii85Decode(input)).toBeNull(); + }, + ); +}); diff --git a/lib/utils/ascii85.ts b/lib/utils/ascii85.ts index 5a3a7fe..0843ba8 100644 --- a/lib/utils/ascii85.ts +++ b/lib/utils/ascii85.ts @@ -34,10 +34,10 @@ export function ascii85Decode(input: string): Uint8Array | null { value = value * 85 + digit; } - if (chunkLen === 5 && value > 0xffffffff) return null; + // Applies to padded short tails too: a group whose value exceeds uint32 is invalid input. + if (value > 0xffffffff) return null; - // Use >>> 0 to simulate uint32 overflow for padded groups - const v = value >>> 0; + const v = value; const numBytes = chunkLen === 5 ? 4 : chunkLen - 1; if (numBytes >= 1) output.push((v >>> 24) & 0xff); if (numBytes >= 2) output.push((v >>> 16) & 0xff);