Skip to content

Commit

Permalink
Dev (#22)
Browse files Browse the repository at this point in the history
* Changed PQ automatic configuration to use the implemented algorithms as default, moving the classical non-PQ algorithms as counter algorithms, or check the hybrid algorithms in strict mode, too
+ Added `RandomDataProvider`
+ Added `Extensions` which contains methods for getting/restoring a `VmpcRandomGenerator` internal state
+ Added `ChaCha20Rng`
+ Added `CipherRng`
+ Added `XSalsa20Rng`
+ Added `BouncyCastleRngWrapper` to merge the `wan24-Crypto` and Bouncy Castle RNG APIs by wrapping Bouncy Castle's `IRandomGenerator` with `ISeedableRng`
+ Added `DisposableRngWrapper`
+ Added `IBouncyCastleRng`
+ Added NTRUEncrypt asymmetric algorithm (but disabled 'cause of a bug in the Bouncy Castle library)
+ `BouncyCastleRandomGenerator` does forward seed to `RND` now
- Fixed asymmetric key disposing
  • Loading branch information
nd1012 authored Oct 15, 2023
1 parent 8ee2008 commit e4e4d0c
Show file tree
Hide file tree
Showing 25 changed files with 1,353 additions and 31 deletions.
84 changes: 76 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ the `wan24-Crypto` library with these algorithms:
| CRYSTALS-Dilithium | 3 | CRYSTALSDILITHIUM |
| FALCON | 4 | FALCON |
| SPHINCS+ | 5 | SPHINCSPLUS |
| FrodoKEM | 6 | FRODOKEM |
| FrodoKEM* | 6 | FRODOKEM |
| NTRUEncrypt* | 7 | NTRUENCRYPT |
| **Symmetric** | | |
| ChaCha20 | 1 | CHACHA20 |
| XSalsa20 | 2 | XSALSA20 |
Expand All @@ -30,8 +31,13 @@ the `wan24-Crypto` library with these algorithms:
| HMAC-SHA3-384 | 5 | HMAC-SHA3-384 |
| HMAC-SHA3-512 | 6 | HMAC-SHA3-512 |

**NOTE**: FrodoKEM is currently disabled, 'cause there seems to be a bug
(missing code) in the Bouncy Castle library for FrodoKEM.
**NOTE**: FrodoKEM and NTRUEncrypt are currently disabled, 'cause there seems
to be a bug (missing code) in the Bouncy Castle library for
exporting/importing private keys (at last).

NTRUSign is currently not implemented, 'cause it'd require the using code to
be GPL licensed. This algorithm may be included in a separate package which is
licensed using the GPL license (to avoid misunderstandings) in the future.

## How to get it

Expand Down Expand Up @@ -81,16 +87,15 @@ These algorithms are designed for post quantum cryptography:
- SPHINCS+ (signature)
- FrodoKEM (key exchange)

Normally you want to use them in hybrid mode as counter algorithm for
extending a default algorithm of the `wan24-Crypto` package. To do this per
default:
Normally you want to use them in hybrid mode and use classical algorithms of
the `wan24-Crypto` package as counter algorithm. To do this per default:

```cs
// Enable the post quantum algorithms as counter-defaults
// Enable the post quantum algorithms as (counter-)defaults
CryptoHelper.ForcePostQuantumSafety();
```

This will use these algorithms as counter algorithms for asymmetric
This will use these algorithms as (counter) algorithms for asymmetric
cryptography, in case you didn't define other post quantum algorithms already:

- CRYSTALS-Kyber (key exchange)
Expand Down Expand Up @@ -141,3 +146,66 @@ SignatureContainer signature = dataToSign.Sign(yourNormalPrivateKey, options: op
For CRYSTALS-Kyber and CRYSTALS-Dilithium the AES parameters are being used.
When using SPHINCS+, the Haraka F hashing parameters will be used. For
FrodoKEM the AES parameters will be used.

## Random data provider

The `RandomDataProvider` is a `RandomDataGenerator` which provides added seed
data to `OnSeed(Async)` attached event handlers. It uses the `ChaCha20Rng` in
combination with `RND` of `wan24-Crypto` to produce cryptographic secure
random data (CSRNG). An instance may be set as `RND.Generator` singleton
random data generator for all consumers (like key generators etc.).

`RandomDataProvider` can be customized by extending the type. Pregnant methods
are virtual and can be overridden. Since the type is a `HostedServiceBase`, it
can be used in modern .NET app environments. And since it implements the
`IRandomGenerator` interface of Bouncy Castle, it can be used as secure random
data source for all Bouncy Castle algorithms (like key generators) also.

By calling the `CreateFork(Async)` method, you can create an attached
instance, which will be initialized with a random seed generated by the parent
instance and consumes the provided seeds from the parent automatically.

**NOTE**: Don't forget to dispose an unused `RandomDataProvider` instance!

**CAUTION**: There is a patent (US10402172B1) which comes into play, if you
plan to create a Random or Entropy as a Service (R/EaaS) application,
especially when using QRNG entropy. Read that document carefully to avoid
disappointments.

## Stream cipher RNG

The `StreamCipherRng` uses any stream cipher to encrypt the generated random
bytes of an underlaying PRNG using a random key. The result is a CSRNG. These
stream ciphers are available with `wan24-Crypto-BC`, but you could use any
other stream cipher (but not AEAD implementations!) also:

- ChaCha20 - `ChaCha20Rng`
- XSalsa20 - `XSalsa20Rng`

If you didn't specify an underlaying PRNG, Bouncy Castle's
`VmpcRandomGenerator` will be used and seeded using 256 bytes from `RND`.

The final CSRNG implements `IRandomGenerator` for use with Bouncy Castle, and
also `ISeedableRng` for use with `RND` (as seed consumer, for example).

**NOTE**: A `StreamCipherRng` needs to be disposed after use!

You can use the resulting CSRNG as default RNG for `RND`:

```cs
ChaCha20Rng csrng = new();

// Enable automatic seeding
RND.SeedConsumer = csrng;

// Use as default CSRNG
RND.FillBytes = csrng.GetBytes;
RND.FillBytesAsync = csrng.GetBytesAsync;
```

**NOTE**: When setting the `RND.FillBytes(Async)` callbacks, they may not be
used, if `/dev/urandom` was preferred. To disable `/dev/urandom`, set
`RND.UseDevUrandom` and `RND.RequireDevUrandom` to `false` also.

**NOTE**: Currently only stream ciphers are supported, because the cipher RNG
implementation doesn't buffer pre-generated random data.
2 changes: 1 addition & 1 deletion src/wan24-Crypto-BC Tests/wan24-Crypto-BC Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="wan24-Crypto-Shared-Tests" Version="1.12.1" />
<PackageReference Include="wan24-Crypto-Shared-Tests" Version="1.13.0" />
</ItemGroup>

<ItemGroup>
Expand Down
15 changes: 15 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricDilithiumPrivateKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ protected override void Dispose(bool disposing)
privateKey.Tr.Clear();
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys == null) return;
DilithiumPrivateKeyParameters privateKey = (DilithiumPrivateKeyParameters)Keys.Private;
privateKey.K.Clear();
privateKey.Rho.Clear();
privateKey.S1.Clear();
privateKey.S2.Clear();
privateKey.T0.Clear();
privateKey.T1.Clear();
privateKey.Tr.Clear();
}

/// <summary>
/// Cast to public key
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricFalconPrivateKey.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pqc.Crypto.Falcon;
using wan24.Core;

namespace wan24.Crypto.BC
{
Expand Down Expand Up @@ -41,6 +42,14 @@ protected override void Dispose(bool disposing)
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys == null) return;
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <summary>
/// Cast to public key
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricFrodoKemPrivateKey.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pqc.Crypto.Frodo;
using wan24.Core;

namespace wan24.Crypto.BC
{
Expand Down Expand Up @@ -42,6 +43,14 @@ protected override void Dispose(bool disposing)
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys == null) return;
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <summary>
/// Cast to public key
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricKyberPrivateKey.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
using wan24.Core;

namespace wan24.Crypto.BC
{
Expand Down Expand Up @@ -42,6 +43,14 @@ protected override void Dispose(bool disposing)
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys == null) return;
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <summary>
/// Cast to public key
/// </summary>
Expand Down
71 changes: 71 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricNtruEncryptAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Org.BouncyCastle.Pqc.Crypto.Ntru;
using System.Collections.ObjectModel;

namespace wan24.Crypto.BC
{
/// <summary>
/// NTRUEncrypt asymmetric algorithm
/// </summary>
public sealed record class AsymmetricNtruEncryptAlgorithm
: BouncyCastleAsymmetricAlgorithmBase<
AsymmetricNtruEncryptPublicKey,
AsymmetricNtruEncryptPrivateKey,
NtruKeyPairGenerator,
NtruKeyGenerationParameters,
NtruParameters,
NtruPublicKeyParameters,
NtruPrivateKeyParameters,
AsymmetricNtruEncryptAlgorithm
>
{
/// <summary>
/// Algorithm name
/// </summary>
public const string ALGORITHM_NAME = "NTRUENCRYPT";
/// <summary>
/// Algorithm value
/// </summary>
public const int ALGORITHM_VALUE = 7;
/// <summary>
/// Default key size in bits
/// </summary>
public const int DEFAULT_KEY_SIZE = 701;
/// <summary>
/// Algorithm usages
/// </summary>
public const AsymmetricAlgorithmUsages USAGES = AsymmetricAlgorithmUsages.KeyExchange;
/// <summary>
/// Display name
/// </summary>
public const string DISPLAY_NAME = "NTRUEncrypt";

/// <summary>
/// Allowed key sizes in bits
/// </summary>
private static readonly ReadOnlyCollection<int> _AllowedKeySizes;

/// <summary>
/// Static constructor
/// </summary>
static AsymmetricNtruEncryptAlgorithm() => _AllowedKeySizes = new List<int>()
{
509,
677,
701,
821
}.AsReadOnly();

/// <summary>
/// Constructor
/// </summary>
public AsymmetricNtruEncryptAlgorithm()
: base(ALGORITHM_NAME, ALGORITHM_VALUE, USAGES, isEllipticCurveAlgorithm: false, _AllowedKeySizes, isPostQuantum: true, DEFAULT_KEY_SIZE)
{ }

/// <inheritdoc/>
public override string DisplayName => DISPLAY_NAME;

/// <inheritdoc/>
protected override NtruParameters GetEngineParameters(CryptoOptions options) => AsymmetricNtruHelper.GetParameters(options.AsymmetricKeyBits);
}
}
66 changes: 66 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricNtruEncryptPrivateKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pqc.Crypto.Ntru;
using wan24.Core;

namespace wan24.Crypto.BC
{
/// <summary>
/// NTRUEncrypt asymmetric private key
/// </summary>
public sealed record class AsymmetricNtruEncryptPrivateKey
: BouncyCastleAsymmetricPrivateKeyExchangeKeyBase<
AsymmetricNtruEncryptPublicKey,
AsymmetricNtruEncryptAlgorithm,
NtruPublicKeyParameters,
NtruPrivateKeyParameters,
NtruKemGenerator,
NtruKemExtractor,
AsymmetricNtruEncryptPrivateKey
>
{
/// <summary>
/// Constructor
/// </summary>
public AsymmetricNtruEncryptPrivateKey() : base(AsymmetricNtruEncryptAlgorithm.ALGORITHM_NAME) { }

/// <summary>
/// Constructor
/// </summary>
/// <param name="keyData">Key data</param>
public AsymmetricNtruEncryptPrivateKey(byte[] keyData) : base(AsymmetricNtruEncryptAlgorithm.ALGORITHM_NAME, keyData) { }

/// <summary>
/// Constructor
/// </summary>
/// <param name="keys">Keys</param>
public AsymmetricNtruEncryptPrivateKey(AsymmetricCipherKeyPair keys) : base(AsymmetricNtruEncryptAlgorithm.ALGORITHM_NAME, keys) { }

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (Keys == null) return;
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys == null) return;
Keys.Private.ClearPrivateByteArrayFields();//TODO All parameter fields are private :(
}

/// <summary>
/// Cast to public key
/// </summary>
/// <param name="privateKey">Private key</param>
public static implicit operator AsymmetricNtruEncryptPublicKey(AsymmetricNtruEncryptPrivateKey privateKey) => privateKey.PublicKey;

/// <summary>
/// Cast from serialized data
/// </summary>
/// <param name="data">Data</param>
public static explicit operator AsymmetricNtruEncryptPrivateKey(byte[] data) => Import<AsymmetricNtruEncryptPrivateKey>(data);
}
}
Loading

0 comments on commit e4e4d0c

Please sign in to comment.