2021-04-16 23:13:13 +00:00
|
|
|
// Copyright 2021 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
import { assert } from 'chai';
|
|
|
|
|
2021-09-24 00:49:05 +00:00
|
|
|
import * as Bytes from '../Bytes';
|
|
|
|
import { constantTimeEqual } from '../Crypto';
|
2021-04-16 23:13:13 +00:00
|
|
|
import {
|
|
|
|
calculateSignature,
|
|
|
|
clampPrivateKey,
|
|
|
|
createKeyPair,
|
2021-04-27 00:42:12 +00:00
|
|
|
calculateAgreement,
|
2021-04-16 23:13:13 +00:00
|
|
|
generateKeyPair,
|
|
|
|
generatePreKey,
|
|
|
|
generateSignedPreKey,
|
|
|
|
isNonNegativeInteger,
|
|
|
|
verifySignature,
|
|
|
|
} from '../Curve';
|
|
|
|
|
|
|
|
describe('Curve', () => {
|
|
|
|
it('verifySignature roundtrip', () => {
|
2021-09-24 00:49:05 +00:00
|
|
|
const message = Buffer.from('message');
|
2021-04-16 23:13:13 +00:00
|
|
|
const { pubKey, privKey } = generateKeyPair();
|
|
|
|
const signature = calculateSignature(privKey, message);
|
|
|
|
const verified = verifySignature(pubKey, message, signature);
|
|
|
|
|
|
|
|
assert.isTrue(verified);
|
|
|
|
});
|
|
|
|
|
2021-04-27 00:42:12 +00:00
|
|
|
it('calculateAgreement roundtrip', () => {
|
|
|
|
const alice = generateKeyPair();
|
|
|
|
const bob = generateKeyPair();
|
|
|
|
|
|
|
|
const sharedSecretAlice = calculateAgreement(bob.pubKey, alice.privKey);
|
|
|
|
const sharedSecretBob = calculateAgreement(alice.pubKey, bob.privKey);
|
|
|
|
|
|
|
|
assert.isTrue(constantTimeEqual(sharedSecretAlice, sharedSecretBob));
|
|
|
|
});
|
|
|
|
|
2021-04-16 23:13:13 +00:00
|
|
|
describe('#isNonNegativeInteger', () => {
|
|
|
|
it('returns false for -1, Infinity, NaN, a string, etc.', () => {
|
|
|
|
assert.isFalse(isNonNegativeInteger(-1));
|
|
|
|
assert.isFalse(isNonNegativeInteger(NaN));
|
|
|
|
assert.isFalse(isNonNegativeInteger(Infinity));
|
|
|
|
assert.isFalse(isNonNegativeInteger('woo!'));
|
|
|
|
});
|
|
|
|
it('returns true for 0 and positive integgers', () => {
|
|
|
|
assert.isTrue(isNonNegativeInteger(0));
|
|
|
|
assert.isTrue(isNonNegativeInteger(1));
|
|
|
|
assert.isTrue(isNonNegativeInteger(3));
|
|
|
|
assert.isTrue(isNonNegativeInteger(400_000));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#generateSignedPrekey', () => {
|
|
|
|
it('geernates proper signature for created signed prekeys', () => {
|
|
|
|
const keyId = 4;
|
|
|
|
const identityKeyPair = generateKeyPair();
|
|
|
|
const signedPreKey = generateSignedPreKey(identityKeyPair, keyId);
|
|
|
|
|
|
|
|
assert.equal(keyId, signedPreKey.keyId);
|
|
|
|
|
|
|
|
const verified = verifySignature(
|
|
|
|
identityKeyPair.pubKey,
|
|
|
|
signedPreKey.keyPair.pubKey,
|
|
|
|
signedPreKey.signature
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.isTrue(verified);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#generatePrekey', () => {
|
|
|
|
it('returns keys of the right length', () => {
|
|
|
|
const keyId = 7;
|
|
|
|
const preKey = generatePreKey(keyId);
|
|
|
|
|
|
|
|
assert.equal(keyId, preKey.keyId);
|
|
|
|
assert.equal(33, preKey.keyPair.pubKey.byteLength);
|
|
|
|
assert.equal(32, preKey.keyPair.privKey.byteLength);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#createKeyPair', () => {
|
|
|
|
it('does not modify unclamped private key', () => {
|
|
|
|
const initialHex =
|
|
|
|
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
2021-09-24 00:49:05 +00:00
|
|
|
const privateKey = Bytes.fromHex(initialHex);
|
|
|
|
const copyOfPrivateKey = new Uint8Array(privateKey);
|
2021-04-16 23:13:13 +00:00
|
|
|
|
|
|
|
assert.isTrue(
|
|
|
|
constantTimeEqual(privateKey, copyOfPrivateKey),
|
|
|
|
'initial copy check'
|
|
|
|
);
|
|
|
|
|
|
|
|
const keyPair = createKeyPair(privateKey);
|
|
|
|
|
|
|
|
assert.equal(32, keyPair.privKey.byteLength);
|
|
|
|
assert.equal(33, keyPair.pubKey.byteLength);
|
|
|
|
|
|
|
|
// The original incoming key is not modified
|
|
|
|
assert.isTrue(
|
|
|
|
constantTimeEqual(privateKey, copyOfPrivateKey),
|
|
|
|
'second copy check'
|
|
|
|
);
|
|
|
|
|
|
|
|
// But the keypair that comes out has indeed been updated
|
|
|
|
assert.notEqual(
|
|
|
|
initialHex,
|
2021-09-24 00:49:05 +00:00
|
|
|
Bytes.toHex(keyPair.privKey),
|
2021-04-16 23:13:13 +00:00
|
|
|
'keypair check'
|
|
|
|
);
|
|
|
|
assert.isFalse(
|
|
|
|
constantTimeEqual(keyPair.privKey, privateKey),
|
|
|
|
'keypair vs incoming value'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not modify clamped private key', () => {
|
|
|
|
const initialHex =
|
|
|
|
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
2021-09-24 00:49:05 +00:00
|
|
|
const privateKey = Bytes.fromHex(initialHex);
|
2021-04-16 23:13:13 +00:00
|
|
|
clampPrivateKey(privateKey);
|
2021-09-24 00:49:05 +00:00
|
|
|
const postClampHex = Bytes.toHex(privateKey);
|
|
|
|
const copyOfPrivateKey = new Uint8Array(privateKey);
|
2021-04-16 23:13:13 +00:00
|
|
|
|
|
|
|
assert.notEqual(postClampHex, initialHex, 'initial clamp check');
|
|
|
|
assert.isTrue(
|
|
|
|
constantTimeEqual(privateKey, copyOfPrivateKey),
|
|
|
|
'initial copy check'
|
|
|
|
);
|
|
|
|
|
|
|
|
const keyPair = createKeyPair(privateKey);
|
|
|
|
|
|
|
|
assert.equal(32, keyPair.privKey.byteLength);
|
|
|
|
assert.equal(33, keyPair.pubKey.byteLength);
|
|
|
|
|
|
|
|
// The original incoming key is not modified
|
|
|
|
assert.isTrue(
|
|
|
|
constantTimeEqual(privateKey, copyOfPrivateKey),
|
|
|
|
'second copy check'
|
|
|
|
);
|
|
|
|
|
|
|
|
// The keypair that comes out hasn't been updated either
|
2021-09-24 00:49:05 +00:00
|
|
|
assert.equal(postClampHex, Bytes.toHex(keyPair.privKey), 'keypair check');
|
2021-04-16 23:13:13 +00:00
|
|
|
assert.isTrue(
|
|
|
|
constantTimeEqual(privateKey, keyPair.privKey),
|
|
|
|
'keypair vs incoming value'
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|