decrypt/encrypt with libsignal-client, remove libsignal-protocol-javascript
This commit is contained in:
parent
37ff4a1df4
commit
86d2a4b5dd
60 changed files with 2508 additions and 28714 deletions
176
ts/Curve.ts
Normal file
176
ts/Curve.ts
Normal file
|
@ -0,0 +1,176 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as client from 'libsignal-client';
|
||||
|
||||
import { constantTimeEqual, typedArrayToArrayBuffer } from './Crypto';
|
||||
import {
|
||||
KeyPairType,
|
||||
CompatPreKeyType,
|
||||
CompatSignedPreKeyType,
|
||||
} from './textsecure/Types.d';
|
||||
|
||||
export function isNonNegativeInteger(n: unknown): n is number {
|
||||
return typeof n === 'number' && n % 1 === 0 && n >= 0;
|
||||
}
|
||||
|
||||
export function generateSignedPreKey(
|
||||
identityKeyPair: KeyPairType,
|
||||
keyId: number
|
||||
): CompatSignedPreKeyType {
|
||||
if (!isNonNegativeInteger(keyId)) {
|
||||
throw new TypeError(
|
||||
`generateSignedPreKey: Invalid argument for keyId: ${keyId}`
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!(identityKeyPair.privKey instanceof ArrayBuffer) ||
|
||||
identityKeyPair.privKey.byteLength !== 32 ||
|
||||
!(identityKeyPair.pubKey instanceof ArrayBuffer) ||
|
||||
identityKeyPair.pubKey.byteLength !== 33
|
||||
) {
|
||||
throw new TypeError(
|
||||
'generateSignedPreKey: Invalid argument for identityKeyPair'
|
||||
);
|
||||
}
|
||||
|
||||
const keyPair = generateKeyPair();
|
||||
const signature = calculateSignature(identityKeyPair.privKey, keyPair.pubKey);
|
||||
|
||||
return {
|
||||
keyId,
|
||||
keyPair,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
export function generatePreKey(keyId: number): CompatPreKeyType {
|
||||
if (!isNonNegativeInteger(keyId)) {
|
||||
throw new TypeError(`generatePreKey: Invalid argument for keyId: ${keyId}`);
|
||||
}
|
||||
|
||||
const keyPair = generateKeyPair();
|
||||
|
||||
return {
|
||||
keyId,
|
||||
keyPair,
|
||||
};
|
||||
}
|
||||
|
||||
export function generateKeyPair(): KeyPairType {
|
||||
const privKey = client.PrivateKey.generate();
|
||||
const pubKey = privKey.getPublicKey();
|
||||
|
||||
return {
|
||||
privKey: typedArrayToArrayBuffer(privKey.serialize()),
|
||||
pubKey: typedArrayToArrayBuffer(pubKey.serialize()),
|
||||
};
|
||||
}
|
||||
|
||||
export function copyArrayBuffer(source: ArrayBuffer): ArrayBuffer {
|
||||
const sourceArray = new Uint8Array(source);
|
||||
|
||||
const target = new ArrayBuffer(source.byteLength);
|
||||
const targetArray = new Uint8Array(target);
|
||||
|
||||
targetArray.set(sourceArray, 0);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
export function createKeyPair(incomingKey: ArrayBuffer): KeyPairType {
|
||||
const copy = copyArrayBuffer(incomingKey);
|
||||
clampPrivateKey(copy);
|
||||
if (!constantTimeEqual(copy, incomingKey)) {
|
||||
window.log.warn('createKeyPair: incoming private key was not clamped!');
|
||||
}
|
||||
|
||||
const incomingKeyBuffer = Buffer.from(incomingKey);
|
||||
|
||||
if (incomingKeyBuffer.length !== 32) {
|
||||
throw new Error('key must be 32 bytes long');
|
||||
}
|
||||
|
||||
const privKey = client.PrivateKey.deserialize(incomingKeyBuffer);
|
||||
const pubKey = privKey.getPublicKey();
|
||||
|
||||
return {
|
||||
privKey: typedArrayToArrayBuffer(privKey.serialize()),
|
||||
pubKey: typedArrayToArrayBuffer(pubKey.serialize()),
|
||||
};
|
||||
}
|
||||
|
||||
export function calculateAgreement(
|
||||
pubKey: ArrayBuffer,
|
||||
privKey: ArrayBuffer
|
||||
): ArrayBuffer {
|
||||
const privKeyBuffer = Buffer.from(privKey);
|
||||
|
||||
const pubKeyObj = client.PublicKey.deserialize(
|
||||
Buffer.concat([
|
||||
Buffer.from([0x05]),
|
||||
Buffer.from(validatePubKeyFormat(pubKey)),
|
||||
])
|
||||
);
|
||||
const privKeyObj = client.PrivateKey.deserialize(privKeyBuffer);
|
||||
const sharedSecret = privKeyObj.agree(pubKeyObj);
|
||||
return typedArrayToArrayBuffer(sharedSecret);
|
||||
}
|
||||
|
||||
export function verifySignature(
|
||||
pubKey: ArrayBuffer,
|
||||
message: ArrayBuffer,
|
||||
signature: ArrayBuffer
|
||||
): boolean {
|
||||
const pubKeyBuffer = Buffer.from(pubKey);
|
||||
const messageBuffer = Buffer.from(message);
|
||||
const signatureBuffer = Buffer.from(signature);
|
||||
|
||||
const pubKeyObj = client.PublicKey.deserialize(pubKeyBuffer);
|
||||
const result = pubKeyObj.verify(messageBuffer, signatureBuffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function calculateSignature(
|
||||
privKey: ArrayBuffer,
|
||||
plaintext: ArrayBuffer
|
||||
): ArrayBuffer {
|
||||
const privKeyBuffer = Buffer.from(privKey);
|
||||
const plaintextBuffer = Buffer.from(plaintext);
|
||||
|
||||
const privKeyObj = client.PrivateKey.deserialize(privKeyBuffer);
|
||||
const signature = privKeyObj.sign(plaintextBuffer);
|
||||
return typedArrayToArrayBuffer(signature);
|
||||
}
|
||||
|
||||
export function validatePubKeyFormat(pubKey: ArrayBuffer): ArrayBuffer {
|
||||
if (
|
||||
pubKey === undefined ||
|
||||
((pubKey.byteLength !== 33 || new Uint8Array(pubKey)[0] !== 5) &&
|
||||
pubKey.byteLength !== 32)
|
||||
) {
|
||||
throw new Error('Invalid public key');
|
||||
}
|
||||
if (pubKey.byteLength === 33) {
|
||||
return pubKey.slice(1);
|
||||
}
|
||||
|
||||
return pubKey;
|
||||
}
|
||||
|
||||
export function setPublicKeyTypeByte(publicKey: ArrayBuffer): void {
|
||||
const byteArray = new Uint8Array(publicKey);
|
||||
byteArray[0] = 5;
|
||||
}
|
||||
|
||||
export function clampPrivateKey(privateKey: ArrayBuffer): void {
|
||||
const byteArray = new Uint8Array(privateKey);
|
||||
|
||||
// eslint-disable-next-line no-bitwise
|
||||
byteArray[0] &= 248;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
byteArray[31] &= 127;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
byteArray[31] |= 64;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue