// Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { ProfileKeyCredentialRequestContext } from '@signalapp/signal-client/zkgroup'; import { AuthCredential, ClientZkAuthOperations, ClientZkGroupCipher, ClientZkProfileOperations, GroupMasterKey, GroupSecretParams, ProfileKey, ProfileKeyCiphertext, ProfileKeyCredential, ProfileKeyCredentialPresentation, ProfileKeyCredentialResponse, ServerPublicParams, UuidCiphertext, } from '@signalapp/signal-client/zkgroup'; import { UUID } from '../types/UUID'; import type { UUIDStringType } from '../types/UUID'; export * from '@signalapp/signal-client/zkgroup'; // Scenarios export function decryptGroupBlob( clientZkGroupCipher: ClientZkGroupCipher, ciphertext: Uint8Array ): Uint8Array { return clientZkGroupCipher.decryptBlob(Buffer.from(ciphertext)); } export function decryptProfileKeyCredentialPresentation( clientZkGroupCipher: ClientZkGroupCipher, presentationBuffer: Uint8Array ): { profileKey: Uint8Array; uuid: UUIDStringType } { const presentation = new ProfileKeyCredentialPresentation( Buffer.from(presentationBuffer) ); const uuidCiphertext = presentation.getUuidCiphertext(); const uuid = clientZkGroupCipher.decryptUuid(uuidCiphertext); const profileKeyCiphertext = presentation.getProfileKeyCiphertext(); const profileKey = clientZkGroupCipher.decryptProfileKey( profileKeyCiphertext, uuid ); return { profileKey: profileKey.serialize(), uuid: UUID.cast(uuid), }; } export function decryptProfileKey( clientZkGroupCipher: ClientZkGroupCipher, profileKeyCiphertextBuffer: Uint8Array, uuid: UUIDStringType ): Uint8Array { const profileKeyCiphertext = new ProfileKeyCiphertext( Buffer.from(profileKeyCiphertextBuffer) ); const profileKey = clientZkGroupCipher.decryptProfileKey( profileKeyCiphertext, uuid ); return profileKey.serialize(); } export function decryptUuid( clientZkGroupCipher: ClientZkGroupCipher, uuidCiphertextBuffer: Uint8Array ): string { const uuidCiphertext = new UuidCiphertext(Buffer.from(uuidCiphertextBuffer)); return clientZkGroupCipher.decryptUuid(uuidCiphertext); } export function deriveProfileKeyVersion( profileKeyBase64: string, uuid: UUIDStringType ): string { const profileKeyArray = Buffer.from(profileKeyBase64, 'base64'); const profileKey = new ProfileKey(profileKeyArray); const profileKeyVersion = profileKey.getProfileKeyVersion(uuid); return profileKeyVersion.toString(); } export function deriveGroupPublicParams( groupSecretParamsBuffer: Uint8Array ): Uint8Array { const groupSecretParams = new GroupSecretParams( Buffer.from(groupSecretParamsBuffer) ); return groupSecretParams.getPublicParams().serialize(); } export function deriveGroupID(groupSecretParamsBuffer: Uint8Array): Uint8Array { const groupSecretParams = new GroupSecretParams( Buffer.from(groupSecretParamsBuffer) ); return groupSecretParams.getPublicParams().getGroupIdentifier().serialize(); } export function deriveGroupSecretParams( masterKeyBuffer: Uint8Array ): Uint8Array { const masterKey = new GroupMasterKey(Buffer.from(masterKeyBuffer)); const groupSecretParams = GroupSecretParams.deriveFromMasterKey(masterKey); return groupSecretParams.serialize(); } export function encryptGroupBlob( clientZkGroupCipher: ClientZkGroupCipher, plaintext: Uint8Array ): Uint8Array { return clientZkGroupCipher.encryptBlob(Buffer.from(plaintext)); } export function encryptUuid( clientZkGroupCipher: ClientZkGroupCipher, uuidPlaintext: UUIDStringType ): Uint8Array { const uuidCiphertext = clientZkGroupCipher.encryptUuid(uuidPlaintext); return uuidCiphertext.serialize(); } export function generateProfileKeyCredentialRequest( clientZkProfileCipher: ClientZkProfileOperations, uuid: UUIDStringType, profileKeyBase64: string ): { context: ProfileKeyCredentialRequestContext; requestHex: string } { const profileKeyArray = Buffer.from(profileKeyBase64, 'base64'); const profileKey = new ProfileKey(profileKeyArray); const context = clientZkProfileCipher.createProfileKeyCredentialRequestContext( uuid, profileKey ); const request = context.getRequest(); const requestArray = request.serialize(); return { context, requestHex: requestArray.toString('hex'), }; } export function getAuthCredentialPresentation( clientZkAuthOperations: ClientZkAuthOperations, authCredentialBase64: string, groupSecretParamsBase64: string ): Uint8Array { const authCredential = new AuthCredential( Buffer.from(authCredentialBase64, 'base64') ); const secretParams = new GroupSecretParams( Buffer.from(groupSecretParamsBase64, 'base64') ); const presentation = clientZkAuthOperations.createAuthCredentialPresentation( secretParams, authCredential ); return presentation.serialize(); } export function createProfileKeyCredentialPresentation( clientZkProfileCipher: ClientZkProfileOperations, profileKeyCredentialBase64: string, groupSecretParamsBase64: string ): Uint8Array { const profileKeyCredentialArray = Buffer.from( profileKeyCredentialBase64, 'base64' ); const profileKeyCredential = new ProfileKeyCredential( profileKeyCredentialArray ); const secretParams = new GroupSecretParams( Buffer.from(groupSecretParamsBase64, 'base64') ); const presentation = clientZkProfileCipher.createProfileKeyCredentialPresentation( secretParams, profileKeyCredential ); return presentation.serialize(); } export function getClientZkAuthOperations( serverPublicParamsBase64: string ): ClientZkAuthOperations { const serverPublicParams = new ServerPublicParams( Buffer.from(serverPublicParamsBase64, 'base64') ); return new ClientZkAuthOperations(serverPublicParams); } export function getClientZkGroupCipher( groupSecretParamsBase64: string ): ClientZkGroupCipher { const serverPublicParams = new GroupSecretParams( Buffer.from(groupSecretParamsBase64, 'base64') ); return new ClientZkGroupCipher(serverPublicParams); } export function getClientZkProfileOperations( serverPublicParamsBase64: string ): ClientZkProfileOperations { const serverPublicParams = new ServerPublicParams( Buffer.from(serverPublicParamsBase64, 'base64') ); return new ClientZkProfileOperations(serverPublicParams); } export function handleProfileKeyCredential( clientZkProfileCipher: ClientZkProfileOperations, context: ProfileKeyCredentialRequestContext, responseBase64: string ): string { const response = new ProfileKeyCredentialResponse( Buffer.from(responseBase64, 'base64') ); const profileKeyCredential = clientZkProfileCipher.receiveProfileKeyCredential(context, response); const credentialArray = profileKeyCredential.serialize(); return credentialArray.toString('base64'); } export function deriveProfileKeyCommitment( profileKeyBase64: string, uuid: UUIDStringType ): string { const profileKeyArray = Buffer.from(profileKeyBase64, 'base64'); const profileKey = new ProfileKey(profileKeyArray); return profileKey.getCommitment(uuid).contents.toString('base64'); }