signal-desktop/libtextsecure/test/crypto_test.js
2020-11-04 13:03:13 -06:00

149 lines
5.4 KiB
JavaScript

// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global libsignal, textsecure */
describe('encrypting and decrypting profile data', () => {
const NAME_PADDED_LENGTH = 53;
describe('encrypting and decrypting profile names', () => {
it('pads, encrypts, decrypts, and unpads a short string', () => {
const name = 'Alice';
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto
.encryptProfileName(buffer, key)
.then(encrypted => {
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
return textsecure.crypto
.decryptProfileName(encrypted, key)
.then(({ given, family }) => {
assert.strictEqual(family, null);
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
name
);
});
});
});
it('handles a given name of the max, 53 characters', () => {
const name = '01234567890123456789012345678901234567890123456789123';
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto
.encryptProfileName(buffer, key)
.then(encrypted => {
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
return textsecure.crypto
.decryptProfileName(encrypted, key)
.then(({ given, family }) => {
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
name
);
assert.strictEqual(family, null);
});
});
});
it('handles family/given name of the max, 53 characters', () => {
const name = '01234567890123456789\u000001234567890123456789012345678912';
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto
.encryptProfileName(buffer, key)
.then(encrypted => {
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
return textsecure.crypto
.decryptProfileName(encrypted, key)
.then(({ given, family }) => {
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
'01234567890123456789'
);
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
'01234567890123456789012345678912'
);
});
});
});
it('handles a string with family/given name', () => {
const name = 'Alice\0Jones';
const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto
.encryptProfileName(buffer, key)
.then(encrypted => {
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
return textsecure.crypto
.decryptProfileName(encrypted, key)
.then(({ given, family }) => {
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
'Alice'
);
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
'Jones'
);
});
});
});
it('works for empty string', () => {
const name = dcodeIO.ByteBuffer.wrap('').toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto
.encryptProfileName(name.buffer, key)
.then(encrypted => {
assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
return textsecure.crypto
.decryptProfileName(encrypted, key)
.then(({ given, family }) => {
assert.strictEqual(family, null);
assert.strictEqual(given.byteLength, 0);
assert.strictEqual(
dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
''
);
});
});
});
});
describe('encrypting and decrypting profile avatars', () => {
it('encrypts and decrypts', () => {
const buffer = dcodeIO.ByteBuffer.wrap(
'This is an avatar'
).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
return textsecure.crypto
.decryptProfile(encrypted, key)
.then(decrypted => {
assertEqualArrayBuffers(buffer, decrypted);
});
});
});
it('throws when decrypting with the wrong key', () => {
const buffer = dcodeIO.ByteBuffer.wrap(
'This is an avatar'
).toArrayBuffer();
const key = libsignal.crypto.getRandomBytes(32);
const badKey = libsignal.crypto.getRandomBytes(32);
return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
return textsecure.crypto
.decryptProfile(encrypted, badKey)
.catch(error => {
assert.strictEqual(error.name, 'ProfileDecryptError');
});
});
});
});
});