Signal-Desktop/ts/util/zkgroup.ts

297 lines
7.9 KiB
TypeScript
Raw Normal View History

2020-10-30 20:34:04 +00:00
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type {
FFICompatArrayType,
ProfileKeyCredentialRequestContext,
} from 'zkgroup';
import {
2020-09-09 02:25:05 +00:00
AuthCredential,
ClientZkAuthOperations,
ClientZkGroupCipher,
ClientZkProfileOperations,
FFICompatArray,
2020-09-09 02:25:05 +00:00
GroupMasterKey,
GroupSecretParams,
ProfileKey,
2020-09-09 02:25:05 +00:00
ProfileKeyCiphertext,
2020-10-06 17:06:34 +00:00
ProfileKeyCredential,
2020-09-09 02:25:05 +00:00
ProfileKeyCredentialPresentation,
ProfileKeyCredentialResponse,
ServerPublicParams,
2020-09-09 02:25:05 +00:00
UuidCiphertext,
} from 'zkgroup';
2021-06-22 14:46:42 +00:00
import * as Bytes from '../Bytes';
export * from 'zkgroup';
2020-09-09 02:25:05 +00:00
2021-06-22 14:46:42 +00:00
export function uint8ArrayToCompatArray(
buffer: Uint8Array
): FFICompatArrayType {
2021-06-22 14:46:42 +00:00
return new FFICompatArray(Buffer.from(buffer));
}
2021-06-22 14:46:42 +00:00
export function compatArrayToUint8Array(
compatArray: FFICompatArrayType
2021-06-22 14:46:42 +00:00
): Uint8Array {
return compatArray.buffer;
}
export function base64ToCompatArray(base64: string): FFICompatArrayType {
2021-06-22 14:46:42 +00:00
return uint8ArrayToCompatArray(Bytes.fromBase64(base64));
}
export function compatArrayToBase64(compatArray: FFICompatArrayType): string {
2021-06-22 14:46:42 +00:00
return Bytes.toBase64(compatArrayToUint8Array(compatArray));
}
export function compatArrayToHex(compatArray: FFICompatArrayType): string {
2021-06-22 14:46:42 +00:00
return Bytes.toHex(compatArrayToUint8Array(compatArray));
}
2020-09-09 02:25:05 +00:00
// Scenarios
export function decryptGroupBlob(
clientZkGroupCipher: ClientZkGroupCipher,
2021-06-22 14:46:42 +00:00
ciphertext: Uint8Array
): Uint8Array {
return compatArrayToUint8Array(
clientZkGroupCipher.decryptBlob(uint8ArrayToCompatArray(ciphertext))
2020-09-09 02:25:05 +00:00
);
}
export function decryptProfileKeyCredentialPresentation(
clientZkGroupCipher: ClientZkGroupCipher,
2021-06-22 14:46:42 +00:00
presentationBuffer: Uint8Array
): { profileKey: Uint8Array; uuid: string } {
2020-09-09 02:25:05 +00:00
const presentation = new ProfileKeyCredentialPresentation(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(presentationBuffer)
2020-09-09 02:25:05 +00:00
);
const uuidCiphertext = presentation.getUuidCiphertext();
const uuid = clientZkGroupCipher.decryptUuid(uuidCiphertext);
const profileKeyCiphertext = presentation.getProfileKeyCiphertext();
const profileKey = clientZkGroupCipher.decryptProfileKey(
profileKeyCiphertext,
uuid
);
return {
2021-06-22 14:46:42 +00:00
profileKey: compatArrayToUint8Array(profileKey.serialize()),
2020-09-09 02:25:05 +00:00
uuid,
};
}
export function decryptProfileKey(
clientZkGroupCipher: ClientZkGroupCipher,
2021-06-22 14:46:42 +00:00
profileKeyCiphertextBuffer: Uint8Array,
2020-09-09 02:25:05 +00:00
uuid: string
2021-06-22 14:46:42 +00:00
): Uint8Array {
2020-09-09 02:25:05 +00:00
const profileKeyCiphertext = new ProfileKeyCiphertext(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(profileKeyCiphertextBuffer)
2020-09-09 02:25:05 +00:00
);
const profileKey = clientZkGroupCipher.decryptProfileKey(
profileKeyCiphertext,
uuid
);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(profileKey.serialize());
2020-09-09 02:25:05 +00:00
}
export function decryptUuid(
clientZkGroupCipher: ClientZkGroupCipher,
2021-06-22 14:46:42 +00:00
uuidCiphertextBuffer: Uint8Array
2020-09-09 02:25:05 +00:00
): string {
const uuidCiphertext = new UuidCiphertext(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(uuidCiphertextBuffer)
2020-09-09 02:25:05 +00:00
);
return clientZkGroupCipher.decryptUuid(uuidCiphertext);
}
export function deriveProfileKeyVersion(
profileKeyBase64: string,
uuid: string
): string {
const profileKeyArray = base64ToCompatArray(profileKeyBase64);
const profileKey = new ProfileKey(profileKeyArray);
const profileKeyVersion = profileKey.getProfileKeyVersion(uuid);
return profileKeyVersion.toString();
}
export function deriveGroupPublicParams(
2021-06-22 14:46:42 +00:00
groupSecretParamsBuffer: Uint8Array
): Uint8Array {
2020-09-09 02:25:05 +00:00
const groupSecretParams = new GroupSecretParams(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(groupSecretParamsBuffer)
2020-09-09 02:25:05 +00:00
);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(
2020-09-09 02:25:05 +00:00
groupSecretParams.getPublicParams().serialize()
);
}
2021-06-22 14:46:42 +00:00
export function deriveGroupID(groupSecretParamsBuffer: Uint8Array): Uint8Array {
2020-09-09 02:25:05 +00:00
const groupSecretParams = new GroupSecretParams(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(groupSecretParamsBuffer)
2020-09-09 02:25:05 +00:00
);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(
groupSecretParams.getPublicParams().getGroupIdentifier().serialize()
2020-09-09 02:25:05 +00:00
);
}
export function deriveGroupSecretParams(
2021-06-22 14:46:42 +00:00
masterKeyBuffer: Uint8Array
): Uint8Array {
2020-09-09 02:25:05 +00:00
const masterKey = new GroupMasterKey(
2021-06-22 14:46:42 +00:00
uint8ArrayToCompatArray(masterKeyBuffer)
2020-09-09 02:25:05 +00:00
);
const groupSecretParams = GroupSecretParams.deriveFromMasterKey(masterKey);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(groupSecretParams.serialize());
2020-09-09 02:25:05 +00:00
}
export function encryptGroupBlob(
clientZkGroupCipher: ClientZkGroupCipher,
2021-06-22 14:46:42 +00:00
plaintext: Uint8Array
): Uint8Array {
return compatArrayToUint8Array(
clientZkGroupCipher.encryptBlob(uint8ArrayToCompatArray(plaintext))
2020-09-09 02:25:05 +00:00
);
}
export function encryptUuid(
clientZkGroupCipher: ClientZkGroupCipher,
uuidPlaintext: string
2021-06-22 14:46:42 +00:00
): Uint8Array {
2020-09-09 02:25:05 +00:00
const uuidCiphertext = clientZkGroupCipher.encryptUuid(uuidPlaintext);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(uuidCiphertext.serialize());
}
export function generateProfileKeyCredentialRequest(
clientZkProfileCipher: ClientZkProfileOperations,
uuid: string,
profileKeyBase64: string
): { context: ProfileKeyCredentialRequestContext; requestHex: string } {
const profileKeyArray = base64ToCompatArray(profileKeyBase64);
const profileKey = new ProfileKey(profileKeyArray);
const context = clientZkProfileCipher.createProfileKeyCredentialRequestContext(
uuid,
profileKey
);
const request = context.getRequest();
const requestArray = request.serialize();
return {
context,
requestHex: compatArrayToHex(requestArray),
};
}
2020-09-09 02:25:05 +00:00
export function getAuthCredentialPresentation(
clientZkAuthOperations: ClientZkAuthOperations,
authCredentialBase64: string,
groupSecretParamsBase64: string
2021-06-22 14:46:42 +00:00
): Uint8Array {
2020-09-09 02:25:05 +00:00
const authCredential = new AuthCredential(
base64ToCompatArray(authCredentialBase64)
);
const secretParams = new GroupSecretParams(
base64ToCompatArray(groupSecretParamsBase64)
);
const presentation = clientZkAuthOperations.createAuthCredentialPresentation(
secretParams,
authCredential
);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(presentation.serialize());
2020-09-09 02:25:05 +00:00
}
2020-10-06 17:06:34 +00:00
export function createProfileKeyCredentialPresentation(
clientZkProfileCipher: ClientZkProfileOperations,
profileKeyCredentialBase64: string,
groupSecretParamsBase64: string
2021-06-22 14:46:42 +00:00
): Uint8Array {
2020-10-06 17:06:34 +00:00
const profileKeyCredentialArray = base64ToCompatArray(
profileKeyCredentialBase64
);
const profileKeyCredential = new ProfileKeyCredential(
profileKeyCredentialArray
);
const secretParams = new GroupSecretParams(
base64ToCompatArray(groupSecretParamsBase64)
);
const presentation = clientZkProfileCipher.createProfileKeyCredentialPresentation(
secretParams,
profileKeyCredential
);
2021-06-22 14:46:42 +00:00
return compatArrayToUint8Array(presentation.serialize());
2020-10-06 17:06:34 +00:00
}
2020-09-09 02:25:05 +00:00
export function getClientZkAuthOperations(
serverPublicParamsBase64: string
): ClientZkAuthOperations {
const serverPublicParams = new ServerPublicParams(
base64ToCompatArray(serverPublicParamsBase64)
);
return new ClientZkAuthOperations(serverPublicParams);
}
export function getClientZkGroupCipher(
groupSecretParamsBase64: string
): ClientZkGroupCipher {
const serverPublicParams = new GroupSecretParams(
base64ToCompatArray(groupSecretParamsBase64)
);
return new ClientZkGroupCipher(serverPublicParams);
}
export function getClientZkProfileOperations(
serverPublicParamsBase64: string
): ClientZkProfileOperations {
const serverPublicParams = new ServerPublicParams(
base64ToCompatArray(serverPublicParamsBase64)
);
return new ClientZkProfileOperations(serverPublicParams);
}
export function handleProfileKeyCredential(
clientZkProfileCipher: ClientZkProfileOperations,
context: ProfileKeyCredentialRequestContext,
responseBase64: string
): string {
2020-09-09 02:25:05 +00:00
const response = new ProfileKeyCredentialResponse(
base64ToCompatArray(responseBase64)
);
const profileKeyCredential = clientZkProfileCipher.receiveProfileKeyCredential(
context,
response
);
const credentialArray = profileKeyCredential.serialize();
return compatArrayToBase64(credentialArray);
}
2021-07-19 19:26:06 +00:00
export function deriveProfileKeyCommitment(
profileKeyBase64: string,
uuid: string
): string {
const profileKeyArray = base64ToCompatArray(profileKeyBase64);
const profileKey = new ProfileKey(profileKeyArray);
return compatArrayToBase64(profileKey.getCommitment(uuid).contents);
}