encryptWalletToBundle function

Future<String> encryptWalletToBundle({
  1. required String mnemonic,
  2. required String importBundle,
  3. required String userId,
  4. required String organizationId,
  5. String? dangerouslyOverrideSignerPublicKey,
})

Encrypts a mnemonic wallet bundle using HPKE and verifies the enclave signature.

This function securely encrypts a mnemonic phrase using HPKE (Hybrid Public Key Encryption) based on a target public key extracted from the provided import bundle. The function also verifies the integrity of the enclave signature to ensure the authenticity of the bundle before encryption.

Parameters:

  • mnemonic: The mnemonic phrase to encrypt.
  • importBundle: A JSON string representing the import bundle, which includes enclave-generated metadata and target public key.
  • userId: The user ID associated with the import bundle.
  • organizationId: The organization ID associated with the import bundle.
  • dangerouslyOverrideSignerPublicKey: Optionally override the default signer public key for testing purposes.

Returns:

  • A String representing the encrypted wallet bundle in JSON format.

Throws:

  • Exception: If the enclave signature verification fails, or if the bundle validation fails (e.g., mismatched organization or user ID).

Implementation

Future<String> encryptWalletToBundle({
  required String mnemonic,
  required String importBundle,
  required String userId,
  required String organizationId,
  String? dangerouslyOverrideSignerPublicKey,
}) async {
  final Map<String, dynamic> parsedImportBundle = jsonDecode(importBundle);
  final Uint8List plainTextBuf = Uint8List.fromList(utf8.encode(mnemonic));
  final bool verified = await verifyEnclaveSignature(
    enclaveQuorumPublic: parsedImportBundle['enclaveQuorumPublic'],
    publicSignature: parsedImportBundle['dataSignature'],
    signedData: parsedImportBundle['data'],
    dangerouslyOverrideSignerPublicKey: dangerouslyOverrideSignerPublicKey,
  );

  if (!verified) {
    throw Exception('Failed to verify enclave signature: $importBundle');
  }

  final Uint8List dataBytes =
      uint8ArrayFromHexString(parsedImportBundle['data']);
  final String signedDataJson = utf8.decode(dataBytes);
  final Map<String, dynamic> signedData = jsonDecode(signedDataJson);

  if (signedData['organizationId'] == null ||
      signedData['organizationId'] != organizationId) {
    throw Exception(
      'Organization ID does not match expected value. '
      'Expected: $organizationId. Found: ${signedData["organizationId"]}.',
    );
  }

  if (signedData['userId'] == null || signedData['userId'] != userId) {
    throw Exception(
      'User ID does not match expected value. '
      'Expected: $userId. Found: ${signedData["userId"]}.',
    );
  }

  if (signedData['targetPublic'] == null) {
    throw Exception('Missing "targetPublic" in bundle signed data.');
  }

  // Load target public key generated from enclave
  final Uint8List targetKeyBuf =
      uint8ArrayFromHexString(signedData['targetPublic']);
  final Uint8List privateKeyBundle = hpkeEncrypt(
    plainTextBuf: plainTextBuf,
    targetKeyBuf: targetKeyBuf,
    hpkeInfo: zeroxkeyHpkeInfo,
  );
  return formatHpkeBuf(privateKeyBundle);
}