Skip to content

Commit

Permalink
Dev (#29)
Browse files Browse the repository at this point in the history
+ Added `ExportBc` and `ImportBc` methods and `IsBcImportExportImplemented` to asymmetric keys which support ex-/import using a key info object
+ Added constructor to asymmetric private keys which accepts a Bouncy Castle private key, if the public key can be generated from that private key
+ Added `BouncyCastleAsymmetricAlgorithmBase` which supports any key generator type
+ Added Streamlined NTRU Prime asymmetric PQC key exchange algorithm
+ Added BIKE asymmetric PQC key exchange algorithm
+ Added HQC asymmetric PQC key exchange algorithm
+ Added Picnic asymmetric PQC signature algorithm
- Fixed Falcon, FrodoKEM, CRYSTALS-Kyber, NTRUEncrypt and SPHINCS+ asymmetric public key `Bits` property
  • Loading branch information
nd1012 authored Feb 17, 2024
1 parent e27eb8b commit bfcc386
Show file tree
Hide file tree
Showing 69 changed files with 1,672 additions and 206 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/docfx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
dotnet-version: 8.0.x
- name: Setup docfx
run: dotnet tool update -g docfx
- name: Copy README
run: cp README.md "./src/wan24-Crypto-BC Docs/index.md"
- name: Build docs
run: docfx "./src/wan24-Crypto-BC Docs/docfx.json"
- name: Commit
Expand Down
91 changes: 58 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ the `wan24-Crypto` library with these algorithms:
| CRYSTALS-Dilithium | 3 | CRYSTALSDILITHIUM |
| FALCON | 4 | FALCON |
| SPHINCS+ | 5 | SPHINCSPLUS |
| FrodoKEM* | 6 | FRODOKEM |
| NTRUEncrypt* | 7 | NTRUENCRYPT |
| FrodoKEM | 6 | FRODOKEM |
| NTRUEncrypt | 7 | NTRUENCRYPT |
| Ed25519 | 8 | ED25519 |
| Ed448 | 9 | ED448 |
| X25519 | 10 | X25519 |
| X448 | 11 | X448 |
| XEd25519 | 12 | XED25519 |
| XEd448 | 13 | XED448 |
| Streamlined NTRU Prime | 14 | SNTRUP |
| BIKE | 15 | BIKE |
| HQC | 16 | HQC |
| Picnic | 17 | PICNIC |
| **Symmetric** | | |
| ChaCha20 | 1 | CHACHA20 |
| XSalsa20 | 2 | XSALSA20 |
Expand All @@ -29,14 +33,10 @@ the `wan24-Crypto` library with these algorithms:
| Twofish 256 CBC (ISO10126 padding) | 7 | TWOFISH256CBC |
| Twofish 256 GCM AEAD (128 bit MAC) | 8 | TWOFISH256GCM |

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.

**NOTE**: SPHINCS+ and NTRUEncrypt key serialization uses a custom serializer
at present, which will change in the future, as soon as Bouncy Castle
implemented a (working) serializer (again). This change will require a manual
key conversion from the current serialization format.
Main goals of this extension library are to make `wan24-Crypto` usable on all
platforms and extend its algorithms by PQC algorithms and other non-PQC
algorithms, which are not available from .NET, but implemented in the Bouncy
Castle library.

## How to get it

Expand All @@ -54,21 +54,7 @@ wan24.Crypto.BC.Bootstrap.Boot();

This will register the algorithms to the `wan24-Crypto` library.

To set Bouncy Castle defaults as `wan24-Crypto` defaults:

```cs
BouncyCastle.SetDefaults();
```

Per default the current `wan24-Crypto` default will be set as counter
algorithms to `HybridAlgorithmHelper`.

Current Bouncy Castle default algorithms are:

- Key exchange: NTRUEncrypt
- Signature: CRYSTALS-Dilithium
- Encryption: Serpent 256 bit CBC
- PAKE encryption: Serpent 256 bit GCM
### `wan24-Crypto` algorithm replacement

Some algorithms of the `wan24-Crypto` library are not available on some
platforms, that's why they need to be replaced in order to be used:
Expand All @@ -95,7 +81,28 @@ BouncyCastle.ReplaceNetAlgorithms();

**NOTE**: The Shake128/256 replacements don't support variable output length
and use the default output length of the `wan24-Crypto` implementations
instead.
instead. The `NetShake128/256HashAlgorithmAdapter` can't be replaced for this
reason.

### Use as default algorithms

To set Bouncy Castle defaults as `wan24-Crypto` defaults:

```cs
BouncyCastle.SetDefaults();
```

Per default the current `wan24-Crypto` default will be set as counter
algorithms to `HybridAlgorithmHelper`.

Current Bouncy Castle default algorithms are:

| Usage | Algorithm |
| ----- | --------- |
| Key exchange | NTRUEncrypt |
| Signature | CRYSTALS-Dilithium |
| Encryption | Serpent 256 bit CBC |
| PAKE encryption | Serpent 256 bit GCM |

## Post quantum safety

Expand All @@ -107,6 +114,10 @@ These asymmetric algorithms are designed for post quantum cryptography:
- SPHINCS+ (signature)
- FrodoKEM (key exchange)
- NTRUEncrypt (key exchange)
- Streamlined NTRU Prime (key exchange)
- BIKE (key exchange)
- HQC (key exchange)
- Picnic (signature)

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:
Expand Down Expand Up @@ -148,11 +159,23 @@ SignatureContainer signature = dataToSign.Sign(yourNormalPrivateKey, options: op

## Algorithm parameters used

For CRYSTALS-Kyber and CRYSTALS-Dilithium the non-AES parameters are being
used, since the AES parameter sets have been deprecated. When using SPHINCS+,
the Haraka simple hashing parameters will be used (since the Haraka robust
hashing parameters have been reprecated). For FrodoKEM the AES parameters will
be used.
| Algorithm | Parameters |
| --------- | ---------- |
| CRYSTALS-Kyber, CRYSTALS-Dilithium | non-AES |
| SPHINCS+ | Haraka simple* |
| FrodoKEM | AES* |
| Picnic | Full |

**NOTE**: CRYSTALS-Kyber and CRYSTALS-Dilithium AES parameters and SPHINCS+
robust parameters are deprecated! SPHINCS+ Haraka parameters are removed from
the FIPS standard, so `wan24-Crypto-BC` will switch to Shake parameters
instead. Also the FrodoKEM Shake parameters will be used in the next major
release, which will require to renew existing keys, which use the AES
parameters from the current version of this library.

**WARNING** The PQC standards are in development at the moment, so future
incompatible changes are very likely and will be handled in a new major
release of this library.

## Random data provider

Expand Down Expand Up @@ -186,8 +209,10 @@ 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`
| Stream cipher | RNG |
| ------------- | --- |
| 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`.
Expand Down
6 changes: 3 additions & 3 deletions src/wan24-Crypto-BC Tests/wan24-Crypto-BC Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.2.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.2.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.2.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="wan24-Crypto-Shared-Tests" Version="2.1.0" />
<PackageReference Include="wan24-Crypto-Shared-Tests" Version="2.1.3" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricBcEcDiffieHellmanPrivateKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public AsymmetricBcEcDiffieHellmanPrivateKey(byte[] keyData) : base(AsymmetricBc
/// <param name="keys">Keys</param>
public AsymmetricBcEcDiffieHellmanPrivateKey(AsymmetricCipherKeyPair keys) : base(AsymmetricBcEcDiffieHellmanAlgorithm.ALGORITHM_NAME, keys) { }

/// <summary>
/// Constructor
/// </summary>
/// <param name="privateKey">Private key</param>
public AsymmetricBcEcDiffieHellmanPrivateKey(ECPrivateKeyParameters privateKey) : base(AsymmetricBcEcDiffieHellmanAlgorithm.ALGORITHM_NAME, privateKey) { }

/// <inheritdoc/>
public override (byte[] Key, byte[] KeyExchangeData) GetKeyExchangeData(IAsymmetricPublicKey? publicKey = null, CryptoOptions? options = null)
{
Expand Down
6 changes: 6 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricBcEcDsaPrivateKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public AsymmetricBcEcDsaPrivateKey(byte[] keyData) : base(AsymmetricBcEcDsaAlgor
/// <param name="keys">Keys</param>
public AsymmetricBcEcDsaPrivateKey(AsymmetricCipherKeyPair keys) : base(AsymmetricBcEcDsaAlgorithm.ALGORITHM_NAME, keys) { }

/// <summary>
/// Constructor
/// </summary>
/// <param name="privateKey">Private key</param>
public AsymmetricBcEcDsaPrivateKey(ECPrivateKeyParameters privateKey) : base(AsymmetricBcEcDsaAlgorithm.ALGORITHM_NAME, privateKey) { }

/// <inheritdoc/>
protected override ECPublicKeyParameters GetPublicKey(ECPrivateKeyParameters privateKey) => new(privateKey.Parameters.G.Multiply(privateKey.D), privateKey.Parameters);

Expand Down
70 changes: 70 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricBikeAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Org.BouncyCastle.Pqc.Crypto.Bike;
using System.Collections.ObjectModel;

namespace wan24.Crypto.BC
{
/// <summary>
/// BIKE asymmetric algorithm
/// </summary>
public sealed record class AsymmetricBikeAlgorithm
: BouncyCastleAsymmetricAlgorithmBase<
AsymmetricBikePublicKey,
AsymmetricBikePrivateKey,
BikeKeyPairGenerator,
BikeKeyGenerationParameters,
BikeParameters,
BikePublicKeyParameters,
BikePrivateKeyParameters,
AsymmetricBikeAlgorithm
>
{
/// <summary>
/// Algorithm name
/// </summary>
public const string ALGORITHM_NAME = "BIKE";
/// <summary>
/// Algorithm value
/// </summary>
public const int ALGORITHM_VALUE = 15;
/// <summary>
/// Default key size in bits
/// </summary>
public const int DEFAULT_KEY_SIZE = 256;
/// <summary>
/// Algorithm usages
/// </summary>
public const AsymmetricAlgorithmUsages USAGES = AsymmetricAlgorithmUsages.KeyExchange;
/// <summary>
/// Display name
/// </summary>
public const string DISPLAY_NAME = "BIKE";

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

/// <summary>
/// Static constructor
/// </summary>
static AsymmetricBikeAlgorithm() => _AllowedKeySizes = new List<int>()
{
128,// 128 bit security
192,// 192 bit security
256// 256 bit security
}.AsReadOnly();

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

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

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

namespace wan24.Crypto.BC
{
/// <summary>
/// BIKE asymmetric algorithm helper
/// </summary>
public static class AsymmetricBikeHelper
{
/// <summary>
/// Get the key size in bits
/// </summary>
/// <param name="param">Parameters</param>
/// <returns>Key size in bits</returns>
public static int GetKeySize(this BikeParameters param)
{
if (param == BikeParameters.bike128) return 128;
if (param == BikeParameters.bike192) return 192;
if (param == BikeParameters.bike256) return 256;
throw new ArgumentException("Invalid BIKE parameters", nameof(param));
}

/// <summary>
/// Get the BIKE parameters
/// </summary>
/// <param name="keySize">Key size in bits</param>
/// <returns>Parameters</returns>
public static BikeParameters GetParameters(int keySize) => keySize switch
{
128 => BikeParameters.bike128,
192 => BikeParameters.bike192,
256 => BikeParameters.bike256,
_ => throw new ArgumentException("Invalid key size", nameof(keySize))
};
}
}
82 changes: 82 additions & 0 deletions src/wan24-Crypto-BC/AsymmetricBikePrivateKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pqc.Crypto.Bike;
using wan24.Core;

namespace wan24.Crypto.BC
{
/// <summary>
/// BIKE asymmetric private key
/// </summary>
public sealed record class AsymmetricBikePrivateKey
: BouncyCastleAsymmetricPqcPrivateKeyExchangeKeyBase<
AsymmetricBikePublicKey,
AsymmetricBikeAlgorithm,
BikePublicKeyParameters,
BikePrivateKeyParameters,
BikeKemGenerator,
BikeKemExtractor,
AsymmetricBikePrivateKey
>
{
/// <summary>
/// Constructor
/// </summary>
public AsymmetricBikePrivateKey() : base(AsymmetricBikeAlgorithm.ALGORITHM_NAME) { }

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

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

/// <inheritdoc/>
new public static bool IsBcImportExportImplemented => false;

/// <inheritdoc/>
protected override byte[] SerializeKeyData() => SerializeFullKeyData();

/// <inheritdoc/>
protected override void DeserializeKeyData() => DeserializeFullKeyData();

/// <inheritdoc/>
protected override BikePublicKeyParameters GetPublicKey(BikePrivateKeyParameters privateKey) => throw new NotSupportedException();

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (Keys?.Private is not BikePrivateKeyParameters privateKey) return;
privateKey.GetH0().Clear();
privateKey.GetH1().Clear();
privateKey.GetSigma().Clear();
}

/// <inheritdoc/>
protected override async Task DisposeCore()
{
await base.DisposeCore().DynamicContext();
if (Keys?.Private is not BikePrivateKeyParameters privateKey) return;
privateKey.GetH0().Clear();
privateKey.GetH1().Clear();
privateKey.GetSigma().Clear();
}

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

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

0 comments on commit bfcc386

Please sign in to comment.