Class ConnectionEncryptionData
- Namespace
- FishMMO.Auth.Implementation
- Assembly
- FishMMO-AuthShared.dll
Holds per-connection encryption state including directional AES keys, nonce contexts, and negotiated protocol version. Keys are established via X25519 ECDH key agreement during the handshake phase.
Thread-safety: nonce contexts use Interlocked internally for counter operations.
public class ConnectionEncryptionData : IDisposable
- Inheritance
-
ConnectionEncryptionData
- Implements
- Inherited Members
Constructors
ConnectionEncryptionData(byte[])
Initializes a new instance storing the peer's public key. Directional keys and nonce contexts remain null until PromoteToDirectional(SessionKeys) is called after the X25519 ECDH key agreement completes.
public ConnectionEncryptionData(byte[] publicKey)
Parameters
publicKeybyte[]The peer's X25519 public key (32 bytes).
Properties
AgreedVersion
Negotiated protocol version for this connection. Set during the handshake and used in AAD construction for all subsequent messages. Defaults to ProtocolVersion for backward compatibility. NOTE: Public setter retained because BaseAuthenticatorCore writes this from the handshake result. This is a simple ushort value (no lock needed).
public ushort AgreedVersion { get; set; }
Property Value
ClientToServerKey
Directional AES keys derived via HKDF-SHA256. ClientToServerKey is used to decrypt client→server messages.
ServerToClientKey is used to encrypt server→client messages.
public byte[]? ClientToServerKey { get; }
Property Value
- byte[]
MasterSecret
Master secret derived via X25519 ECDH + HKDF. Null after promotion to directional keys.
public byte[]? MasterSecret { get; }
Property Value
- byte[]
PublicKey
The client's X25519 public key received during the handshake.
public byte[]? PublicKey { get; }
Property Value
- byte[]
ReceiveNonceCtx
Nonce context for client→server (receive/decrypt) direction. Owns the client prefix and receive counter. Null until PromoteToDirectional(SessionKeys) is called. Private setter prevents external code from bypassing the FishMMO.Auth.Implementation.ConnectionEncryptionData.clearLock that Clear() and NextReceiveNonce() use for thread safety.
public CryptoHelper.GcmNonceContext? ReceiveNonceCtx { get; }
Property Value
SendNonceCtx
Nonce context for server→client (send/encrypt) direction. Owns the server prefix and send counter. Null until PromoteToDirectional(SessionKeys) is called. Private setter prevents external code from bypassing the FishMMO.Auth.Implementation.ConnectionEncryptionData.clearLock that Clear() and NextSendNonce() use for thread safety.
public CryptoHelper.GcmNonceContext? SendNonceCtx { get; }
Property Value
ServerToClientKey
public byte[]? ServerToClientKey { get; }
Property Value
- byte[]
Methods
BuildReceiveNonce(uint)
Builds a receive-direction nonce for a specific sequence number. Use after TryConsumeReceiveSequence(uint) has validated the sequence.
public byte[] BuildReceiveNonce(uint seq)
Parameters
sequint
Returns
- byte[]
BuildSendNonce(uint)
Builds a send-direction nonce for a specific sequence number. Use when the sequence was obtained from NextSendSequence().
public byte[] BuildSendNonce(uint seq)
Parameters
sequint
Returns
- byte[]
Clear()
Zeroes all sensitive key material and disposes nonce contexts.
Call before removing the entry from the AccountManager.
public void Clear()
CloneForAsyncWorker()
Creates a snapshot suitable for async worker processing. Key material is shared (read-only after derivation); nonce contexts are SHARED (not cloned) — GcmNonceContext is already thread-safe via Interlocked for all counter operations. Sharing ensures that all workers processing messages for the same connection observe a single monotonic sequence space, preventing both receive-sequence rejection and catastrophic send-nonce reuse.
public ConnectionEncryptionData CloneForAsyncWorker()
Returns
Remarks
IMPORTANT — do not dispose the clone. The returned clone shares
GcmNonceContext references with the original. Never call
Clear() or Dispose() on the clone — the original
owns disposal of all key material and nonce contexts. Calling Clear()
on the clone will dispose the shared GcmNonceContext instances,
corrupting the original and all other clones derived from it.
Dispose()
Releases all sensitive key material by zeroing buffers and disposing nonce contexts. Suppresses finalization since the work is done eagerly.
public void Dispose()
~ConnectionEncryptionData()
Zeroes all sensitive key material and disposes nonce contexts. Called by the finalizer as a safety net on the ORIGINAL instance only. Clones share nonce context references — their finalizer must NOT dispose them.
protected ~ConnectionEncryptionData()
NextReceiveNonce()
Builds the next client→server GCM nonce and advances the receive counter.
public (byte[] Nonce, uint Sequence) NextReceiveNonce()
Returns
Remarks
The lock is held across both the reference read and the NextNonce() call
to prevent a concurrent Clear() from disposing the context mid-operation.
NextSendNonce()
Builds the next server→client GCM nonce and advances the send counter.
public (byte[] Nonce, uint Sequence) NextSendNonce()
Returns
Remarks
The lock is held across both the reference read and the NextNonce() call
to prevent a concurrent Clear() from disposing the context mid-operation.
NextSendSequence()
Atomically increments and returns the next send sequence number without building a nonce. Use when the sequence is needed for AAD construction and the nonce will be built separately via BuildSendNonce(uint).
public uint NextSendSequence()
Returns
- uint
The next send sequence number.
PromoteToDirectional(SessionKeys)
Promotes the stored state into directional keys and nonce contexts using derived session keys. Creates GcmNonceContext instances that own their respective prefixes and enforce nonce uniqueness per direction.
public void PromoteToDirectional(CryptoHelper.SessionKeys keys)
Parameters
keysCryptoHelper.SessionKeys
TryConsumeReceiveSequence(uint)
Attempts to consume an expected receive sequence number.
Returns true and advances the counter if seq is exactly
one greater than the current counter. Returns false for duplicates or gaps.
public bool TryConsumeReceiveSequence(uint seq)
Parameters
sequintThe expected incoming sequence number to consume.
Returns
- bool
trueif consumed;falseotherwise.
TryConsumeReceiveSequenceRange(uint, uint)
Atomically consumes a contiguous receive-sequence range
[baseSeq, baseSeq + count - 1]. Use when a single logical message
spans multiple wire-level sequence numbers (e.g. multi-field encrypted
payloads) so that a partial failure cannot leave the counter advanced
part-way through.
public bool TryConsumeReceiveSequenceRange(uint baseSeq, uint count)
Parameters
Returns
- bool
trueon success;falseon duplicate/gap/exhaustion.