encrypt method
- List<
int> clearText, { - required SecretKey secretKey,
- List<
int> ? nonce, - List<
int> aad = const <int>[], - int keyStreamIndex = 0,
- Uint8List? possibleBuffer,
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);
}