From 9b69b593757cd2e5504639e3f232dd25ad3ccd3f Mon Sep 17 00:00:00 2001 From: Liam O'Boyle Date: Tue, 16 Dec 2025 09:56:43 +1100 Subject: [PATCH] fix: return Buffer from decrypt instead of string Converting decrypted data to UTF-8 corrupts binary data because invalid byte sequences are replaced with the U+FFFD replacement character. This makes it impossible to decrypt non-text content (e.g. binary salts). Returning a Buffer allows callers to interpret the data as needed - they can call .toString('utf-8') for text, or use the raw bytes for binary data. Fixes #2 --- src/Fernet.ts | 20 +++++++++----------- tests/fernet.spec.ts | 9 ++++++++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/Fernet.ts b/src/Fernet.ts index a95c552..d839784 100644 --- a/src/Fernet.ts +++ b/src/Fernet.ts @@ -72,36 +72,34 @@ export class Fernet { } /** - * Returns decrypted plain text from provided Fernet token. + * Returns decrypted data from provided Fernet token. * * @remarks * This method decrypts Fernet token with the given key. - * Returns decrypted string as plain text. - * The decrypted string is encoded as utf-8 encoded string. + * Returns decrypted data as a Buffer. * * @param token - Fernet token - * @returns Decrypted utf-8 encoded string. + * @returns Decrypted data as a Buffer. * */ - decrypt(token: string): string { + decrypt(token: string): Buffer { return Fernet.decrypt(token, this.key); } /** - * Returns decrypted plain text from provided Fernet token. + * Returns decrypted data from provided Fernet token. * * @remarks * This method decrypts Fernet token with the given key. - * Returns decrypted string as plain text. - * The decrypted string is encoded as utf-8 encoded string. + * Returns decrypted data as a Buffer. * * @param token - Fernet token * @param key - The provided 32-byte long base64url encoded key - * @returns Decrypted utf-8 encoded string. + * @returns Decrypted data as a Buffer. * @throws Error if the key, token or cipher text is invalid * */ - static decrypt(token: string, key: string): string { + static decrypt(token: string, key: string): Buffer { try { Fernet.checkKey(key); const keyBuffer = fromBase64Url(key); @@ -132,7 +130,7 @@ export class Fernet { throw new Error('Invalid signature. Signature did not match digest.'); } const decrypted = aesDecrypt(cipherText, encryptionKey, iv); - return decrypted.toString('utf-8'); + return decrypted; } catch (err) { throw err; } diff --git a/tests/fernet.spec.ts b/tests/fernet.spec.ts index fda7de0..0d833e1 100644 --- a/tests/fernet.spec.ts +++ b/tests/fernet.spec.ts @@ -34,7 +34,14 @@ describe('Fernet', () => { const fernet = new Fernet(key); const token = fernet.encrypt(text); const decryptedText = fernet.decrypt(token); - expect(decryptedText).toEqual(text); + expect(decryptedText.toString('utf-8')).toEqual(text); + }); + + it('should return a Buffer from decrypt', () => { + const fernet = new Fernet(key); + const token = fernet.encrypt(text); + const decrypted = fernet.decrypt(token); + expect(Buffer.isBuffer(decrypted)).toBe(true); }); it('should throw error when the key is invalid', () => {