DC-019: fix flaky backup-manager tamper test (authTag byte corruption)
The 'rejects tampered data (auth tag mismatch)' test corrupted the encrypted blob by replacing its first base64 char with 'X'. When the random 16-byte IV's first base64 char was already 'X' (~1/64 chance), the replacement was a no-op and decryption succeeded — causing the test to flake ~1.6% of runs. Fix: parse the iv:authTag:ciphertext format, XOR the first authTag byte with 0xFF (guaranteed to change the value), reassemble. This reliably triggers the AES-256-GCM integrity failure every time. Verified: 30/30 isolated runs + 8/8 full-suite runs (1036/1036), zero failures. The production encryptBackup/decryptBackup (AES-256-GCM) code is correct and unchanged.
This commit is contained in:
@@ -184,9 +184,16 @@ describe('BackupManager — backup/restore lifecycle', () => {
|
|||||||
it('rejects tampered data (auth tag mismatch)', async () => {
|
it('rejects tampered data (auth tag mismatch)', async () => {
|
||||||
const data = Buffer.from('test');
|
const data = Buffer.from('test');
|
||||||
const encrypted = await backupManager.encryptBackup(data, testKey);
|
const encrypted = await backupManager.encryptBackup(data, testKey);
|
||||||
// Corrupt the first character of the IV
|
// Corrupt the authTag so the GCM integrity check is guaranteed to fail.
|
||||||
const str = encrypted.toString();
|
// The format is iv:authTag:ciphertext (all base64). We flip all bits of
|
||||||
const tampered = Buffer.from('X' + str.substring(1));
|
// the first authTag byte — XOR with 0xFF always changes the value, so
|
||||||
|
// this can never be a no-op (unlike replacing a base64 char with a fixed
|
||||||
|
// char, which collides ~1/64 of the time when that char already matches).
|
||||||
|
const parts = encrypted.toString().split(':');
|
||||||
|
const authTagBuf = Buffer.from(parts[1], 'base64');
|
||||||
|
authTagBuf[0] ^= 0xFF;
|
||||||
|
parts[1] = authTagBuf.toString('base64');
|
||||||
|
const tampered = Buffer.from(parts.join(':'));
|
||||||
await expect(backupManager.decryptBackup(tampered, testKey))
|
await expect(backupManager.decryptBackup(tampered, testKey))
|
||||||
.rejects.toThrow();
|
.rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user