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,
})
override

Encrypts bytes and returns SecretBox. Authenticates SecretBox with macAlgorithm, decrypts it, and returns the cleartext.

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 non-secret unique sequence of bytes. If you don't define it, the cipher will generate nonce for you.

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.

Implementation

@override
Future<SecretBox> encrypt(
  List<int> clearText, {
  required SecretKey secretKey,
  List<int>? nonce,
  List<int> aad = const <int>[],
  int keyStreamIndex = 0,
}) 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 (nonceLength != 16) {
    throw ArgumentError.value(
      nonce,
      'nonce',
      'Expected nonce with 16 bytes, got $nonceLength bytes',
    );
  }
  if (keyStreamIndex < 0) {
    throw ArgumentError.value(
      keyStreamIndex,
      'keyStreamIndex',
    );
  }

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

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

  // Fill output with input + PKCS7 padding
  cipherTextBytes.setRange(0, clearText.length, clearText);
  cipherTextBytes.fillRange(
    clearText.length,
    cipherTextBytes.lengthInBytes,
    paddingLength,
  );
  if (Endian.host == Endian.big) {
    final outputByteData = ByteData.view(cipherTextBytes.buffer);
    for (var i = 0; i < cipherTextBytes.length; i += 4) {
      cipherTextBytes[i] = outputByteData.getUint32(i, Endian.big);
    }
  }

  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);
}