import { CipherOptions } from '@wireapp/api-client/src/asset' ; import type { EncryptedAsset } from './EncryptedAsset' ; import { crypto } from './crypto.node' ; const isEqual = ( a , b ) : boolean => { const arrayA = new Uint32Array ( a ) ; const arrayB = new Uint32Array ( b ) ; const hasSameLength = arrayA . length === arrayB . length ; const hasSameValues = arrayA . every ( ( value , index ) => value === arrayB [ index ] ) ; return hasSameLength && hasSameValues ; } ; interface EncryptOptions extends CipherOptions { plainText : Buffer | Uint8Array ; } export const decryptAsset = async ( { cipherText , keyBytes , sha256 : referenceSha256 , } ) : Promise < Buffer > => { const computedSha256 = await crypto . digest ( cipherText ) ; if ( ! isEqual ( computedSha256 , referenceSha256 ) ) { throw new Error ( 'Encrypted asset does not match its SHA-256 hash' ) ; } return crypto . decrypt ( cipherText , keyBytes ) ; } ; export const encryptAsset = async ( { plainText , algorithm = 'AES-256-CBC' } ) : Promise < EncryptedAsset > => { const initializationVector = crypto . getRandomValues ( 16 ) ; const rawKeyBytes = crypto . getRandomValues ( 32 ) ; const { key , cipher } = await crypto . encrypt ( plainText , rawKeyBytes , initializationVector , algorithm ) ; const ivCipherText = new Uint8Array ( cipher . byteLength + initializationVector . byteLength ) ; ivCipherText . set ( initializationVector , 0 ) ; ivCipherText . set ( new Uint8Array ( cipher ) , initializationVector . byteLength ) ; const sha256 = await crypto . digest ( ivCipherText ) ; return { cipherText : Buffer . from ( ivCipherText . buffer ) , keyBytes : key , sha256 , } ; } ;