streamXOR static method

List<int> streamXOR(
  1. List<int> key,
  2. List<int> nonce,
  3. List<int> src,
  4. List<int> dst, {
  5. int nonceInplaceCounterLength = 0,
})

Encrypts or decrypts data by XORing it with the output of the ChaCha stream cipher.

This function takes a key, nonce, source data (src), and destination data (dst) and encrypts or decrypts the source data by XORing it with the output of the ChaCha stream cipher. The nonce can be used with or without an inplace counter, depending on the value of nonceInplaceCounterLength.

Parameters:

  • key: The 256-bit (32-byte) encryption key as a List
  • nonce: The nonce data, which must be either 8, 12, or 16 bytes in length depending on the value of nonceInplaceCounterLength.
  • src: The source data to be encrypted or decrypted.
  • dst: The destination data where the result will be written.
  • nonceInplaceCounterLength: An optional parameter to specify the length of the nonce inplace counter (0 for no counter, 16 bytes if a counter is included in the nonce).

Throws:

  • ArgumentException if the key size is not 32 bytes, if the destination is shorter than the source, or if the nonce length is invalid.

Returns:

  • The dst List

Note: This function securely zeros temporary data to protect sensitive information.

Implementation

static List<int> streamXOR(
    List<int> key, List<int> nonce, List<int> src, List<int> dst,
    {int nonceInplaceCounterLength = 0}) {
  // We only support 256-bit keys.
  if (key.length != 32) {
    throw const ArgumentException("ChaCha: key size must be 32 bytes");
  }

  if (dst.length < src.length) {
    throw const ArgumentException(
        "ChaCha: destination is shorter than source");
  }

  List<int> nc;
  int counterLength;

  if (nonceInplaceCounterLength == 0) {
    if (nonce.length != 8 && nonce.length != 12) {
      throw const ArgumentException("ChaCha nonce must be 8 or 12 bytes");
    }
    nc = List<int>.filled(16, 0);
    counterLength = nc.length - nonce.length;
    nc.setAll(counterLength, nonce);
  } else {
    if (nonce.length != 16) {
      throw const ArgumentException(
          "ChaCha nonce with counter must be 16 bytes");
    }
    nc = nonce;
    counterLength = nonceInplaceCounterLength;
  }

  final block = List<int>.filled(64, 0);

  for (int i = 0; i < src.length; i += 64) {
    _core(block, nc, key);

    for (int j = i; j < i + 64 && j < src.length; j++) {
      dst[j] = (src[j] & mask8) ^ block[j - i];
    }

    _incrementCounter(nc, 0, counterLength);
  }

  zero(block);

  if (nonceInplaceCounterLength == 0) {
    zero(nc);
  }

  return dst;
}