Skip to content

Commit

Permalink
Dev (#27)
Browse files Browse the repository at this point in the history
* Build target is .NET 8 now
* SHA3 hash/MAC algorithms are now not the default anymore and being used as .NET replacements only
* Separated base classes for asymmetric algorithms in PQC and non-PQC implementations (which have different serialization helpers)
* Asymmetric key data is PKCS#8 now
* Using AES-256-GCM AEAD (128 bit MAC) as default crypto algorithm for PAKE now
* Default key exchange algorithm is NTRU now
+ Added Shake128/256 hash algorithms as .NET replacements
+ Added Ed25519 and Ed448 asymmetric signature algorithms
+ Added `BouncyCastleAsymmetricNonPqcPrivate/PublicSignatureKeyBase2` to support a signer which requires a context constructor parameter
+ Added ECDH algorithm as replacement for the .NET variant from wan24-Crypto
+ Added ECDSA algorithm as replacement for the .NET variant from wan24-Crypto
+ Added `BcEllipticCurves` ECDH and ECDSA elliptic curve helper
+ Added X25519 and X448 asymmetric key exchange algorithms
+ Added own serialization logic for FrodoKEM and NTRU and enabled the algorithms to be available per default
+ Added `CryptoEnvironment.(UpdateDefaultOptionsAfter)RemoveUnsupportedAlgorithms`
- Fixed all SHA3 algorithms are considered to be post-quantum-safe
- Fixed wrong asymmetric PQC key data serialization
- Fixed PQC key exchange derive key from encapsulated secret methods had to clone the provided information (they'll be cleared from Bouncy Castle)
  • Loading branch information
nd1012 authored Jan 21, 2024
1 parent 7be476e commit 5892422
Show file tree
Hide file tree
Showing 83 changed files with 3,201 additions and 413 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore ./src/wan24-Crypto-BC.sln --ignore-failed-sources
- name: Build lib
Expand Down
58 changes: 47 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ the `wan24-Crypto` library with these algorithms:
| SPHINCS+ | 5 | SPHINCSPLUS |
| FrodoKEM* | 6 | FRODOKEM |
| NTRUEncrypt* | 7 | NTRUENCRYPT |
| Ed25519 | 8 | ED25519 |
| Ed448 | 9 | ED448 |
| X25519 | 10 | X25519 |
| X448 | 11 | X448 |
| **Symmetric** | | |
| ChaCha20 | 1 | CHACHA20 |
| XSalsa20 | 2 | XSALSA20 |
Expand All @@ -22,14 +26,6 @@ the `wan24-Crypto` library with these algorithms:
| Serpent 256 GCM AEAD (128 bit MAC) | 6 | SERPENT256GCM |
| Twofish 256 CBC (ISO10126 padding) | 7 | TWOFISH256CBC |
| Twofish 256 GCM AEAD (128 bit MAC) | 8 | TWOFISH256GCM |
| **Hashing** | | |
| SHA3-256 | 5 | SHA3-256 |
| SHA3-384 | 6 | SHA3-384 |
| SHA3-512 | 7 | SHA3-512 |
| **MAC** | | |
| HMAC-SHA3-256 | 4 | HMAC-SHA3-256 |
| HMAC-SHA3-384 | 5 | HMAC-SHA3-384 |
| HMAC-SHA3-512 | 6 | HMAC-SHA3-512 |

**NOTE**: FrodoKEM and NTRUEncrypt are currently disabled, 'cause there seems
to be a bug (missing code) in the Bouncy Castle library for
Expand Down Expand Up @@ -64,28 +60,50 @@ 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

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:

| `wan24-Crypto` | `wan24-Crypto-BC` |
| -------------- | ----------------- |
| `AsymmetricEcDiffieHellmanAlgorithm` | `AsymmetricBcEcDiffieHellmanAlgorithm` |
| `AsymmetricEcDsaAlgorithm` | `AsymmetricBcEcDsaAlgorithm` |
| `EncryptionAes256CbcAlgorithm` | `EncryptionBcAes256CbcAlgorithm` |
| `HashShake128Algorithm` | `HashBcShake128Algorithm` |
| `HashShake256Algorithm` | `HashBcShake256Algorithm` |
| `HashSha3_256Algorithm` | `HashBcSha3_256Algorithm` |
| `HashSha3_384Algorithm` | `HashBcSha3_384Algorithm` |
| `HashSha3_512Algorithm` | `HashBcSha3_512Algorithm` |
| `MacHmacSha3_256Algorithm` | `MacBcHmacSha3_256Algorithm` |
| `MacHmacSha3_384Algorithm` | `MacBcHmacSha3_384Algorithm` |
| `MacHmacSha3_512Algorithm` | `MacBcHmacSha3_512Algorithm` |

To replace all of them:

```cs
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.

## Post quantum safety

These algorithms are designed for post quantum cryptography:
These asymmetric algorithms are designed for post quantum cryptography:

- CRYSTALS-Kyber (key exchange)
- CRYSTALS-Dilithium (signature)
- FALCON (signature)
- SPHINCS+ (signature)
- FrodoKEM (key exchange)
- NTRUEncrypt (key exchange)

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 All @@ -98,12 +116,16 @@ CryptoHelper.ForcePostQuantumSafety();
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)
- NTRUEncrypt (key exchange)
- CRYSTALS-Dilithium (signature)

For using other algorithms instead:

```cs
// CRYSTALS-Kyber
HybridAlgorithmHelper.SignatureAlgorithm =
AsymmetricHelper.GetAlgorithm(AsymmetricKyberAlgorithm.ALGORITHM_NAME);

// FALCON
HybridAlgorithmHelper.SignatureAlgorithm =
AsymmetricHelper.GetAlgorithm(AsymmetricFalconAlgorithm.ALGORITHM_NAME);
Expand All @@ -123,7 +145,7 @@ encryption:
```cs
// Create options having a counter private key
CryptoOptions options = EncryptionHelper.GetDefaultOptions();
options.SetCounterPrivateKey(yourKyberPrivateKey);
options.SetCounterPrivateKey(yourNtruPrivateKey);

// Encrypt using the options and your normal private key
byte[] cipherData = rawData.Encrypt(yourNormalPrivateKey, options);
Expand Down Expand Up @@ -209,3 +231,17 @@ used, if `/dev/random` was preferred. To disable `/dev/random`, set

**NOTE**: Currently only stream ciphers are supported, because the cipher RNG
implementation doesn't buffer pre-generated random data.

## X/Ed448-Goldilocks and X/Ed25519

Just a short note on Curve448: Private and public keys have a different key
size: The private key has 456 bit, while the public key has 448 bit. Both key
sizes are supported for key generation and result in the same key sizes for
the private (456 bit) and the public (448 bit) key. The private key of a key
pair will always identify with 456 bit, while the public key will always
identify with 448 bit - no matter which key size was chosen for key pair
generation.

The Ed448 signature is context based, but currently only an empty byte array
is being used as context data. Instead of a context you should use the purpose
free text, which can be given to the signature methods of `wan24-Crypto`.
2 changes: 1 addition & 1 deletion src/wan24-Crypto-BC Docs/wan24-Crypto-BC Docs.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>wan24_Crypto_BC_Docs</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
8 changes: 8 additions & 0 deletions src/wan24-Crypto-BC Tests/A_Initialization.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using wan24.Core;
using wan24.Crypto.BC;
using wan24.Crypto.Tests;
using wan24.ObjectValidation;

namespace wan24_Crypto_BC_Tests
Expand All @@ -15,6 +16,13 @@ public static void Init(TestContext tc)
ValidateObject.Logger = (message) => Logging.WriteDebug(message);
TypeHelper.Instance.AddAssemblies(typeof(wan24.Crypto.BC.Bootstrap).Assembly);
wan24.Core.Bootstrap.Async().Wait();
DisposableBase.CreateStackInfo = true;
DisposableRecordBase.CreateStackInfo = true;
ErrorHandling.ErrorHandler = (info) =>
{
if (info.Exception is StackInfoException six) Logging.WriteError(six.StackInfo.Stack);
};
SharedTests.Initialize();
BouncyCastle.ReplaceNetAlgorithms();
Logging.WriteDebug("wan24-Crypto-BC Tests initialized");
}
Expand Down
11 changes: 9 additions & 2 deletions src/wan24-Crypto-BC Tests/Asymmetric_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
using wan24.Crypto.Tests;
using wan24.Crypto;
using wan24.Crypto.BC;
using wan24.Crypto.Tests;

namespace wan24_Crypto_Tests
{
[TestClass]
public class Asymmetric_Tests
{
[TestMethod]
public void AllAlgo_Tests() => AsymmetricTests.TestAllAlgorithms();
public void AllAlgo_Tests()
{
Assert.IsTrue(AsymmetricHelper.Algorithms[AsymmetricEcDiffieHellmanAlgorithm.ALGORITHM_NAME] is AsymmetricBcEcDiffieHellmanAlgorithm);
Assert.IsTrue(AsymmetricHelper.Algorithms[AsymmetricEcDsaAlgorithm.ALGORITHM_NAME] is AsymmetricBcEcDsaAlgorithm);
AsymmetricTests.TestAllAlgorithms();
}
}
}
78 changes: 78 additions & 0 deletions src/wan24-Crypto-BC Tests/Compatibility_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Security.Cryptography;
using wan24.Core;
using wan24.Crypto;
using wan24.Crypto.BC;

namespace wan24_Crypto_Tests
{
[TestClass]
public class Compatibility_Tests
{
private static readonly byte[] TestData = [1, 2, 3];

[TestMethod]
public void EcDh_Tests()
{
using AsymmetricEcDiffieHellmanPrivateKey keyA = AsymmetricEcDiffieHellmanAlgorithm.Instance.CreateKeyPair();
using AsymmetricBcEcDiffieHellmanPublicKey pubKeyA = new(keyA.PublicKey.KeyData.Array.CloneArray());
using AsymmetricBcEcDiffieHellmanPrivateKey keyB = AsymmetricBcEcDiffieHellmanAlgorithm.Instance.CreateKeyPair();
(byte[] secretB, byte[] kexB) = keyB.GetKeyExchangeData(pubKeyA);
byte[] secretA = keyA.DeriveKey(kexB);
Assert.IsTrue(secretA.SequenceEqual(secretB));
}

[TestMethod]
public void EcDsa_Tests()
{
using AsymmetricEcDsaPrivateKey netKey = AsymmetricEcDsaAlgorithm.Instance.CreateKeyPair();
using AsymmetricBcEcDsaPrivateKey bcKey = new(netKey.KeyData.Array);
SignatureContainer signature = netKey.SignData(TestData);
Assert.IsTrue(bcKey.PublicKey.ValidateSignature(signature, TestData, throwOnError: false), ".NET signature vlidation with Bouncy Castle failed");
signature = bcKey.SignData(TestData);
Assert.IsTrue(netKey.PublicKey.ValidateSignature(signature, TestData, throwOnError: false), "Bouncy Castle signature vlidation with .NET failed");
}

[TestMethod]
public void Aes256Cbc_Tests()
{
CryptoOptions options = new()
{
LeaveOpen = true
};
using MemoryStream raw = new(TestData);
using MemoryStream cipher = new();
using MemoryStream decrypted = new();
EncryptionAes256CbcAlgorithm.Instance.Encrypt(raw, cipher, TestData, options);
cipher.Position = 0;
EncryptionAes256CbcAlgorithm.Instance.Decrypt(cipher, decrypted, TestData, options);
Assert.IsTrue(decrypted.ToArray().SequenceEqual(TestData));
}

[TestMethod]
public void Sha3_Tests()
{
if (!Shake128.IsSupported) return;
byte[] a, b;
foreach (HashAlgorithmBase[] algos in new HashAlgorithmBase[][]{
[HashSha3_256Algorithm.Instance, HashBcSha3_256Algorithm.Instance],
[HashSha3_384Algorithm.Instance, HashBcSha3_384Algorithm.Instance],
[HashSha3_512Algorithm.Instance, HashBcSha3_512Algorithm.Instance],
})
{
a = algos[0].Hash(TestData);
b = algos[1].Hash(TestData);
Assert.IsTrue(a.SequenceEqual(b), $"{algos[0].GetType()} ({a.Length}/{b.Length})");
}
foreach (MacAlgorithmBase[] algos in new MacAlgorithmBase[][]{
[MacHmacSha3_256Algorithm.Instance, MacBcHmacSha3_256Algorithm.Instance],
[MacHmacSha3_384Algorithm.Instance, MacBcHmacSha3_384Algorithm.Instance],
[MacHmacSha3_512Algorithm.Instance, MacBcHmacSha3_512Algorithm.Instance],
})
{
a = algos[0].Mac(TestData, TestData);
b = algos[1].Mac(TestData, TestData);
Assert.IsTrue(a.SequenceEqual(b), $"{algos[0].GetType()} ({a.Length}/{b.Length})");
}
}
}
}
10 changes: 8 additions & 2 deletions src/wan24-Crypto-BC Tests/Encryption_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
using wan24.Crypto.Tests;
using wan24.Crypto;
using wan24.Crypto.BC;
using wan24.Crypto.Tests;

namespace wan24_Crypto_Tests
{
[TestClass]
public class Encryption_Tests
{
[TestMethod]
public async Task All_Tests() => await EncryptionTests.TestAllAlgorithms();
public async Task All_Tests()
{
Assert.IsTrue(EncryptionHelper.Algorithms[EncryptionAes256CbcAlgorithm.ALGORITHM_NAME] is EncryptionBcAes256CbcAlgorithm);
await EncryptionTests.TestAllAlgorithms();
}
}
}
14 changes: 12 additions & 2 deletions src/wan24-Crypto-BC Tests/Hashing_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
using wan24.Crypto.Tests;
using wan24.Crypto;
using wan24.Crypto.BC;
using wan24.Crypto.Tests;

namespace wan24_Crypto_Tests
{
[TestClass]
public class Hashing_Tests
{
[TestMethod]
public async Task All_Tests() => await HashingTests.TestAllAlgorithms();
public async Task All_Tests()
{
Assert.IsTrue(HashHelper.Algorithms[HashSha3_256Algorithm.ALGORITHM_NAME] is HashBcSha3_256Algorithm);
Assert.IsTrue(HashHelper.Algorithms[HashSha3_384Algorithm.ALGORITHM_NAME] is HashBcSha3_384Algorithm);
Assert.IsTrue(HashHelper.Algorithms[HashSha3_512Algorithm.ALGORITHM_NAME] is HashBcSha3_512Algorithm);
Assert.IsTrue(HashHelper.Algorithms[HashShake128Algorithm.ALGORITHM_NAME] is HashBcShake128Algorithm);
Assert.IsTrue(HashHelper.Algorithms[HashShake256Algorithm.ALGORITHM_NAME] is HashBcShake256Algorithm);
await HashingTests.TestAllAlgorithms();
}
}
}
12 changes: 10 additions & 2 deletions src/wan24-Crypto-BC Tests/Mac_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
using wan24.Crypto.Tests;
using wan24.Crypto;
using wan24.Crypto.BC;
using wan24.Crypto.Tests;

namespace wan24_Crypto_Tests
{
[TestClass]
public class Mac_Tests
{
[TestMethod]
public async Task All_Tests() => await MacTests.TestAllAlgorithms();
public async Task All_Tests()
{
Assert.IsTrue(MacHelper.Algorithms[MacHmacSha3_256Algorithm.ALGORITHM_NAME] is MacBcHmacSha3_256Algorithm);
Assert.IsTrue(MacHelper.Algorithms[MacHmacSha3_384Algorithm.ALGORITHM_NAME] is MacBcHmacSha3_384Algorithm);
Assert.IsTrue(MacHelper.Algorithms[MacHmacSha3_512Algorithm.ALGORITHM_NAME] is MacBcHmacSha3_512Algorithm);
await MacTests.TestAllAlgorithms();
}
}
}
10 changes: 5 additions & 5 deletions src/wan24-Crypto-BC Tests/wan24-Crypto-BC Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>wan24_Crypto_BC_Tests2</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand All @@ -12,16 +12,16 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<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.8.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.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="1.13.0" />
<PackageReference Include="wan24-Crypto-Shared-Tests" Version="2.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 5892422

Please sign in to comment.