Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,27 @@ 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);
let result: string | undefined;
try {
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', () => {
// 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);
});
});