encryptE2eeBuffer method

NativeOwnedBuffer encryptE2eeBuffer(
  1. int sessionHandle,
  2. NativeOwnedBuffer plaintext, {
  3. String? keyId,
  4. required String cipher,
})

Encrypt a retained frozen input handle and return ciphertext in a new native-owned buffer. No payload bytes cross the Dart/native boundary. The input is never consumed, including when validation or encryption fails.

Implementation

NativeOwnedBuffer encryptE2eeBuffer(
  int sessionHandle,
  NativeOwnedBuffer plaintext, {
  String? keyId,
  required String cipher,
}) {
  _require();
  if (!_ownedE2eeEncryptionSupported) {
    throw UnsupportedError('Native owned-buffer E2EE ABI v1 is unavailable');
  }
  RangeError.checkValueInInterval(
    sessionHandle,
    1,
    0x7fffffff,
    'sessionHandle',
  );
  validateFrozenBuffer(plaintext);
  final cipherCode = switch (cipher) {
    'xsalsa20poly1305' => 1,
    'aes256gcm' => 2,
    _ => throw ArgumentError.value(
      cipher,
      'cipher',
      'Unsupported E2EE cipher',
    ),
  };
  final keyIdBytes = keyId == null ? null : utf8.encode(keyId);
  if ((keyIdBytes?.length ?? 0) > 0x7fffffff) {
    throw ArgumentError.value(keyId, 'keyId', 'Key ID is too long');
  }
  final keyIdPointer = keyId?.toNativeUtf8().cast<ffi.Char>() ?? ffi.nullptr;
  final outHandle = calloc<ffi.Int32>();
  try {
    final status = _encryptOwnedE2ee(
      sessionHandle,
      keyIdPointer,
      keyIdBytes?.length ?? 0,
      plaintext._handle.id,
      cipherCode,
      outHandle,
    );
    if (status != 0) {
      if (outHandle.value > 0) _release(outHandle.value);
      _check(status);
    }
    final id = outHandle.value;
    if (id <= 0) throw StateError('Native E2EE returned no output handle');
    late final ({
      ffi.Pointer<ffi.Uint8> base,
      int capacity,
      int initializedLength,
      int offset,
      int length,
      int writable,
    })
    info;
    try {
      info = _getInfoId(id);
      if (info.writable != 0 || info.length == 0) {
        throw StateError('Native E2EE returned an invalid frozen output');
      }
    } catch (_) {
      _release(id);
      rethrow;
    }
    final handle = _OwnedHandle(this, id, externalSize: info.capacity);
    return NativeOwnedBuffer._(handle, info.length, 0, 0);
  } finally {
    calloc.free(outHandle);
    if (keyIdPointer != ffi.nullptr) malloc.free(keyIdPointer);
  }
}