From 08716d0a92e1c43730dea826594e81ab73e77cb5 Mon Sep 17 00:00:00 2001 From: norbert-kulus-blockydevs Date: Tue, 14 Jul 2026 12:20:32 +0200 Subject: [PATCH 1/2] test(ksef): de-flake aes-cipher wrong-key spec AES-256-CBC has no key verification: decrypting with a random wrong key yields accidentally valid PKCS#7 padding ~0.4% of the time, so the old toThrow assertion failed randomly in CI. The wrong-key test now accepts both legal outcomes (KsefSessionCryptoException or garbage != plaintext), and a new deterministic test covers the exception-wrapping path via a truncated ciphertext, which always fails decipher.final(). No production code changes. Closes #1538 Co-Authored-By: Claude Fable 5 Signed-off-by: norbert-kulus-blockydevs --- .../crypto/__tests__/aes-cipher.spec.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts b/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts index 7f75dccdd..e62ef2aaf 100644 --- a/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts +++ b/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts @@ -31,9 +31,25 @@ describe('aes-cipher', () => { expect(() => encryptAesCbc('x', key, new Uint8Array(8))).toThrow(KsefSessionCryptoException); }); - it('should throw KsefSessionCryptoException when decrypting with the wrong key', () => { - const ciphertext = encryptAesCbc('secret', key, iv); + it('should never recover the plaintext when decrypting with the wrong key', () => { + // CBC has no key verification: a wrong key usually fails PKCS#7 padding + // validation (throws), but ~0.4% of random keys yield accidentally valid + // padding and return garbage instead. Both outcomes are legal (#1538). + const plaintext = 'secret'; + const ciphertext = encryptAesCbc(plaintext, key, iv); const wrongKey = new Uint8Array(randomBytes(KSEF_AES_KEY_BYTES)); - expect(() => decryptAesCbc(ciphertext, wrongKey, iv)).toThrow(KsefSessionCryptoException); + try { + const result = decryptAesCbc(ciphertext, wrongKey, iv); + expect(result).not.toBe(plaintext); + } catch (err) { + expect(err).toBeInstanceOf(KsefSessionCryptoException); + } + }); + + it('should throw KsefSessionCryptoException when the ciphertext length is not a multiple of the block size', () => { + // decipher.final() always throws on a truncated ciphertext, so this covers + // the wrapping path of decryptAesCbc deterministically. + const truncated = encryptAesCbc('secret', key, iv).slice(0, -1); + expect(() => decryptAesCbc(truncated, key, iv)).toThrow(KsefSessionCryptoException); }); }); From 44c8a5df5a7d9a3c3cb2a563672bb432527c9621 Mon Sep 17 00:00:00 2001 From: norbert-kulus-blockydevs Date: Tue, 14 Jul 2026 13:07:30 +0200 Subject: [PATCH 2/2] test(ksef): move wrong-key success assertion out of try/catch Signed-off-by: norbert-kulus-blockydevs --- .../src/infrastructure/crypto/__tests__/aes-cipher.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts b/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts index e62ef2aaf..ede6046fb 100644 --- a/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts +++ b/libs/integrations/ksef/src/infrastructure/crypto/__tests__/aes-cipher.spec.ts @@ -38,12 +38,14 @@ describe('aes-cipher', () => { const plaintext = 'secret'; const ciphertext = encryptAesCbc(plaintext, key, iv); const wrongKey = new Uint8Array(randomBytes(KSEF_AES_KEY_BYTES)); + let result: string | undefined; try { - const result = decryptAesCbc(ciphertext, wrongKey, iv); - expect(result).not.toBe(plaintext); + result = decryptAesCbc(ciphertext, wrongKey, iv); } catch (err) { expect(err).toBeInstanceOf(KsefSessionCryptoException); + return; } + expect(result).not.toBe(plaintext); }); it('should throw KsefSessionCryptoException when the ciphertext length is not a multiple of the block size', () => {