encrypt method

  1. @override
Future<SecretBox> encrypt(
  1. List<int> clearText, {
  2. required SecretKey secretKey,
  3. List<int>? nonce,
  4. List<int> aad = const <int>[],
  5. int keyStreamIndex = 0,
  6. Uint8List? possibleBuffer,
})
override

Encrypts bytes and returns SecretBox.

You must give a SecretKey that has the correct length and type.

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.

Parameter aad can be used to pass Associated Authenticated Data (AAD). If you pass a non-empty list and the underlying cipher doesn't support AAD, the method will throw ArgumentError.

If possibleBuffer is non-null, the method is allowed (but not required) to write the output to it. The buffer can be the same as clearText. Otherwise the method will allocate memory for the output.

Implementation

@override
Future<SecretBox> encrypt(
  List<int> clearText, {
  required SecretKey secretKey,
  List<int>? nonce,
  List<int> aad = const <int>[],
  int keyStreamIndex = 0,
  Uint8List? possibleBuffer,
}) async {
  // Check parameters
  final secretKeyData = await secretKey.extract();
  final actualSecretKeyLength = secretKeyData.bytes.length;
  final expectedSecretKeyLength = secretKeyLength;
  if (actualSecretKeyLength != expectedSecretKeyLength) {
    throw ArgumentError.value(
      secretKey,
      'secretKey',
      'Expected $secretKeyLength bytes, got $actualSecretKeyLength bytes',
    );
  }
  nonce ??= newNonce();
  if (nonce.length != nonceLength) {
    throw ArgumentError.value(
      nonce,
      'nonce',
      'Expected nonce with $nonceLength bytes, got ${nonce.length} bytes',
    );
  }
  if (keyStreamIndex < 0) {
    throw ArgumentError.value(
      keyStreamIndex,
      'keyStreamIndex',
    );
  }

  // Expand key
  final expandedKey = aesExpandKeyForEncrypting(secretKeyData);

  // Construct Uint32List list for the output
  final paddingLength = paddingAlgorithm.paddingLength(
    _blockLength,
    clearText.length,
  );
  final cipherTextBlocks = Uint32List(
    (clearText.length + paddingLength) ~/ 16 * 4,
  );
  final cipherTextBytes = Uint8List.view(cipherTextBlocks.buffer);

  // Write clear text to buffer
  cipherTextBytes.setRange(0, clearText.length, clearText);

  // Fill output with input + PKCS7 padding
  paddingAlgorithm.setBlockPadding(
    _blockLength,
    cipherTextBytes,
    clearText.length,
  );

  // Handle big-endian systems.
  flipUint32ListEndianUnless(cipherTextBlocks, Endian.little);

  for (var i = 0; i < cipherTextBlocks.length; i += 4) {
    if (i == 0) {
      // block ^= nonce
      final nonceBytes = nonce;
      for (var i = 0; i < nonceBytes.length; i++) {
        cipherTextBytes[i] ^= nonceBytes[i];
      }
    } else {
      // block ^= previous_block
      for (var j = 0; j < 4; j++) {
        cipherTextBlocks[i + j] ^= cipherTextBlocks[i + j - 4];
      }
    }

    // Block function
    aesEncryptBlock(
      cipherTextBlocks,
      i,
      cipherTextBlocks,
      i,
      expandedKey,
    );
  }
  final mac = await macAlgorithm.calculateMac(
    cipherTextBytes,
    secretKey: secretKey,
    nonce: nonce,
    aad: aad,
  );
  return SecretBox(cipherTextBytes, nonce: nonce, mac: mac);
}