unprotect method

Uint8List unprotect(
  1. SecureMessage msg
)

Verifies and decrypts a previously parsed SecureMessage.

INPUT:

  • msg: a format-validated message (see SecureMessage.fromWire).

OUTPUT:

  • plaintext bytes if authentication and decryption succeed.

Throws:

HINT:

  • Always call this on the server for incoming requests and on the client for responses returned by the server.

Implementation

Uint8List unprotect(SecureMessage msg) {
  // 1) Protocol version check (extensible: allow only exact match for v1).
  if (msg.version != _cfg.protocolVersion) {
    throw InvalidMessageException(
      cause: ArgumentError.value(
        msg.version,
        'version',
        'Unsupported protocol version; expected ${_cfg.protocolVersion}.',
      ),
    );
  }

  // 2) Window skew check (reject too old/future messages quickly).
  _enforceWindowSkew(msg.window);

  // 3) Verify tag in constant time (Encrypt-then-MAC).
  final computedTag = TagDeriver.derive(
    macKey: _keys.macKey,
    window: msg.window,
    nonce: msg.nonce,
    ciphertext: msg.ciphertext,
  );
  final ok = Bytes.constantTimeEquals(computedTag, msg.tag);
  // Best-effort zeroization (mutable copy).
  Bytes.secureZero(computedTag);

  if (!ok) {
    throw AuthenticationFailedException();
  }

  // 4) Derive IV and decrypt.
  final iv = IvDeriver.derive(
    macKey: _keys.macKey,
    window: msg.window,
    nonce: msg.nonce,
  );

  // If AES fails (e.g., bad padding), OtpCipher throws DecryptionFailedException.
  final plaintext = OtpCipher.decrypt(
    encKey: _keys.encKey,
    iv: iv,
    ciphertext: msg.ciphertext,
  );

  return plaintext;
}