wan24-Crypto
1.15.0
See the version list below for details.
dotnet add package wan24-Crypto --version 1.15.0
NuGet\Install-Package wan24-Crypto -Version 1.15.0
<PackageReference Include="wan24-Crypto" Version="1.15.0" />
paket add wan24-Crypto --version 1.15.0
#r "nuget: wan24-Crypto, 1.15.0"
// Install wan24-Crypto as a Cake Addin #addin nuget:?package=wan24-Crypto&version=1.15.0 // Install wan24-Crypto as a Cake Tool #tool nuget:?package=wan24-Crypto&version=1.15.0
wan24-Crypto
This library exports a generic high level crypto API, which allows to use an implemented cryptographic algorithm to be applied using a simple interface.
Per default these cryptographic algorithms are implemented:
Usage | Algorithm |
---|---|
Hashing | MD5 |
SHA-1 | |
SHA-256 | |
SHA-384 | |
SHA-512 | |
MAC | HMAC-SHA-1 |
HMAC-SHA-256 | |
HMAC-SHA-384 | |
HMAC-SHA-512 | |
Symmetric encryption | AES-256-CBC (ISO10126 padding) |
Asymmetric keys | Elliptic Curve Diffie Hellman |
Elliptic Curve DSA (RFC 3279 signatures) | |
KDF key stretching | PBKDF#2 (20,000 iterations per default) |
These elliptic curves are supported at present:
- secp256r1
- secp384r1
- secp521r1
The number of algorithms can be extended easy, a bunch of additional libraries implementing more algorithms (and probably more elliptic curves) will follow soon.
The goals of this library are:
- Make a choice being a less torture
- Make a complex thing as easy as possible
Implementing (new) cryptographic algorithms into (existing) code can be
challenging. wan24-Crypto
tries to make it as easy as possible, while the
API is still complex due to the huge number of options it offers. Please see
the Wiki for examples of the
most common use cases, which cover:
- Simple encryption using a password
- Advanced encryption using a private PFS key
- Advanced encryption using a private PFS key and hybrid key exchange
- Advanced encryption using a peers public key
- Advanced encryption using a peers public key and hybrid key exchange
For more examples please open an issue - I'd be glad to help! If you've found a security issue, please report it private.
NOTE: The cipher output of this library may include a header, which can't (yet) be interpreted by any third party vendor code (which is true especially if the raw data was compressed before encryption, which is the default). That means, a cipher output of this library can't be decrypted with a third party crypto library, even this library implements standard cryptographic algorithms.
Using this library for a cipher which has to be exchanged with a third party application, which relies on working with standard crypto algorithm output, is not recommended - it may not work!
Anyway, this library should be a good choice for isolated use within your application(s), if want to avoid a hussle with implementing newer crypto algorithms.
How to get it
This library is available as NuGet package.
These extension NuGet packages are available:
Usage
Hashing
byte[] hash = rawData.Hash();
The default hash algorithm ist SHA512.
MAC
byte[] mac = rawData.Mac(password);
The default MAC algorithm is HMAC-SHA512.
KDF (key stretching)
(byte[] stretchedPassword, byte[] salt) = password.Stretch(len: 64);
The default KDF algorithm is PBKDF#2, using 20,000 iterations.
Encryption
byte[] cipher = raw.Encrypt(password);
byte[] raw = cipher.Decrypt(password);
There are extension methods for memory and streams.
The default algorithms used:
Usage | Algorithm |
---|---|
Symmetric encryption | AES-256-CBC (HMAC secured and Brotli compressed) |
HMAC | HMAC-SHA512 |
KDF | PBKDF#2 |
Asymmetric key exchange and digital signature | Diffie Hellman secp521r1 |
Using asymmetric keys for encryption
This way you encrypt using a stored private key (which will be required for decryption later):
using IAsymmetricPrivateKey privateKey = AsymmetricHelper.CreateKeyExchangeKeyPair();
byte[] cipher = raw.Encrypt(privateKey);
byte[] raw = cipher.Decrypt(privateKey);
In case you want to encrypt for a peer using the peers asymmetric public key for performing a PFS key exchange:
// Peer creates a key pair (PFS or stored) and sends peerPublicKeyData to the provider
using IAsymmetricPrivateKey peerPrivateKey = AsymmetricHelper.CreateKeyExchangeKeyPair();
byte[] peerPublicKeyData = (byte[])peerPrivateKey.PublicKey;// Needs to be available at the provider
// Encryption at the provider (pfsKey shouldn't be stored and can be a new key for every cipher message)
using IAsymmetricPublicKey peerPublicKey = AsymmetricKeyBase.Import<IAsymmetricPublicKey>(peerPublicKeyData);// Deserialize the peers public key of any format
CryptoOptions options = EncryptionHelper.GetDefaultOptions();// Add the asymmetric key information for key pair creation
options.AsymmetricAlgorithm = peerPublicKey.Algorithm.Name;
options.AsymmetricKeyBits = peerPublicKey.Bits;
options.PublicKey = peerPublicKey;// Required for encrypting especially for the one specific peer
byte[] cipher;
using(IKeyExchangePrivateKey pfsKey = AsymmetricHelper.CreateKeyExchangeKeyPair(options))
cipher = raw.Encrypt(pfsKey, options);// Only the peer can decrypt the cipher after pfsKey was disposed
// Decryption at the peer
byte[] raw = cipher.Decrypt(peerPrivateKey, options);
Time critical decryption
It's possible to define a maximum age for cipher data, which can't be decrypted after expired:
// Encryption
CryptoOptions options = new()
{
TimeIncluded = true
};
byte[] cipher = raw.Encrypt(password, options);
// Decryption (required to be decrypted within 10 seconds, or the decryption will fail)
options = new()
{
RequireTime = true,
MaximumAge = TimeSpan.FromSeconds(10)
}
byte[] raw = cipher.Decrypt(password, options);
By defining CryptoOptions.MaximumTimeOffset
you may define a time tolerance
which is being used to be tolerant with peers having a slightly different
system time.
Asymmetric keys
Key exchange
PFS example:
// A: Create a key pair
using IKeyExchangePrivateKey privateKeyA = AsymmetricHelper.CreateKeyExchangeKeyPair();
byte[] publicKeyData = (byte[])privateKeyA.PublicKey;// Needs to be available at B
// B: Create a key pair, key exchange data and derive the shared key
using IAsymmetricPublicKey publicKeyA = AsymmetricKeyBase.Import<IAsymmetricPublicKey>(publicKeyData);// Deserialize the peers public key of any format
using IKeyExchangePrivateKey privateKeyB = AsymmetricHelper.CreateKeyExchangeKeyPair(new()
{
AsymmetricAlgorithm = publicKeyA.Algorithm.Name,
AsymmetricKeyBits = publicKeyA.Bits
});
(byte[] keyB, byte[] keyExchangeData) = privateKeyB.GetKeyExchangeData(publicKey);// Needs to be available at A
// A: Derive the exchanged key
byte[] keyA = privateKeyA.DeriveKey(keyExchangeData);
Assert.IsTrue(keyA.SequenceEquals(keyB));
The default key exchange algorithm is ECDH from a secp521r1 elliptic curve.
Digital signature
// Create a key pair for signature
using ISignaturePrivateKey privateKey = AsymmetricHelper.CreateSignatureKeyPair();
// Sign data
SignatureContainer signature = privateKey.SignData(anyData);
// Validate a signature
privateKey.PublicKey.ValidateSignature(signature, anyData);
The default signature algorithm is DSA from a secp521r1 elliptic curve.
Too many options?
The CryptoOptions
contains a huge collection of properties, which follow a
simple pattern in case of en-/decryption: Which information should be included
in the cipher header, and is an information in the header required? Because
the options include information for all sections, there are single values
which belongs to the specific section only. If you separate the options into
sections, it's easy to overview:
Section | Property | Description | Default value |
---|---|---|---|
Encryption | Algorithm |
Encryption algorithm name | null (AES256CBC ) |
FlagsIncluded |
Are the flags included in the header? | true |
|
RequireFlags |
Are the flags required to be included in the header? | true |
|
MAC | MacAlgorithm |
MAC algorithm name | null (HMAC-SHA512 ) |
MacIncluded |
Include a MAC in the header | true |
|
RequireMac |
Is the MAC required in the header? | true |
|
CounterMacAlgorithm |
Counter MAC algorithm name | null |
|
CounterMacIncluded |
Include a counter MAC in the header | false |
|
RequireCounterMac |
Is the counter MAC required in the header? | false |
|
ForceMacCoverWhole |
Force the MAC to cover all data | false |
|
RequireMacCoverWhole |
Is the MAC required to cover all data? | false |
|
Encryption / Key creation / Signature | AsymmetricAlgorithm |
Asymmetric algorithm name | null (ECDH for encryption, ECDSA for signature) |
AsymmetricCounterAlgorithm |
Asymmetric counter algorithm name | null |
|
KeyExchangeData |
Key exchange data (includes counter key exchange data; generated automatic) | null |
|
RequireKeyExchangeData |
Is the key exchange data required in the header? | false |
|
PrivateKey |
Private key for key exchange | null |
|
CounterPrivateKey |
Private key for counter key exchange (required when using a counter asymmetric algorithm) | null |
|
PublicKey |
Public key for key exchange (if not using a PFS key) | null |
|
CounterPublicKey |
Public key for counter key exchange (required when using a counter asymmetric algorithm and not using a PFS key) | null |
|
KDF | KdfAlgorithm |
KDF algorithm name | null (PBKDF2 ) |
KdfIterations |
KDF iteration count | 1 |
|
KdfSalt |
KDF salt (generated automatic) | null |
|
KdfAlgorithmIncluded |
Include the KDF information in the header | true |
|
RequireKdfAlgorithm |
Is the KDF information required in the header? | true |
|
CounterKdfAlgorithm |
Counter KDF algorithm name | null |
|
CounterKdfIterations |
Counter KDF iteration count | 1 |
|
CounterKdfSalt |
Counter KDF salt (generated automatic) | null |
|
CounterKdfAlgorithmIncluded |
Include the counter KDF information in the header | false |
|
RequireCounterKdfAlgorithm |
Is the counter KDF information required in the header? | false |
|
Payload | PayloadData |
Plain payload | null |
PayloadIncluded |
Is the payload object data included in the header? | false |
|
RequirePayload |
Is payload object data required in the header? | false |
|
Serializer version | SerializerVersion |
Serializer version number (set automatic) | null |
SerializerVersionIncluded |
Include the serializer version number in the header | true |
|
RequireSerializerVersion |
Is the serializer version number required in the header? | true |
|
Header version | HeaderVersion |
Header version number (set automatic) | 1 |
HeaderVersionIncluded |
Is the header version included in the header? | true |
|
RequireHeaderVersion |
Is the header version required in the header? | true |
|
Encryption time | Time |
Encryption timestamp (UTC) | null |
TimeIncluded |
Is the encryption time included in the header? | false |
|
RequireTime |
Is the encryption time required to be included in the header? | false |
|
MaximumAge |
Maximum age of cipher data (the default can be set to DefaultMaximumAge ) |
null |
|
MaximumTimeOffset |
Maximum time offset for a peer with a different system time (the default can be set to DefaultMaximumTimeOffset ) |
null |
|
Compression | Compressed |
Should the raw data be compressed before encryption? | true |
Compression |
The CompressionOptions instance to use (will be set automatic, if not given) |
null |
|
Hashing / Signature | HashAlgorithm |
The name of the hash algorithm to use | null (SHA512 ) |
Key creation | AsymmetricKeyBits |
Key size in bits to use for creating a new asymmetric key pair | 1 |
Stream options | LeaveOpen |
Leave the processing stream open after operation? | false |
Other options, which are not listed here, are used internal only.
If you use a new instance of CryptoOptions
, all defaults will be applied.
You can override these defaults in the static *Helper.Default*
properties,
or by setting other values in the CryptoOptions
instance, which you use when
calling any method.
For encryption these sections matter:
- Encryption
- MAC
- PFS
- KDF
- Payload
- Serializer version
- Header version
- Encryption time
- Compression
- Stream options
In case you want to use the *Counter*
options, you'll need to set the
CounterPrivateKey
value.
For MAC these sections matter:
- MAC
- Stream options
For hashing these sections matter:
- Hashing
- Stream options
For asymmetric key creation the "Key creation" section matters.
For signature these sections matter:
- Signature
- Hashing
- Stream options
Crypto suite
You can use a CryptoOptions
instance as crypto suite. The type can be binary
serialized (using the Stream-Serializer-Extensions
) for storing/restoring
to/from anywhere.
NOTE: Only crypto suite relevant information will be serialized! This excludes:
SerializerVersion
HeaderVersion
PrivateKey
(needs to be stored in another place)CounterPrivateKey
(needs to be stored in another place)PublicKey
CounterPublicKey
KeyExchangeData
PayloadData
Time
LeaveOpen
MacPosition
Mac
HeaderProcessed
Password
PKI
Using the AsymmetricSignedPublicKey
type, you can implement a simple PKI,
which allows to
- define trusted root keys
- define a key revocation list
- sign public keys
- validate signed public keys until the root signer key
// Create the root key pair
using ISignaturePrivateKey privateRootKey = AsymmetricHelper.CreateSignatureKeyPair();
// Self-sign the public root key
using AsymmetricSignedPublicKey signedPublicRootKey = new(privateRootKey.PublicKey);
signedPublicRootKey.Sign(privateRootKey);
// Create a key pair, which will be signed, and a signing request
using ISignaturePrivateKey privateKey = AsymmetricHelper.CreateSignatureKeyPair();
using AsymmetricPublicKeySigningRequest signingRequest = new(privateKey.PublicKey);
// Sign the public key
using AsymmetricSignedPublicKey signedPublicKey = signingRequest.GetAsUnsignedKey();
signedPublicKey.Sign(privateRootKey);
// Setup the PKI (minimal setup for signed public key validation)
AsymmetricSignedPublicKey.RootTrust =
// Normally you would have a DBMS which stores the trusted public key IDs
(id) => id.SequenceEqual(privateRootKey.ID);
AsymmetricSignedPublicKey.SignedPublicKeyStore = (id) =>
{
// Normally you would have a DBMS which stores the known keys
if(id.SequenceEqual(privateRootKey.ID)) return signedPublicRootKey;
if(id.SequenceEqual(privateKey.ID)) return signedPublicKey;
return null;
};
// Normally you would have a DBMS which stores a revocation list for AsymmetricSignedPublicKey.SignedPublicKeyRevocation
// Validate the signed public key
signedPublicKey.Validate();
As you can see, it's a really simple PKI implementation. It's good for internal use, and if there won't be too many keys to manage.
Algorithm IDs
Internal each algorithm has an unique ID within a category:
- Asymmetric cryptography
- Symmetric cryptography
- Hashing
- MAC
- KDF
If you'd like to implement inofficial algorithms on your own, please use the ID bits 24-32 only to avoid possible collisions with official libraries! These are the official implementation IDs (not guaranteed to be complete):
Algorithm | ID | Library |
---|---|---|
Asymmetric cryptography | ||
ECDH | 0 | wan24-Crypto |
ECDSA | 1 | wan24-Crypto |
CRYSTALS-Kyber | 2 | wan24-Crypto-BC |
CRYSTALS-Dilithium | 3 | wan24-Crypto-BC |
FALCON | 4 | wan24-Crypto-BC |
SPHINCS+ | 5 | wan24-Crypto-BC |
FrodoKEM | 6 | wan24-Crypto-BC |
Symmetric cryptography | ||
AES256CBC | 0 | wan24-Crypto |
CHACHA20 | 1 | wan24-Crypto-BC |
XSALSA20 | 2 | wan24-Crypto-BC |
AES256CM | 3 | wan24-Crypto-BC |
Hashing | ||
MD5 | 0 | wan24-Crypto |
SHA1 | 1 | wan24-Crypto |
SHA256 | 2 | wan24-Crypto |
SHA384 | 3 | wan24-Crypto |
SHA512 | 4 | wan24-Crypto |
MAC | ||
HMAC-SHA1 | 0 | wan24-Crypto |
HMAC-SHA256 | 1 | wan24-Crypto |
HMAC-SHA384 | 2 | wan24-Crypto |
HMAC-SHA512 | 3 | wan24-Crypto |
KDF | ||
PBKDF2 | 0 | wan24-Crypto |
Counter algorithms
A counter algorithm is being applied after the main algorithm. So the main algorithm result is secured by the counter algorithm result. You can use this in case you want to double security, for example when using post quantum algorithms, which may not be trustable at present.
The HybridAlgorithmHelper
allows to set default hybrid algorithms for
- key exchange in
KeyExchangeAlgorithm
- signature in
SignatureAlgorithm
- KDF in
KdfAlgorithm
- MAC in
MacAlgorithm
and exports some helper methods, which are being used internal (you don't need to use them unless you have to). If you want the additional hybrid algorithms to be used every time, you can set the
EncryptionHelper.UseHybridOptions
AsymmetricHelper.UseHybridKeyExchangeOptions
AsymmetricHelper.UseHybridSignatureOptions
to true
to extend used CryptoOptions
instances by the algorithms defined
in the HybridAlgorithmHelper
properties.
Post quantum safety
Some of the used cryptographic algorithms are quantum safe already, but
especially the asymmetric algorithms are not post quantum safe at all. If you
use an extension library which offers asymmetric post quantum safe algorithms
for key exchange and signature, you can enforce post quantum safety for all
used default algorithms by calling CryptoHelper.ForcePostQuantumSafety
. This
method will ensure that all used default algorithms are post quantum safe. In
case it's not possible to use post quantum algorithms for all defaults, this
method will throw an exception.
NOTE: AES-256 and SHA-384+ (and HMAC-SHA-384+) are considered to be post
quantum safe algorithms, while currently no post quantum-safe asymmetric
algorithms are implemented in this main library (wan24-Crypto-BC
does).
Disclaimer
wan24-Crypto
and provided sub-libraries are provided "as is", without any
warranty of any kind. Please read the license for the full disclaimer.
This library uses the available .NET cryptographic algorithms and doesn't implement any "selfmade" cryptographic algorithms. Extension libraries may add other well known third party cryptographic algorithm libraries, like Bouncy Castle.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Stream-Serializer-Extensions (>= 2.5.0)
- wan24-Compression (>= 1.13.0)
- wan24-Core (>= 1.25.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on wan24-Crypto:
Package | Downloads |
---|---|
wan24-Crypto-BC
Bouncy Castle adoption to wan24-Crypto |
|
wan24-Crypto-Shared-Tests
Shared tests for wan24-Crypto libraries |
|
wan24-Crypto-NaCl
NaCl adoption for wan24-Crypto |
|
wan24-Crypto-TPM
TPM crypto helper extension package for wan24-Crypto |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
2.20.0 | 193 | 10/27/2024 | |
2.19.0 | 173 | 9/21/2024 | |
2.18.0 | 125 | 9/9/2024 | |
2.17.0 | 385 | 8/16/2024 | |
2.16.1 | 200 | 7/13/2024 | |
2.16.0 | 141 | 7/6/2024 | |
2.15.0 | 125 | 6/29/2024 | |
2.14.0 | 161 | 6/22/2024 | |
2.13.0 | 293 | 6/16/2024 | |
2.12.0 | 132 | 5/20/2024 | |
2.11.0 | 82 | 5/11/2024 | |
2.10.0 | 119 | 4/28/2024 | |
2.9.1 | 108 | 4/21/2024 | |
2.9.0 | 127 | 4/20/2024 | |
2.8.1 | 125 | 4/14/2024 | |
2.8.0 | 161 | 4/13/2024 | |
2.7.0 | 170 | 3/9/2024 | |
2.6.0 | 187 | 3/2/2024 | |
2.5.0 | 193 | 2/24/2024 | |
2.4.0 | 173 | 2/17/2024 | |
2.3.0 | 122 | 2/17/2024 | |
2.2.0 | 122 | 2/14/2024 | |
2.1.1 | 152 | 2/11/2024 | |
2.1.0 | 162 | 2/10/2024 | |
2.0.0 | 180 | 1/20/2024 | |
1.26.1 | 254 | 11/11/2023 | |
1.26.0 | 160 | 11/1/2023 | |
1.25.0 | 175 | 10/29/2023 | |
1.24.0 | 197 | 10/21/2023 | |
1.23.0 | 244 | 10/15/2023 | |
1.22.0 | 226 | 10/8/2023 | |
1.20.1 | 200 | 10/1/2023 | |
1.20.0 | 132 | 10/1/2023 | |
1.19.0 | 218 | 9/19/2023 | |
1.18.0 | 169 | 9/16/2023 | |
1.17.0 | 193 | 9/10/2023 | |
1.16.0 | 191 | 9/3/2023 | |
1.15.1 | 179 | 7/30/2023 | |
1.15.0 | 163 | 7/30/2023 | |
1.14.0 | 224 | 7/22/2023 | |
1.13.0 | 254 | 6/8/2023 | |
1.12.0 | 233 | 6/3/2023 | |
1.11.0 | 161 | 5/29/2023 | |
1.10.0 | 174 | 5/27/2023 | |
1.8.0 | 192 | 5/20/2023 | |
1.7.0 | 217 | 5/11/2023 | |
1.6.0 | 301 | 5/7/2023 | |
1.5.0 | 258 | 5/1/2023 | |
1.4.0 | 306 | 4/30/2023 | |
1.3.0 | 233 | 4/29/2023 | |
1.2.2 | 245 | 4/28/2023 | |
1.2.1 | 268 | 4/28/2023 | |
1.2.0 | 343 | 4/26/2023 | |
1.1.0 | 205 | 4/25/2023 |