import { NitroModules } from 'react-native-nitro-modules' import type { Aes } from './specs/Aes.nitro' import { bufferToInt8Array, int8ArrayToBuffer } from './utils/HybridInterop' import { hybridStrongRandom } from './StrongRandomService' export enum AesKeySize { Aes128 = 128, Aes256 = 256, } export enum AesAlgorithm { AesCbcPkcs7 = 'AesCbcPkcs7', } export interface XAesKey { readonly aesKey: Int8Array readonly algorithm: AesAlgorithm } export interface XAesService { generateKey(algorithm: AesAlgorithm, size: AesKeySize): Promise exportKey(key: XAesKey): Promise loadKey(algorithm: AesAlgorithm, bytes: Int8Array): Promise encrypt(data: Int8Array, key: XAesKey, iv?: Int8Array): Promise decrypt(ivAndEncryptedData: Int8Array, key: XAesKey): Promise } const hybridAes = NitroModules.createHybridObject('Aes') export const AesService: XAesService = { generateKey(algorithm: AesAlgorithm, size: AesKeySize): Promise { if (algorithm !== AesAlgorithm.AesCbcPkcs7) throw new Error(`Unsupported/invalid AES algorithm ${algorithm}`) if (size !== AesKeySize.Aes128 && size !== AesKeySize.Aes256) throw new Error(`Unsupported/invalid AES key size ${size}`) const key = new Int8Array(size / 8) hybridStrongRandom.fillPrivate(key.buffer) return Promise.resolve({ aesKey: key, algorithm: algorithm }) }, exportKey(key: XAesKey): Promise { return Promise.resolve(new Int8Array(key.aesKey)) }, loadKey(algorithm: AesAlgorithm, bytes: Int8Array): Promise { if (algorithm !== AesAlgorithm.AesCbcPkcs7) throw new Error(`Unsupported/invalid AES algorithm ${algorithm}`) if ( bytes.byteLength * 8 !== AesKeySize.Aes128 && bytes.byteLength * 8 !== AesKeySize.Aes256 ) throw new Error( `Unsupported/invalid AES key size ${bytes.byteLength * 8}` ) return Promise.resolve({ aesKey: new Int8Array(bytes), algorithm: algorithm, }) }, async encrypt( data: Int8Array, key: XAesKey, iv?: Int8Array ): Promise { if (key.algorithm !== AesAlgorithm.AesCbcPkcs7) throw new Error( `Unsupported/invalid AES algorithm ${key.algorithm} in key` ) const dataBuffer = int8ArrayToBuffer(data) const keyBuffer = int8ArrayToBuffer(key.aesKey) const ivBuffer = iv != null ? int8ArrayToBuffer(iv) : undefined const res = await hybridAes.encrypt(dataBuffer, keyBuffer, ivBuffer) return bufferToInt8Array(res) }, async decrypt( ivAndEncryptedData: Int8Array, key: XAesKey ): Promise { if (key.algorithm !== AesAlgorithm.AesCbcPkcs7) throw new Error( `Unsupported/invalid AES algorithm ${key.algorithm} in key` ) const ivAndEncryptedDataBuffer = int8ArrayToBuffer(ivAndEncryptedData) const keyBuffer = int8ArrayToBuffer(key.aesKey) const res = await hybridAes.decrypt(ivAndEncryptedDataBuffer, keyBuffer) return bufferToInt8Array(res) }, }