Version: 1.0.3
Target Framework: net10.0+
NuGet Package ID: Marai.Cryptography
Introduction
Marai.Cryptography is a production-ready cryptography library for .NET providing AES-256 encryption across multiple modes, HMAC-SHA256 request signing, and secure PBKDF2 password hashing with a clean, consistent API.
Major capabilities:
- AES-256 encryption and decryption in GCM, CBC, CTR, CFB, and GCMFormatted modes
- SHA-256 hashing of arbitrary text
- Key and IV generation for AES-256
- AES keys, RSA public/private key pairs, AES and legacy TDES DUKPT BDKs, and random password generation
- HMAC-SHA256 request signature creation and validation with replay-attack protection
- Secure PBKDF2/SHA-256 password hashing with randomized salt and iteration count
- Constant-time comparison for signature and password verification
- Microsoft Dependency Injection integration
Table of Contents
- Installation
- Getting Started
- AES Provider
- HMAC Signature Provider
- Password Provider
- Key Generator Provider
- Models Reference
- Exceptions Reference
- Security Notes
- Full API Reference
- Recent Changes
- Breaking Changes and Migration
Installation
Getting Started
Register with Dependency Injection
AddMaraiCryptography registers:
ISecurityAESProvider(singleton) — encryption and hashingISecurityHMACSignatureProvider(singleton) — HMAC request signingISecurityPasswordProvider(singleton) — password hashingISecurityKeyGeneratorProvider(singleton) — key and password generation; no configured key or IV required
Generate a Key and IV
AES Provider
Encryption Modes
| Value | Name | Description | Recommended |
|---|---|---|---|
GCMFormatted |
AES-256-GCM with header | GCM with magic-byte prefix for format detection. Layout: [GCM(3)][nonce(12)][tag(16)][ciphertext] |
Yes — default |
GCM |
AES-256-GCM raw | Authenticated GCM without format header. Layout: [nonce(12)][tag(16)][ciphertext] |
Yes |
CBC |
AES-256-CBC | Block cipher with PKCS7 padding. Layout: [iv(16)][ciphertext] |
Acceptable |
CTR |
AES-256-CTR | Stream cipher mode. Layout: [counter(16)][ciphertext] |
Acceptable |
CFB |
AES-256-CFB | Cipher Feedback mode (CFB-128). Layout: [iv(16)][ciphertext] |
Acceptable |
ECB |
AES-256-ECB | No IV. Identical plaintext blocks produce identical ciphertext. Deprecated. | No |
ECBis marked[Obsolete]in the library. Do not use it for any data where block-level patterns could be revealing.
Default Encrypt and Decrypt
EncryptGcm and DecryptGcm use the key and IV passed to AddMaraiCryptography.
Explicit Mode Encrypt and Decrypt
Keys and IVs are passed as strings. The library derives a fixed-length byte array via SHA-256. Use GenerateAes256KeyAndIv() to produce a proper random key.
SHA-256 Hash
Key and IV Generation
HMAC Signature Provider
Creating a Signature
The payload must be valid JSON. The library wraps it with the current UTC Unix timestamp before signing:
Validating a Signature
ValidateSignature steps:
- Recomputes the expected HMAC using the payload and timestamp.
- Compares using constant-time comparison (
CryptographicOperations.FixedTimeEquals). - Validates the timestamp is within the allowed clock skew and expiration window.
Default timing windows: AllowedClockSkewInMinutes = 5, AllowedExpirationInMinutes = 5.
Password Provider
Hashing a Password
Validating a Password
Key Generator Provider
SecurityKeyGeneratorProvider in Marai.Cryptography.Implementations implements ISecurityKeyGeneratorProvider in Marai.Cryptography.Abstractions. It generates fresh software key material and passwords without retaining them as instance state.
| Method | Default / accepted input | Output |
|---|---|---|
GenerateAesKey(keySizeInBits) | 256 bits; 128, 192, or 256 | Base64 encoding of 16, 24, or 32 raw key bytes |
GenerateRsaKeyPair(keySizeInBits) | 3072 bits; 2048, 3072, or 4096 | Matching (PublicKeyPem, PrivateKeyPem) tuple |
GenerateAesBdk(keySizeInBits) | 256 bits; 128, 192, or 256 | 32, 48, or 64 uppercase hex characters |
GenerateBdk() | Legacy two-key TDES; obsolete warning | 16 bytes as 32 uppercase hex characters, with odd parity and weak-key rejection |
GeneratePassword(length) | 24 characters; 15–1024 | Random password without character-class requirements |
GeneratePciPassword(length) | 24 characters; 15–1024 | Random password guaranteed to contain both letters and digits |
Unsupported sizes and lengths throw ArgumentOutOfRangeException. Cryptographic provider failures propagate; no weaker random-source fallback is used.
Dependency Injection
Applications already calling AddMaraiCryptography() can inject ISecurityKeyGeneratorProvider into consuming classes. This registration adds no new runtime package dependency.
How Generation Works
- AES and AES BDK:
RandomNumberGenerator.GetBytes()supplies random key bytes. The output encodings differ; no password derivation is involved. - RSA:
RSA.Create(keySizeInBits)generates one matching pair through the platform provider. The public output is SubjectPublicKeyInfo PEM (PUBLIC KEY); the private output is unencrypted PKCS#8 PEM (PRIVATE KEY). Import withRSA.ImportFromPem(). The RSA instance is disposed after export. - TDES: random bytes are adjusted to odd DES parity. Generation retries for degenerate TDES keys or weak/semi-weak DES components. The 16-byte representation includes parity bits and does not represent 128 bits of security.
- Passwords:
RandomNumberGenerator.GetInt32()selects characters without modulo bias from uppercase/lowercase ASCII letters, digits, and!@#$%^&*()-_=+[]{}:,.?. The PCI variant retries complete candidates until letters and digits are both present. Neither method guarantees all four character classes. - Memory: temporary symmetric key/component buffers are zeroed and password character buffers are cleared. Returned strings cannot be explicitly wiped and must not be logged.
Legacy TDES Support
GenerateBdk() is enabled. Both interface and implementation use [Obsolete(..., false)]; the method no longer intentionally throws NotSupportedException. Builds treating warnings as errors may still reject calls. Use AES BDKs for new AES DUKPT integrations, but migrate the receiving system first: TDES and AES key formats are not interchangeable.
Key Formats and Compatibility
Decode GenerateAesKey() with Convert.FromBase64String() when supplying raw bytes to .NET AES APIs. The existing SecurityAESProvider hashes its string key input, so passing Base64 to that provider produces a different effective key from using the decoded bytes directly. This behavior and GenerateAes256KeyAndIv() are unchanged. The new generator does not manage per-message IVs/nonces, rotate stored keys, or derive DUKPT initial/transaction keys or HSM key blocks.
Standards Basis and Deployment Limits
The implementation review referenced NIST SP 800-133 Rev. 2 for key generation, SP 800-131A Rev. 2 for algorithm/key-length choices, SP 800-63B-4 for password guidance, and PCI DSS v4.0.1 requirements 3.7.1 and 8.3.6. NIST’s verifier composition guidance and PCI’s defined password requirements differ, hence the separate password generators. Legacy TDES support does not reverse NIST’s withdrawal of TDEA approval for new protection.
This library does not establish FIPS validation or PCI compliance. Verify the deployed cryptographic module and its approved configuration where required. Production PCI PIN/DUKPT BDKs need an appropriate approved HSM/secure cryptographic device workflow; both BDK methods here export plaintext into application memory. Secure storage, distribution, rotation, access control, and applicable dual control/split knowledge remain deployment responsibilities. Password generation does not implement hashing, blocklists, or rate limiting. Existing encryption and password hashing were not certified by this generator review.
Models Reference
EncryptionFormats
HmacSecretKey
| Member | Type | Description |
|---|---|---|
Base64 |
string |
Base64-encoded HMAC secret key bytes |
ToBytes() |
byte[] |
Decodes the key to a raw byte array; throws if blank |
HmacSignedRequest
| Member | Type | Description |
|---|---|---|
Payload |
string |
The original JSON request payload |
Signature |
string |
Base64-encoded HMAC-SHA256 signature to validate |
TimeStamp |
UnixTimeSeconds |
Unix timestamp when the signature was created |
SecretKey |
HmacSecretKey |
The shared secret key |
allowedClockSkewInMinutes |
int |
Clock skew tolerance (default: 0, uses config value of 5) |
allowedExpirationInMinutes |
int |
Max request age in minutes (default: 0, uses config value of 5) |
PasswordHash
| Member | Type | Description |
|---|---|---|
HashBase64 |
string |
Base64-encoded PBKDF2 hash output |
SaltBase64 |
string |
Base64-encoded random salt |
Iterations |
int |
PBKDF2 iteration count used when hashing |
UnixTimeSeconds
| Member | Type | Description |
|---|---|---|
Value |
long |
Unix timestamp in seconds |
Now() |
UnixTimeSeconds (static) |
Returns current UTC time as UnixTimeSeconds |
ToDateTimeOffset() |
DateTimeOffset |
Converts to UTC DateTimeOffset |
Exceptions Reference
| Exception | Thrown When |
|---|---|
InvalidSignatureException |
HMAC signature does not match |
ExpiredSignatureException |
Request timestamp is outside the allowed window |
InvalidParameterException |
A required parameter has an invalid value |
ParameterNotFoundException |
A required parameter is missing |
UnknownErrorException |
An unexpected error occurs |
Security Notes
Recommended Modes
- AES-256-GCM / GCMFormatted — Use for all new encryption. GCM provides authenticated encryption, detecting tampering automatically.
- AES-256-CBC / CFB / CTR — Acceptable for interoperability. No built-in authentication; combine with a separate MAC if tamper detection is needed.
- AES-256-ECB — Do not use. Marked
[Obsolete]in the library.
Key and IV Management
- Never hardcode keys in source code. Store them in environment variables, Azure Key Vault, AWS Secrets Manager, or similar.
- Use
GenerateAes256KeyAndIv()to produce cryptographically secure random keys and IVs.
Signature Security
- Uses
CryptographicOperations.FixedTimeEqualsto prevent timing side-channels. - The 5-minute expiration window blocks replay attacks. Tune
allowedExpirationInMinutesas needed. - The secret key should be at least 256 bits (32 bytes) of random data.
Password Hashing
- Uses PBKDF2 with SHA-256, a random 16-byte salt, and a random iteration count between 5,000 and 10,000.
- Password comparison uses constant-time comparison to prevent timing attacks.
Full API Reference
Key Generator API
License
This project is licensed under the Marai Proprietary Software License Agreement.
Free for personal and commercial use.
For the complete license agreement and terms, please visit: https://marai.dev/proprietary-software-license-agreement
Recent Changes — September 12, 2026
- Added
SecurityKeyGeneratorProvider, its interface, singleton DI registration, and six generation methods for AES, RSA, AES/TDES BDKs, and passwords. - Kept AES-256 and RSA-3072 defaults; documented supported sizes and output formats.
- Restored legacy TDES generation after its temporary disabling. It now generates keys with an obsolete compiler warning.
- Added
GeneratePciPassword()and clarified password-generation policies and deployment limits. - Updated README and this guide with examples, implementation details, and compatibility notes.
Breaking Changes and Migration
The following changes affect callers of the earlier key-generator implementation.
| Change | Impact | Developer action |
|---|---|---|
| Password minimum increased from 12 to 15 | GeneratePassword(12) through GeneratePassword(14) now throw ArgumentOutOfRangeException. Both generators accept 15–1024. | Use at least 15 characters or keep the 24-character default. This does not change validation of stored password hashes. |
| Default composition guarantee removed | GeneratePassword() no longer guarantees uppercase, lowercase, digits, and symbols in every result. | Remove assumptions about character classes. Use GeneratePciPassword() for guaranteed letters and digits; it does not guarantee all four classes. |
| TDES marked obsolete on both API declarations | Calls emit CS0618; warnings-as-errors builds may fail. | Plan migration to AES DUKPT. For an intentional legacy integration, handle the warning according to project policy. Do not substitute AES keys into a TDES system. |
| TDES generation restored | The earlier intentional NotSupportedException is removed; callers now receive a generated BDK. | Remove assumptions that the legacy entry point is disabled. Ordinary platform failures can still propagate. |
| Interface gained generation members | Custom implementations of the earlier ISecurityKeyGeneratorProvider contract must implement added members, including GeneratePciPassword(). | Update custom providers, fakes, and mocks when adopting the current interface. |
Existing AES encryption, HMAC signing, password hashing, stored data formats, and GenerateAes256KeyAndIv() remain unchanged by the generator update. No automatic key rotation or data migration is performed.
Verification
The regression console checks DI resolution, defaults and accepted key sizes, AES/RSA round trips, RSA signature verification, password bounds and PCI output rules, TDES parity/weak-key rejection and round trips, and warning-only obsolete attributes. Repeated-output checks detect accidental constant output; they do not certify randomness or compliance.



