Attachments: support for incrementalMac and chunkSize

This commit is contained in:
Scott Nonnenberg 2024-10-09 23:13:41 +10:00 committed by GitHub
parent dbf057856f
commit b51a0e0298
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 322 additions and 69 deletions

View file

@ -44,10 +44,11 @@ describe('ContactsParser', () => {
const keys = generateKeys();
({ path } = await encryptAttachmentV2ToDisk({
plaintext: { data },
keys,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: false,
plaintext: { data },
}));
const contacts = await parseContactsV2({

View file

@ -1,11 +1,13 @@
// Copyright 2015 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { readFileSync, unlinkSync, writeFileSync } from 'fs';
import { join } from 'path';
import { createCipheriv } from 'crypto';
import { assert } from 'chai';
import { isNumber } from 'lodash';
import * as log from '../logging/log';
import * as Bytes from '../Bytes';
import * as Curve from '../Curve';
@ -584,6 +586,8 @@ describe('Crypto', () => {
...splitKeys(keys),
size: FILE_CONTENTS.byteLength,
theirDigest: encryptedAttachment.digest,
theirIncrementalMac: undefined,
theirChunkSize: undefined,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
});
@ -611,6 +615,7 @@ describe('Crypto', () => {
plaintextHash,
encryptionKeys,
dangerousIv,
modifyIncrementalMac,
overrideSize,
}: {
path?: string;
@ -618,6 +623,7 @@ describe('Crypto', () => {
plaintextHash?: Uint8Array;
encryptionKeys?: Uint8Array;
dangerousIv?: HardcodedIVForEncryptionType;
modifyIncrementalMac?: boolean;
overrideSize?: number;
}): Promise<DecryptedAttachmentV2> {
let plaintextPath;
@ -631,12 +637,22 @@ describe('Crypto', () => {
dangerousIv,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: true,
});
ciphertextPath = window.Signal.Migrations.getAbsoluteAttachmentPath(
encryptedAttachment.path
);
const macLength = encryptedAttachment.incrementalMac?.length;
if (
modifyIncrementalMac &&
isNumber(macLength) &&
encryptedAttachment.incrementalMac
) {
encryptedAttachment.incrementalMac[macLength / 2] += 1;
}
const decryptedAttachment = await decryptAttachmentV2({
type: 'standard',
ciphertextPath,
@ -644,6 +660,8 @@ describe('Crypto', () => {
...splitKeys(keys),
size: overrideSize ?? data.byteLength,
theirDigest: encryptedAttachment.digest,
theirIncrementalMac: encryptedAttachment.incrementalMac,
theirChunkSize: encryptedAttachment.chunkSize,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
});
@ -736,6 +754,25 @@ describe('Crypto', () => {
unlinkSync(sourcePath);
}
});
it('v2 fails decrypt for large disk file if incrementalMac is wrong', async () => {
const sourcePath = join(tempDir, 'random');
const data = getRandomBytes(5 * 1024 * 1024);
const plaintextHash = sha256(data);
writeFileSync(sourcePath, data);
try {
await assert.isRejected(
testV2RoundTripData({
path: sourcePath,
data,
plaintextHash,
modifyIncrementalMac: true,
}),
/Corrupted/
);
} finally {
unlinkSync(sourcePath);
}
});
it('v2 roundtrips large file from memory', async () => {
// Get sufficient large data to have more than 64kb of padding and
@ -785,6 +822,7 @@ describe('Crypto', () => {
plaintext: { data: FILE_CONTENTS },
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: true,
});
await testV2RoundTripData({
@ -826,6 +864,7 @@ describe('Crypto', () => {
plaintext: { absolutePath: FILE_PATH },
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: false,
});
ciphertextPath = window.Signal.Migrations.getAbsoluteAttachmentPath(
encryptedAttachment.path
@ -882,6 +921,7 @@ describe('Crypto', () => {
dangerousIv: { iv: dangerousTestOnlyIv, reason: 'test' },
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: false,
});
ciphertextPath = window.Signal.Migrations.getAbsoluteAttachmentPath(
encryptedAttachmentV2.path
@ -918,6 +958,7 @@ describe('Crypto', () => {
plaintext: { absolutePath: plaintextAbsolutePath },
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: true,
});
innerCiphertextPath =
window.Signal.Migrations.getAbsoluteAttachmentPath(
@ -931,6 +972,7 @@ describe('Crypto', () => {
dangerousTestOnlySkipPadding: true,
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: false,
});
outerCiphertextPath =
@ -969,6 +1011,9 @@ describe('Crypto', () => {
...splitKeys(innerKeys),
size: FILE_CONTENTS.byteLength,
theirDigest: encryptResult.innerEncryptedAttachment.digest,
theirIncrementalMac:
encryptResult.innerEncryptedAttachment.incrementalMac,
theirChunkSize: encryptResult.innerEncryptedAttachment.chunkSize,
outerEncryption: splitKeys(outerKeys),
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
@ -1025,6 +1070,9 @@ describe('Crypto', () => {
...splitKeys(innerKeys),
size: data.byteLength,
theirDigest: encryptResult.innerEncryptedAttachment.digest,
theirIncrementalMac:
encryptResult.innerEncryptedAttachment.incrementalMac,
theirChunkSize: encryptResult.innerEncryptedAttachment.chunkSize,
outerEncryption: splitKeys(outerKeys),
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
@ -1075,6 +1123,9 @@ describe('Crypto', () => {
...splitKeys(innerKeys),
size: data.byteLength,
theirDigest: encryptResult.innerEncryptedAttachment.digest,
theirIncrementalMac:
encryptResult.innerEncryptedAttachment.incrementalMac,
theirChunkSize: encryptResult.innerEncryptedAttachment.chunkSize,
outerEncryption: {
aesKey: splitKeys(outerKeys).aesKey,
macKey: splitKeys(innerKeys).macKey, // wrong mac!

View file

@ -107,6 +107,7 @@ describe('AttachmentBackupManager/JobManager', function attachmentBackupManager(
absolutePath: join(__dirname, '../../../fixtures/cat-gif.mp4'),
},
keys: Bytes.fromBase64(LOCAL_ENCRYPTION_KEYS),
needIncrementalMac: false,
sink: createWriteStream(absolutePath),
getAbsoluteAttachmentPath,
});

View file

@ -40,6 +40,7 @@ describe('utils/ensureAttachmentIsReencryptable', async () => {
},
getAbsoluteAttachmentPath:
window.Signal.Migrations.getAbsoluteAttachmentPath,
needIncrementalMac: false,
});
digest = encrypted.digest;
iv = encrypted.iv;