2020-10-30 20:34:04 +00:00
|
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2020-04-15 23:12:28 +00:00
|
|
|
import {
|
2020-09-09 02:25:05 +00:00
|
|
|
AuthCredential,
|
|
|
|
ClientZkAuthOperations,
|
|
|
|
ClientZkGroupCipher,
|
2020-04-15 23:12:28 +00:00
|
|
|
ClientZkProfileOperations,
|
|
|
|
FFICompatArray,
|
|
|
|
FFICompatArrayType,
|
2020-09-09 02:25:05 +00:00
|
|
|
GroupMasterKey,
|
|
|
|
GroupSecretParams,
|
2020-04-15 23:12:28 +00:00
|
|
|
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,
|
2020-04-15 23:12:28 +00:00
|
|
|
ProfileKeyCredentialRequestContext,
|
|
|
|
ProfileKeyCredentialResponse,
|
|
|
|
ServerPublicParams,
|
2020-09-09 02:25:05 +00:00
|
|
|
UuidCiphertext,
|
2020-04-15 23:12:28 +00:00
|
|
|
} from 'zkgroup';
|
|
|
|
import {
|
|
|
|
arrayBufferToBase64,
|
|
|
|
arrayBufferToHex,
|
|
|
|
base64ToArrayBuffer,
|
|
|
|
typedArrayToArrayBuffer,
|
|
|
|
} from '../Crypto';
|
|
|
|
|
2020-09-14 21:56:35 +00:00
|
|
|
export * from 'zkgroup';
|
2020-09-09 02:25:05 +00:00
|
|
|
|
2020-04-15 23:12:28 +00:00
|
|
|
export function arrayBufferToCompatArray(
|
|
|
|
arrayBuffer: ArrayBuffer
|
|
|
|
): FFICompatArrayType {
|
|
|
|
const buffer = Buffer.from(arrayBuffer);
|
|
|
|
|
|
|
|
return new FFICompatArray(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function compatArrayToArrayBuffer(
|
|
|
|
compatArray: FFICompatArrayType
|
|
|
|
): ArrayBuffer {
|
|
|
|
return typedArrayToArrayBuffer(compatArray.buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function base64ToCompatArray(base64: string): FFICompatArrayType {
|
|
|
|
return arrayBufferToCompatArray(base64ToArrayBuffer(base64));
|
|
|
|
}
|
|
|
|
|
|
|
|
export function compatArrayToBase64(compatArray: FFICompatArrayType): string {
|
|
|
|
return arrayBufferToBase64(compatArrayToArrayBuffer(compatArray));
|
|
|
|
}
|
|
|
|
|
|
|
|
export function compatArrayToHex(compatArray: FFICompatArrayType): string {
|
|
|
|
return arrayBufferToHex(compatArrayToArrayBuffer(compatArray));
|
|
|
|
}
|
|
|
|
|
2020-09-09 02:25:05 +00:00
|
|
|
// Scenarios
|
|
|
|
|
|
|
|
export function decryptGroupBlob(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
ciphertext: ArrayBuffer
|
2020-09-14 21:56:35 +00:00
|
|
|
): ArrayBuffer {
|
2020-09-09 02:25:05 +00:00
|
|
|
return compatArrayToArrayBuffer(
|
|
|
|
clientZkGroupCipher.decryptBlob(arrayBufferToCompatArray(ciphertext))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function decryptProfileKeyCredentialPresentation(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
presentationBuffer: ArrayBuffer
|
|
|
|
): { profileKey: ArrayBuffer; uuid: string } {
|
|
|
|
const presentation = new ProfileKeyCredentialPresentation(
|
|
|
|
arrayBufferToCompatArray(presentationBuffer)
|
|
|
|
);
|
|
|
|
|
|
|
|
const uuidCiphertext = presentation.getUuidCiphertext();
|
|
|
|
const uuid = clientZkGroupCipher.decryptUuid(uuidCiphertext);
|
|
|
|
|
|
|
|
const profileKeyCiphertext = presentation.getProfileKeyCiphertext();
|
|
|
|
const profileKey = clientZkGroupCipher.decryptProfileKey(
|
|
|
|
profileKeyCiphertext,
|
|
|
|
uuid
|
|
|
|
);
|
|
|
|
|
|
|
|
return {
|
|
|
|
profileKey: compatArrayToArrayBuffer(profileKey.serialize()),
|
|
|
|
uuid,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function decryptProfileKey(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
profileKeyCiphertextBuffer: ArrayBuffer,
|
|
|
|
uuid: string
|
|
|
|
): ArrayBuffer {
|
|
|
|
const profileKeyCiphertext = new ProfileKeyCiphertext(
|
|
|
|
arrayBufferToCompatArray(profileKeyCiphertextBuffer)
|
|
|
|
);
|
|
|
|
|
|
|
|
const profileKey = clientZkGroupCipher.decryptProfileKey(
|
|
|
|
profileKeyCiphertext,
|
|
|
|
uuid
|
|
|
|
);
|
|
|
|
|
|
|
|
return compatArrayToArrayBuffer(profileKey.serialize());
|
|
|
|
}
|
|
|
|
|
|
|
|
export function decryptUuid(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
uuidCiphertextBuffer: ArrayBuffer
|
|
|
|
): string {
|
|
|
|
const uuidCiphertext = new UuidCiphertext(
|
|
|
|
arrayBufferToCompatArray(uuidCiphertextBuffer)
|
|
|
|
);
|
|
|
|
|
|
|
|
return clientZkGroupCipher.decryptUuid(uuidCiphertext);
|
|
|
|
}
|
|
|
|
|
2020-04-15 23:12:28 +00:00
|
|
|
export function deriveProfileKeyVersion(
|
|
|
|
profileKeyBase64: string,
|
|
|
|
uuid: string
|
2020-09-14 21:56:35 +00:00
|
|
|
): string {
|
2020-04-15 23:12:28 +00:00
|
|
|
const profileKeyArray = base64ToCompatArray(profileKeyBase64);
|
|
|
|
const profileKey = new ProfileKey(profileKeyArray);
|
|
|
|
|
|
|
|
const profileKeyVersion = profileKey.getProfileKeyVersion(uuid);
|
|
|
|
|
|
|
|
return profileKeyVersion.toString();
|
|
|
|
}
|
|
|
|
|
2020-09-14 21:56:35 +00:00
|
|
|
export function deriveGroupPublicParams(
|
|
|
|
groupSecretParamsBuffer: ArrayBuffer
|
|
|
|
): ArrayBuffer {
|
2020-09-09 02:25:05 +00:00
|
|
|
const groupSecretParams = new GroupSecretParams(
|
|
|
|
arrayBufferToCompatArray(groupSecretParamsBuffer)
|
|
|
|
);
|
2020-04-15 23:12:28 +00:00
|
|
|
|
2020-09-09 02:25:05 +00:00
|
|
|
return compatArrayToArrayBuffer(
|
|
|
|
groupSecretParams.getPublicParams().serialize()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-14 21:56:35 +00:00
|
|
|
export function deriveGroupID(
|
|
|
|
groupSecretParamsBuffer: ArrayBuffer
|
|
|
|
): ArrayBuffer {
|
2020-09-09 02:25:05 +00:00
|
|
|
const groupSecretParams = new GroupSecretParams(
|
|
|
|
arrayBufferToCompatArray(groupSecretParamsBuffer)
|
|
|
|
);
|
|
|
|
|
|
|
|
return compatArrayToArrayBuffer(
|
2020-11-18 15:15:42 +00:00
|
|
|
groupSecretParams.getPublicParams().getGroupIdentifier().serialize()
|
2020-09-09 02:25:05 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function deriveGroupSecretParams(
|
|
|
|
masterKeyBuffer: ArrayBuffer
|
|
|
|
): ArrayBuffer {
|
|
|
|
const masterKey = new GroupMasterKey(
|
|
|
|
arrayBufferToCompatArray(masterKeyBuffer)
|
|
|
|
);
|
|
|
|
const groupSecretParams = GroupSecretParams.deriveFromMasterKey(masterKey);
|
|
|
|
|
|
|
|
return compatArrayToArrayBuffer(groupSecretParams.serialize());
|
|
|
|
}
|
|
|
|
|
|
|
|
export function encryptGroupBlob(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
plaintext: ArrayBuffer
|
2020-09-14 21:56:35 +00:00
|
|
|
): ArrayBuffer {
|
2020-09-09 02:25:05 +00:00
|
|
|
return compatArrayToArrayBuffer(
|
|
|
|
clientZkGroupCipher.encryptBlob(arrayBufferToCompatArray(plaintext))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function encryptUuid(
|
|
|
|
clientZkGroupCipher: ClientZkGroupCipher,
|
|
|
|
uuidPlaintext: string
|
|
|
|
): ArrayBuffer {
|
|
|
|
const uuidCiphertext = clientZkGroupCipher.encryptUuid(uuidPlaintext);
|
|
|
|
|
|
|
|
return compatArrayToArrayBuffer(uuidCiphertext.serialize());
|
2020-04-15 23:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-09-14 21:56:35 +00:00
|
|
|
): ArrayBuffer {
|
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
|
|
|
|
);
|
|
|
|
return compatArrayToArrayBuffer(presentation.serialize());
|
|
|
|
}
|
|
|
|
|
2020-10-06 17:06:34 +00:00
|
|
|
export function createProfileKeyCredentialPresentation(
|
|
|
|
clientZkProfileCipher: ClientZkProfileOperations,
|
|
|
|
profileKeyCredentialBase64: string,
|
|
|
|
groupSecretParamsBase64: string
|
|
|
|
): ArrayBuffer {
|
|
|
|
const profileKeyCredentialArray = base64ToCompatArray(
|
|
|
|
profileKeyCredentialBase64
|
|
|
|
);
|
|
|
|
const profileKeyCredential = new ProfileKeyCredential(
|
|
|
|
profileKeyCredentialArray
|
|
|
|
);
|
|
|
|
const secretParams = new GroupSecretParams(
|
|
|
|
base64ToCompatArray(groupSecretParamsBase64)
|
|
|
|
);
|
|
|
|
|
|
|
|
const presentation = clientZkProfileCipher.createProfileKeyCredentialPresentation(
|
|
|
|
secretParams,
|
|
|
|
profileKeyCredential
|
|
|
|
);
|
|
|
|
|
|
|
|
return compatArrayToArrayBuffer(presentation.serialize());
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-04-15 23:12:28 +00:00
|
|
|
export function handleProfileKeyCredential(
|
|
|
|
clientZkProfileCipher: ClientZkProfileOperations,
|
|
|
|
context: ProfileKeyCredentialRequestContext,
|
|
|
|
responseBase64: string
|
|
|
|
): string {
|
2020-09-09 02:25:05 +00:00
|
|
|
const response = new ProfileKeyCredentialResponse(
|
|
|
|
base64ToCompatArray(responseBase64)
|
|
|
|
);
|
2020-04-15 23:12:28 +00:00
|
|
|
const profileKeyCredential = clientZkProfileCipher.receiveProfileKeyCredential(
|
|
|
|
context,
|
|
|
|
response
|
|
|
|
);
|
|
|
|
|
|
|
|
const credentialArray = profileKeyCredential.serialize();
|
|
|
|
|
|
|
|
return compatArrayToBase64(credentialArray);
|
|
|
|
}
|