Class KeyEnvelope
- Namespace
- FishMMO.Auth.Implementation
- Assembly
- FishMMO-AuthShared.dll
AEAD envelope (AES-256-GCM) for wrapping symmetric key material at rest.
public static class KeyEnvelope
- Inheritance
-
KeyEnvelope
- Inherited Members
Remarks
Sealed blob layout:
[0..3] magic (4 bytes, identifies a wrapped blob)
[4] version (1 byte, currently 0x01)
[5..16] nonce (12 bytes, GCM nonce)
[17..N] ciphertext (= plaintext length bytes)
[N..N+15] tag (16 bytes, GCM auth tag)
The magic prefix lets readers distinguish a wrapped blob from a legacy raw 32-byte HMAC key on the same column without an additional schema flag. The false-positive probability for a uniformly-random 32-byte key beginning with the 4-byte magic is 2-32 ≈ negligible; in practice all newly written keys are produced via Wrap(byte[], byte[], byte[]) so the discriminator is unambiguous.
The KEK is supplied per call (e.g. loaded once at startup from a deployment-level secret distinct from the database). A leaked DB dump without the KEK does not disclose any signing-key material.
Fields
HeaderSize
Header length (magic + version + nonce) preceding ciphertext.
public const int HeaderSize = 17
Field Value
Magic
Magic prefix identifying a sealed blob produced by Wrap(byte[], byte[], byte[]).
public static readonly byte[] Magic
Field Value
- byte[]
MinWrappedLength
Minimum length of any sealed blob produced by Wrap(byte[], byte[], byte[]).
public const int MinWrappedLength = 33
Field Value
NonceSize
AES-GCM nonce length in bytes.
public const int NonceSize = 12
Field Value
TagSize
AES-GCM authentication tag length in bytes.
public const int TagSize = 16
Field Value
Version1
Current sealed-blob version. Bump on incompatible layout changes.
public const byte Version1 = 1
Field Value
Methods
LooksWrapped(byte[])
Returns true when blob begins with the wrapped-blob
magic prefix and is structurally large enough to be a valid envelope. Does not
validate the GCM tag — callers must still call Unwrap(byte[], byte[], byte[]) for that.
public static bool LooksWrapped(byte[] blob)
Parameters
blobbyte[]
Returns
Unwrap(byte[], byte[], byte[])
Decrypts a sealed blob produced by Wrap(byte[], byte[], byte[]) under kek,
validating aad. Returns the plaintext on success or null
on any structural, version, or authentication failure (the caller MUST treat
null as a hard failure and fail closed; do not retry with a different KEK).
public static byte[]? Unwrap(byte[] kek, byte[] wrappedBlob, byte[] aad)
Parameters
Returns
- byte[]
Wrap(byte[], byte[], byte[])
Encrypts plaintext under kek with AES-256-GCM,
authenticating aad. Returns the sealed blob.
public static byte[] Wrap(byte[] kek, byte[] plaintext, byte[] aad)
Parameters
kekbyte[]32-byte key-encryption key (AES-256).
plaintextbyte[]Key material to wrap. Caller retains ownership and is responsible for zeroing it after the call returns.
aadbyte[]Additional authenticated data bound to the ciphertext (e.g. the owning row's stable identifier). May be empty but should be non-null and stable across Wrap(byte[], byte[], byte[])/Unwrap(byte[], byte[], byte[]) cycles.
Returns
- byte[]
The sealed blob.