import AesCryptoModule from './ExpoCryptoAES'; import type { ArrayBufferDecryptOptions, Base64DecryptOptions, AESDecryptOptions, AESEncryptOptions, BinaryInput, AESSealedDataConfig, } from './aes.types'; import { uint8ArrayToBase64 } from './web-utils'; export * from './aes.types'; /** * Represents an AES encryption key that can be used for encryption and decryption operations. * This class provides methods to generate, import, and export encryption keys. */ export class AESEncryptionKey extends AesCryptoModule.EncryptionKey {} /** * Represents encrypted data including the ciphertext, initialization vector, and authentication tag. * This class provides methods to create sealed data from various formats and extract its components. */ export class AESSealedData extends AesCryptoModule.SealedData { /** * Static method. Creates a SealedData instance from separate nonce, ciphertext, and optionally a tag. * @param iv The initialization vector. When providing a string, it must be base64-encoded. * @param ciphertext The encrypted data. Should not include GCM tag. When providing a string, it must be base64-encoded. * @param tag The authentication tag. When providing a string, it must be base64-encoded. * @returns A SealedData object. */ static fromParts(iv: BinaryInput, ciphertext: BinaryInput, tag: BinaryInput): AESSealedData; /** * Static method. Creates a SealedData instance from separate nonce, ciphertext, and optionally a tag. * @param iv The initialization vector. When providing a string, it must be base64-encoded. * @param ciphertextWithTag The encrypted data with GCM tag appended. When providing a string, it must be base64-encoded. * @param tagLength Authentication tag length in bytes. Defaults to 16. * @returns A SealedData object. */ static fromParts( iv: BinaryInput, ciphertextWithTag: BinaryInput, tagLength?: number ): AESSealedData; static fromParts( iv: BinaryInput, ciphertext: BinaryInput, tag?: BinaryInput | number ): AESSealedData { const processedIV = convertBinaryInput(iv); const processedCiphertext = convertBinaryInput(ciphertext); if (!tag || typeof tag === 'number') { return AesCryptoModule.SealedData.fromParts(processedIV, processedCiphertext, tag as number); } else { const processedTag = convertBinaryInput(tag); return AesCryptoModule.SealedData.fromParts(processedIV, processedCiphertext, processedTag); } } /** * Static method. Creates a SealedData instance from a combined byte array, including the IV, ciphertext, and tag. * @param combined The combined data array. When providing a string, it must be base64-encoded. * @param config Configuration specifying IV and tag lengths. * @returns A SealedData object. */ static fromCombined(combined: BinaryInput, config?: AESSealedDataConfig): AESSealedData { const processedInput = convertBinaryInput(combined); return AesCryptoModule.SealedData.fromCombined(processedInput, config); } } /** * Encrypts the given plaintext using AES-GCM with the specified key. * @param plaintext The data to encrypt. When providing a string, it must be base64-encoded. * @param key The encryption key to use. * @param options Optional encryption parameters including nonce, tag length, and additional data. * @returns A promise that resolves to a SealedData instance containing the encrypted data. */ export function aesEncryptAsync( plaintext: BinaryInput, key: AESEncryptionKey, options: AESEncryptOptions = {} ): Promise { type NativeEncryptOptions = Omit & { nonce?: number | BinaryInput | undefined; }; const { nonce: iv, additionalData: aad, ...rest } = options; let nativeOptions: NativeEncryptOptions = { ...rest }; if (iv) { const nonce = 'bytes' in iv ? convertBinaryInput(iv.bytes, true) : iv?.length; nativeOptions = { ...nativeOptions, nonce }; } if (aad) { const additionalData = convertBinaryInput(aad, true); nativeOptions = { ...nativeOptions, additionalData }; } return AesCryptoModule.encryptAsync(convertBinaryInput(plaintext), key, nativeOptions); } /** @hidden */ export function aesDecryptAsync( sealedData: AESSealedData, key: AESEncryptionKey, options: Base64DecryptOptions ): Promise; /** @hidden */ export function aesDecryptAsync( sealedData: AESSealedData, key: AESEncryptionKey, options?: ArrayBufferDecryptOptions ): Promise; /** * Decrypts the given sealed data using the specified key and options. * @param sealedData The data to decrypt. * @param key The key to use for decryption. * @param options Options for decryption, including output encoding and additional data. * @returns A promise that resolves to the decrypted data buffer or string, depending on encoding option. */ export function aesDecryptAsync( sealedData: AESSealedData, key: AESEncryptionKey, options?: AESDecryptOptions ): Promise; export function aesDecryptAsync( sealedData: AESSealedData, key: AESEncryptionKey, options: AESDecryptOptions = {} ): Promise { const { additionalData, ...rest } = options; const nativeOptions = { ...rest, additionalData: additionalData ? convertBinaryInput(additionalData, true) : undefined, }; return AesCryptoModule.decryptAsync(sealedData, key, nativeOptions); } function convertBinaryInput(input: BinaryInput, useBase64: boolean = false): BinaryInput { // Native implementations don't support ArrayBuffers directly yet const bytes = input instanceof ArrayBuffer ? new Uint8Array(input) : input; if (typeof bytes !== 'string' && useBase64) { return uint8ArrayToBase64(bytes); } return bytes; }