Encryption

AES-256-CBC with HMAC-SHA256, encrypt-then-MAC, why AEAD is absent, and the honest boundaries of client-side confidentiality.

Security NexusForge Persistence 0.2.0 Updated

What encryption answers#

"Can someone who has the file read it?" Enabling it also gets you authentication: an encrypted save is always authenticated, because the composition requires it.

csharp
options.Security.EncryptionAlgorithm = SaveFileFormat.EncryptionAes256CbcHmacSha256;
options.Security.CompressionAlgorithm = SaveFileFormat.CompressionDeflate;   // applied before encryption
options.Security.KeyId = 3;                                                  // which key; never a secret

Encrypt-then-MAC, with independent keys#

  1. The payload is compressed (if enabled) and encrypted with AES-256-CBC.
  2. A HMAC-SHA256 tag is computed over the header, the metadata, the nonce and the ciphertext.
  3. On read, the tag is verified before any decryption, then the payload is decrypted and verified again by the integrity value.

The two keys are separate (SaveKeyPurpose.Encryption, SaveKeyPurpose.Authentication).

Why not AES-GCM#

AEAD (AES-GCM) is deliberately not used, because its API sits outside the .NET Standard 2.1 surface this package compiles against. Rather than depend on a type that may not exist in a given runtime, SecurityCapabilityProbe reports what the running platform actually provides, and encrypt-then-MAC with independent keys — the standard composition — is used instead. Verified

csharp
var capabilities = SecurityCapabilityProbe.Probe();   // exercises the primitives instead of assuming

What encryption does not cover#

  • Memory. A process that can read your game's memory can read the plaintext.
  • The metadata block. It stays readable so slot listings work without a key. Its integrity is protected, its contents are not secret.
  • Keys you embed. A key compiled into a build is not protection. See Key providers.
  • Rollback. Replacing a save with an older valid file is not detectable on the client.

Next#

Something wrong on this page? Every page here describes behaviour that is checked in the repository. If a page and the package disagree, the package wins.

Report a documentation problem · Frequently asked questions · Troubleshooting