encryptStream method

Stream<List<int>> encryptStream(
  1. Stream<List<int>> stream, {
  2. required SecretKey secretKey,
  3. required List<int> nonce,
  4. required void onMac(
    1. Mac mac
    ),
  5. List<int> aad = const [],
  6. bool allowUseSameBytes = false,
})

Encrypts a Stream of bytes.

Parameter stream is the encrypted stream of bytes.

Parameter secretKey is the secret key. You can generate a random secret key with newSecretKey.

Optional parameter nonce (also known as "initialization vector", "IV", or "salt") is some sequence of bytes. You can generate a nonce with newNonce. If you don't define it, the cipher will generate a random nonce for you. The nonce must be unique for each encryption with the same secret key. It doesn't have to be secret.

You will receive a Message Authentication Code (MAC) using the callback onMac after the input stream is closed and before the output stream is closed. For example, if your macAlgorithm is MacAlgorithm.empty, the MAC will be Mac.empty.

You can use aad to pass Associated Authenticated Data (AAD).

If allowUseSameBytes is true, the method is allowed (but not required) to reduce memory allocations by using the same byte array for input and output. If you use the same byte array for other purposes, this may be unsafe.

The default implementation reads the input stream into a buffer and, after the input stream has been closed, calls encrypt. Subclasses are encouraged to override the default implementation so that the input stream is processed as it is received.

Example

import 'package:browser_cryptography.dart';

void main() {
  final cipher = Chacha20.poly1305Aead();
  final secretKey = cipher.newSecretKey();
  final nonce = cipher.newNonce();

  final file = File('example.txt');
  final encryptedFile = File('example.txt.encrypted');

  final sink = encryptedFile.openWrite();
  try {
    final clearTextStream = file.openRead();
    final encryptedStream = state.encryptStream(
      clearTextStream,
      secretKey: secretKey,
      nonce: nonce,
    );
    await encryptedSink.addStream(encryptedStream);
  } finally {
    sink.close();
  }
}

Implementation

Stream<List<int>> encryptStream(
  Stream<List<int>> stream, {
  required SecretKey secretKey,
  required List<int> nonce,
  required void Function(Mac mac) onMac,
  List<int> aad = const [],
  bool allowUseSameBytes = false,
}) async* {
  final state = newState();
  await state.initialize(
    isEncrypting: true,
    secretKey: secretKey,
    nonce: nonce,
    aad: aad,
  );
  var count = 0;
  await for (var chunk in stream) {
    final convertedChunk = state.convertChunkSync(
      chunk,
      possibleBuffer: allowUseSameBytes && chunk is Uint8List ? chunk : null,
    );
    yield (convertedChunk);

    // Pause every now and then to avoid blocking the event loop.
    count += chunk.length;
    if (count >= _pauseFrequencyInBytes) {
      await Future.delayed(_pauseDuration);
      count = 0;
    }
  }
  final convertedSuffix = await state.convert(
    _emptyUint8List,
    expectedMac: null,
  );
  if (convertedSuffix.isNotEmpty) {
    yield (convertedSuffix);
  }
  onMac(state.mac);
}