Table of Contents

Class EncryptionModule

Namespace
Nucs.JsonSettings.Modulation
Assembly
Nucs.JsonSettings.dll

Encrypts the serialized configuration with a symmetric algorithm from the .NET base class library (System.Security.Cryptography). The algorithm is selected with Algorithm; the default, AesCbc, is byte-for-byte compatible with every file this library has ever written.

public class EncryptionModule : Module, IDisposable
Inheritance
EncryptionModule
Implements
Derived
Inherited Members

Remarks

The secret can be supplied three ways:

Exactly one source is active per module. There is no algorithm or key-size marker in the file, so decrypting requires configuring the same Algorithm, KeySize and secret the file was written with - exactly as the password has always had to match.

Constructors

EncryptionModule(byte[])

A binary password. Run through the same PBKDF2 derivation as a text password - stretched and salted - but a DIFFERENT credential from the text password whose UTF-8 bytes happen to match.

public EncryptionModule(byte[] password)

Parameters

password byte[]

EncryptionModule(Func<byte[]>)

A binary password resolved on demand. See EncryptionModule(byte[]).

public EncryptionModule(Func<byte[]> passwordFetcher)

Parameters

passwordFetcher Func<byte[]>

EncryptionModule(Func<byte[]>, bool)

protected EncryptionModule(Func<byte[]> fetcher, bool rawKey)

Parameters

fetcher Func<byte[]>
rawKey bool

EncryptionModule(Func<SecureString>)

public EncryptionModule(Func<SecureString> passwordFetcher)

Parameters

passwordFetcher Func<SecureString>

EncryptionModule(Func<string>)

public EncryptionModule(Func<string> passwordFetcher)

Parameters

passwordFetcher Func<string>

EncryptionModule(SecureString)

public EncryptionModule(SecureString password)

Parameters

password SecureString

EncryptionModule(string)

public EncryptionModule(string password)

Parameters

password string

Fields

EmptyString

public static readonly SecureString EmptyString

Field Value

SecureString

Properties

Algorithm

The symmetric algorithm used, by default AesCbc - the historical, on-disk-compatible format.

public virtual EncryptionAlgorithm Algorithm { get; set; }

Property Value

EncryptionAlgorithm

KeySize

The AES key size for the AES-based algorithms, by default Aes256. Ignored by ChaCha20Poly1305, which is always 256-bit.

public virtual KeySize KeySize { get; set; }

Property Value

KeySize

Password

The password passed during constructor stored as a SecureString in memory.

public virtual SecureString Password { get; set; }

Property Value

SecureString

Methods

AfterDecryptInternal(JsonSettings, ref byte[])

Wrong-password heuristic for the unauthenticated AesCbc path. Runs once the whole decrypt chain has completed, so data is the final plaintext this library is about to read as JSON.

protected virtual void AfterDecryptInternal(JsonSettings sender, ref byte[] data)

Parameters

sender JsonSettings
data byte[]

Remarks

WHY ONLY FOR AES-CBC. Every other algorithm authenticates during DecryptInternal(JsonSettings, ref byte[]) (a GCM/CCM/ChaCha20 tag, or the HMAC of AES-CBC-HMAC), so a wrong key or a tampered file already failed there with a real integrity error and never reaches here. AES-CBC alone cannot tell a wrong key from a right one: CBC decryption with the wrong key yields random bytes, and PKCS7 padding validation accepts those by chance roughly once in 256 attempts. When it does, decryption "succeeds", the garbage reaches the JSON parser, and the user is told the file is corrupt rather than that the password was wrong. Checking the final plaintext is valid UTF-8 is a diagnostic for that case.

WHY AFTER THE CHAIN AND NOT INSIDE DecryptInternal(JsonSettings, ref byte[]). The test rests on "what this library encrypts is always UTF-8 JSON", which holds only for the FINAL plaintext. A caller may attach another module inside the encryption layer - a compressor, an encoder - and then this module's own output is that module's still-encoded input, with no reason to be UTF-8. Deferring to AfterDecrypt inspects the plaintext no matter how many layers produced it.

This is a diagnostic improvement for AES-CBC, not an integrity guarantee - the authenticated algorithms are what provide that.

Attach(JsonSettings)

public override void Attach(JsonSettings socket)

Parameters

socket JsonSettings

CloneFetcher(byte[])

protected static Func<byte[]> CloneFetcher(byte[] material)

Parameters

material byte[]

Returns

Func<byte[]>

Deattach(JsonSettings)

public override void Deattach(JsonSettings socket)

Parameters

socket JsonSettings

DecryptInternal(JsonSettings, ref byte[])

protected virtual void DecryptInternal(JsonSettings sender, ref byte[] data)

Parameters

sender JsonSettings
data byte[]

EncryptInternal(JsonSettings, ref byte[])

protected virtual void EncryptInternal(JsonSettings sender, ref byte[] data)

Parameters

sender JsonSettings
data byte[]

FromRawKey(byte[])

Builds a module that uses key verbatim as the key, with no key derivation. For the default AES algorithms the key must be 16, 24 or 32 bytes; other algorithms validate their own length when the module runs.

public static EncryptionModule FromRawKey(byte[] key)

Parameters

key byte[]

Returns

EncryptionModule

FromRawKey(Func<byte[]>)

Builds a module that uses the key returned by keyFetcher verbatim, with no key derivation. The key length must match the chosen algorithm each time it is resolved.

public static EncryptionModule FromRawKey(Func<byte[]> keyFetcher)

Parameters

keyFetcher Func<byte[]>

Returns

EncryptionModule