Skip to content

Commit

Permalink
src: Add a Reinitialize function for the Incremental classes.
Browse files Browse the repository at this point in the history
I believe this is the best approach.

- Reset() would imply that the same parameters were being used and would work best if the inputs were cached then disposed. However, that's something I'm trying to avoid, and that also doesn't make sense with Poly1305 since the key can only be used once.
- A FinalizeAndReset() function would save a line of code for the user but FinalizeAndVerifyAndReset() looks horrible and requires another function. Plus see the comments above.
- Switching to an NSec style API would be a breaking change and unnecessarily exposes the state to the user. Furthermore, the new state requires a different name, and the function naming is longer compared to a using statement where the user names it (e.g., IncrementalXChaCha20Poly1305.Push vs secretstream.Push).
  • Loading branch information
samuel-lucas6 committed Jul 13, 2024
1 parent 6eff95e commit 998b1c6
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 22 deletions.
38 changes: 38 additions & 0 deletions src/Geralt.Tests/BLAKE2bTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,26 @@ public void Incremental_Compute_Valid(string hash, string message, string? key =
Assert.AreEqual(hash, Convert.ToHexString(h).ToLower());
}

[TestMethod]
[DynamicData(nameof(UnkeyedTestVectors), DynamicDataSourceType.Method)]
[DynamicData(nameof(KeyedTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Compute_Reinitialize_Valid(string hash, string message, string? key = null)
{
Span<byte> h = stackalloc byte[hash.Length / 2];
Span<byte> m = Convert.FromHexString(message);
Span<byte> k = key != null ? Convert.FromHexString(key) : Span<byte>.Empty;

using var blake2b = new IncrementalBLAKE2b(h.Length, k);
blake2b.Update(m);
blake2b.Finalize(h);
h.Clear();
blake2b.Reinitialize(h.Length, k);
blake2b.Update(m);
blake2b.Finalize(h);

Assert.AreEqual(hash, Convert.ToHexString(h).ToLower());
}

[TestMethod]
[DynamicData(nameof(KeyedTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Valid(string hash, string message, string key)
Expand All @@ -341,6 +361,24 @@ public void Incremental_Verify_Valid(string hash, string message, string key)
Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(KeyedTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Reinitialize_Valid(string hash, string message, string key)
{
Span<byte> h = Convert.FromHexString(hash);
Span<byte> m = Convert.FromHexString(message);
Span<byte> k = Convert.FromHexString(key);

using var blake2b = new IncrementalBLAKE2b(h.Length, k);
blake2b.Update(m);
blake2b.FinalizeAndVerify(h);
blake2b.Reinitialize(h.Length, k);
blake2b.Update(m);
bool valid = blake2b.FinalizeAndVerify(h);

Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(KeyedTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Tampered(string hash, string message, string key)
Expand Down
37 changes: 37 additions & 0 deletions src/Geralt.Tests/Ed25519Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,25 @@ public void Incremental_Sign_Valid(string signature, string message, string priv
Assert.AreEqual(signature, Convert.ToHexString(s).ToLower());
}

[TestMethod]
[DynamicData(nameof(Rfc8032Ed25519phTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Sign_Reinitialize_Valid(string signature, string message, string privateKey)
{
Span<byte> s = stackalloc byte[IncrementalEd25519ph.SignatureSize];
Span<byte> m = Convert.FromHexString(message);
Span<byte> sk = Convert.FromHexString(privateKey);

using var ed25519ph = new IncrementalEd25519ph();
ed25519ph.Update(m);
ed25519ph.Finalize(s, sk);
s.Clear();
ed25519ph.Reinitialize();
ed25519ph.Update(m);
ed25519ph.Finalize(s, sk);

Assert.AreEqual(signature, Convert.ToHexString(s).ToLower());
}

[TestMethod]
[DynamicData(nameof(SignInvalidParameterSizes), DynamicDataSourceType.Method)]
public void Incremental_Sign_Invalid(int signatureSize, int messageSize, int privateKeySize)
Expand Down Expand Up @@ -369,6 +388,24 @@ public void Incremental_Verify_Valid(string signature, string message, string pr
Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(Rfc8032Ed25519phTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Reinitialize_Valid(string signature, string message, string privateKey)
{
Span<byte> s = Convert.FromHexString(signature);
Span<byte> m = Convert.FromHexString(message);
Span<byte> pk = Convert.FromHexString(privateKey)[^Ed25519.PublicKeySize..];

using var ed25519ph = new IncrementalEd25519ph();
ed25519ph.Update(m);
ed25519ph.FinalizeAndVerify(s, pk);
ed25519ph.Reinitialize();
ed25519ph.Update(m);
bool valid = ed25519ph.FinalizeAndVerify(s, pk);

Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(Rfc8032Ed25519phTestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Tampered(string signature, string message, string privateKey)
Expand Down
39 changes: 39 additions & 0 deletions src/Geralt.Tests/Poly1305Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,26 @@ public void Incremental_Compute_Valid(string tag, string message, string oneTime
Assert.AreEqual(tag, Convert.ToHexString(t).ToLower());
}

[TestMethod]
[DynamicData(nameof(Rfc8439TestVectors), DynamicDataSourceType.Method)]
public void Incremental_Compute_Reinitialize_Valid(string tag, string message, string oneTimeKey)
{
Span<byte> t = stackalloc byte[Poly1305.TagSize];
Span<byte> m = Convert.FromHexString(message);
Span<byte> k = Convert.FromHexString(oneTimeKey);

using var poly1305 = new IncrementalPoly1305(k);
poly1305.Update(m);
poly1305.Finalize(t);
t.Clear();
// WARNING: Do NOT reuse the same key in practice
poly1305.Reinitialize(k);
poly1305.Update(m);
poly1305.Finalize(t);

Assert.AreEqual(tag, Convert.ToHexString(t).ToLower());
}

[TestMethod]
[DynamicData(nameof(Rfc8439TestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Valid(string tag, string message, string oneTimeKey)
Expand All @@ -145,6 +165,25 @@ public void Incremental_Verify_Valid(string tag, string message, string oneTimeK
Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(Rfc8439TestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Reinitialize_Valid(string tag, string message, string oneTimeKey)
{
Span<byte> t = Convert.FromHexString(tag);
Span<byte> m = Convert.FromHexString(message);
Span<byte> k = Convert.FromHexString(oneTimeKey);

using var poly1305 = new IncrementalPoly1305(k);
poly1305.Update(m);
poly1305.FinalizeAndVerify(t);
// WARNING: Do NOT reuse the same key in practice
poly1305.Reinitialize(k);
poly1305.Update(m);
bool valid = poly1305.FinalizeAndVerify(t);

Assert.IsTrue(valid);
}

[TestMethod]
[DynamicData(nameof(Rfc8439TestVectors), DynamicDataSourceType.Method)]
public void Incremental_Verify_Tampered(string tag, string message, string oneTimeKey)
Expand Down
20 changes: 20 additions & 0 deletions src/Geralt.Tests/XChaCha20Poly1305Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,26 @@ public void IncrementalChunked_Valid(string key, string plaintext, string associ
Assert.AreEqual(plaintext, Convert.ToHexString(p).ToLower());
}

[TestMethod]
[DynamicData(nameof(IncrementalEncryptParameters), DynamicDataSourceType.Method)]
public void Incremental_Reinitialize_Valid(string key, string plaintext, string associatedData)
{
Span<byte> h = stackalloc byte[IncrementalXChaCha20Poly1305.HeaderSize];
Span<byte> k = Convert.FromHexString(key);
Span<byte> p = Convert.FromHexString(plaintext);
Span<byte> c = stackalloc byte[p.Length + IncrementalXChaCha20Poly1305.TagSize];

using var secretstream = new IncrementalXChaCha20Poly1305(decryption: false, h, k);
secretstream.Push(c, p, IncrementalXChaCha20Poly1305.ChunkFlag.Final);
p.Clear();

secretstream.Reinitialize(decryption: true, h, k);
var chunkFlag = secretstream.Pull(p, c);

Assert.AreEqual(IncrementalXChaCha20Poly1305.ChunkFlag.Final, chunkFlag);
Assert.AreEqual(plaintext, Convert.ToHexString(p).ToLower());
}

[TestMethod]
[DynamicData(nameof(IncrementalInvalidParameterSizes), DynamicDataSourceType.Method)]
public void Incremental_Invalid(int headerSize, int keySize, int ciphertextSize, int plaintextSize)
Expand Down
16 changes: 8 additions & 8 deletions src/Geralt/Crypto/IncrementalBLAKE2b.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ public sealed class IncrementalBLAKE2b : IDisposable
public const int MaxKeySize = BLAKE2b.MaxKeySize;

private crypto_generichash_blake2b_state _state;
private readonly int _hashSize;
private int _hashSize;
private bool _finalized;

public IncrementalBLAKE2b(int hashSize, ReadOnlySpan<byte> key = default)
{
Validation.SizeBetween(nameof(hashSize), hashSize, MinHashSize, MaxHashSize);
if (key.Length != 0) { Validation.SizeBetween(nameof(key), key.Length, MinKeySize, MaxKeySize); }
Sodium.Initialize();
_hashSize = hashSize;
_finalized = false;
Initialize(key);
Reinitialize(hashSize, key);
}

private unsafe void Initialize(ReadOnlySpan<byte> key)
public unsafe void Reinitialize(int hashSize, ReadOnlySpan<byte> key = default)
{
Validation.SizeBetween(nameof(hashSize), hashSize, MinHashSize, MaxHashSize);
if (key.Length != 0) { Validation.SizeBetween(nameof(key), key.Length, MinKeySize, MaxKeySize); }
_hashSize = hashSize;
_finalized = false;
fixed (byte* k = key)
{
int ret = crypto_generichash_init(ref _state, k, (nuint)key.Length, (nuint)_hashSize);
int ret = crypto_generichash_init(ref _state, k, (nuint)key.Length, (nuint)hashSize);
if (ret != 0) { throw new CryptographicException("Error initializing hash function state."); }
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Geralt/Crypto/IncrementalEd25519ph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public sealed class IncrementalEd25519ph : IDisposable
public IncrementalEd25519ph()
{
Sodium.Initialize();
_finalized = false;
Initialize();
Reinitialize();
}

private void Initialize()
public void Reinitialize()
{
_finalized = false;
int ret = crypto_sign_init(ref _state);
if (ret != 0) { throw new CryptographicException("Error initializing signature scheme state."); }
}
Expand Down
8 changes: 4 additions & 4 deletions src/Geralt/Crypto/IncrementalPoly1305.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ public sealed class IncrementalPoly1305 : IDisposable

public IncrementalPoly1305(ReadOnlySpan<byte> oneTimeKey)
{
Validation.EqualToSize(nameof(oneTimeKey), oneTimeKey.Length, KeySize);
Sodium.Initialize();
_finalized = false;
Initialize(oneTimeKey);
Reinitialize(oneTimeKey);
}

private unsafe void Initialize(ReadOnlySpan<byte> oneTimeKey)
public unsafe void Reinitialize(ReadOnlySpan<byte> oneTimeKey)
{
Validation.EqualToSize(nameof(oneTimeKey), oneTimeKey.Length, KeySize);
_finalized = false;
fixed (byte* k = oneTimeKey)
{
int ret = crypto_onetimeauth_init(ref _state, k);
Expand Down
14 changes: 7 additions & 7 deletions src/Geralt/Crypto/IncrementalXChaCha20Poly1305.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public sealed class IncrementalXChaCha20Poly1305 : IDisposable
public const int TagSize = crypto_secretstream_xchacha20poly1305_ABYTES;

private crypto_secretstream_xchacha20poly1305_state _state;
private readonly bool _decryption;
private bool _decryption;
private bool _finalized;

public enum ChunkFlag
Expand All @@ -23,16 +23,16 @@ public enum ChunkFlag

public IncrementalXChaCha20Poly1305(bool decryption, Span<byte> header, ReadOnlySpan<byte> key)
{
Validation.EqualToSize(nameof(header), header.Length, HeaderSize);
Validation.EqualToSize(nameof(key), key.Length, KeySize);
Sodium.Initialize();
_decryption = decryption;
_finalized = false;
Initialize(header, key);
Reinitialize(decryption, header, key);
}

private unsafe void Initialize(Span<byte> header, ReadOnlySpan<byte> key)
public unsafe void Reinitialize(bool decryption, Span<byte> header, ReadOnlySpan<byte> key)
{
Validation.EqualToSize(nameof(header), header.Length, HeaderSize);
Validation.EqualToSize(nameof(key), key.Length, KeySize);
_decryption = decryption;
_finalized = false;
fixed (byte* h = header, k = key)
{
int ret = _decryption
Expand Down

0 comments on commit 998b1c6

Please sign in to comment.