streamXOR static method
Encrypts or decrypts data by XORing it with the output of the ChaCha stream cipher.
Parameters:
key: The 256-bit (32-byte) encryption key`.nonce: The nonce data, which must be either 8, 12, or 16 bytes in length depending on the value ofnonceInplaceCounterLength.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.invalidBytesArgumentLength(reason:if the key size is not 32 bytes, if the destination is shorter than the source, or if the nonce length is invalid.
Implementation
static List<int> streamXOR(
List<int> key,
List<int> nonce,
List<int> src,
List<int> dst, {
int nonceInplaceCounterLength = 0,
int seekBytes = 0,
}) {
// We only support 256-bit keys.
if (key.length != 32) {
throw ArgumentException.invalidOperationArguments(
"streamXOR",
name: "key",
reason: "Invalid key bytes length.",
);
}
if (dst.length < src.length) {
throw ArgumentException.invalidOperationArguments(
"streamXOR",
name: "dst",
reason: "Invalid destination bytes length.",
);
}
List<int> nc;
int counterLength;
if (nonceInplaceCounterLength == 0) {
if (nonce.length != 8 && nonce.length != 12) {
throw ArgumentException.invalidOperationArguments(
"streamXOR",
name: "nonce",
reason: "Invalid nonce bytes length.",
);
}
nc = List<int>.filled(16, 0);
counterLength = nc.length - nonce.length;
nc.setAll(counterLength, nonce);
} else {
if (nonce.length != 16) {
throw ArgumentException.invalidOperationArguments(
"streamXOR",
name: "nonce",
reason: "Invalid nonce bytes length.",
);
}
nc = nonce;
counterLength = nonceInplaceCounterLength;
}
BinaryOps.zero(dst);
final block = List<int>.filled(64, 0);
final int blockSkip = seekBytes ~/ 64;
final int byteSkip = seekBytes % 64;
if (blockSkip != 0) {
for (int b = 0; b < blockSkip; b++) {
for (int i = 0; i < src.length; i += 64) {
_core(block, nc, key);
for (int j = 0; j < 64 && i + j < src.length; j++) {
dst[i + j] = (src[i + j] & BinaryOps.mask8) ^ block[j];
}
_incrementCounter(nc, 0, counterLength);
}
}
}
int srcOffset = 0;
if (byteSkip != 0) {
_core(block, nc, key);
// XOR only after byteSkip
for (
int j = byteSkip;
j < 64 && srcOffset < src.length;
j++, srcOffset++
) {
dst[srcOffset] = (src[srcOffset] & BinaryOps.mask8) ^ block[j];
}
_incrementCounter(nc, 0, counterLength);
}
for (; srcOffset < src.length; srcOffset += 64) {
_core(block, nc, key);
for (int j = 0; j < 64 && srcOffset + j < src.length; j++) {
dst[srcOffset + j] = (src[srcOffset + j] & BinaryOps.mask8) ^ block[j];
}
_incrementCounter(nc, 0, counterLength);
}
BinaryOps.zero(block);
if (nonceInplaceCounterLength == 0) {
BinaryOps.zero(nc);
}
return dst;
}