protect method
Protects plaintext
and returns a SecureMessage
ready for wire encoding.
INPUT:
plaintext
: raw bytes to encrypt (non-empty)
OUTPUT:
SecureMessage
with fields: version = config.protocolVersion window = floor(epochSeconds / windowSeconds) nonce = 8B nonce ciphertext = AES-256-CBC ciphertext tag = HMAC-SHA256 over ("tag" || u64be(window) || nonce || ciphertext)
Throws:
- InvalidMessageException if inputs are malformed.
- InternalCryptoException/DecryptionFailedException on crypto errors.
HINT: Serialize with ApiClient.toWire(message)
to obtain headers/body.
Implementation
SecureMessage protect(Uint8List plaintext) {
if (plaintext.isEmpty) {
throw InvalidMessageException(
cause: ArgumentError('plaintext must not be empty.'),
);
}
try {
// 1) Current window
final int window = _cfg.currentWindow();
// 2) Fresh nonce (8 bytes)
final nonce = _nonceGen.nextNonce();
// 3) IV from macKey + ("iv"||u64be(window)||nonce)
final iv = IvDeriver.derive(
macKey: _keys.macKey,
window: window,
nonce: nonce,
);
// 4) Encrypt
final ciphertext = OtpCipher.encrypt(
encKey: _keys.encKey,
iv: iv,
plaintext: plaintext,
);
// 5) Tag from macKey + ("tag"||u64be(w)||nonce||ciphertext)
final tag = TagDeriver.derive(
macKey: _keys.macKey,
window: window,
nonce: nonce,
ciphertext: ciphertext,
);
// 6) Build message
final msg = SecureMessage.fromParts(
version: _cfg.protocolVersion,
window: window,
nonce: nonce,
ciphertext: ciphertext,
tag: tag,
);
return msg;
} catch (e, st) {
// Wrap unexpected issues in a generic internal error.
throw InternalCryptoException(cause: e, stackTrace: st);
}
}