diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-04-27 15:07:36 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-04-27 15:07:36 +0700 |
commit | 31da29d6869989dd0b049596df77c0c8aef37e8f (patch) | |
tree | b84ab2b2804ecad48be4c592c87e3abf836082d5 | |
parent | Add default case to switch statements (diff) | |
download | BouncyCastle.NET-ed25519-31da29d6869989dd0b049596df77c0c8aef37e8f.tar.xz |
Fix Ascon decryption buffering bug
- add test coverage for all buffer splits
-rw-r--r-- | crypto/Readme.html | 18 | ||||
-rw-r--r-- | crypto/src/crypto/engines/AsconEngine.cs | 14 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/AsconTest.cs | 70 |
3 files changed, 96 insertions, 6 deletions
diff --git a/crypto/Readme.html b/crypto/Readme.html index d71cf63da..a7c903371 100644 --- a/crypto/Readme.html +++ b/crypto/Readme.html @@ -32,6 +32,8 @@ <a href="#mozTocId3413">Notes:</a> <ol> <li> + <a href="#mozTocId85331">Release 2.3.0</a> + <li> <a href="#mozTocId85330">Release 2.2.1</a> <li> <a href="#mozTocId85329">Release 2.2.0</a> @@ -327,6 +329,22 @@ <hr style="WIDTH: 100%; HEIGHT: 2px"> <h3><a class="mozTocH3" name="mozTocId3413"></a>Notes:</h3> + <h4><a class="mozTocH4" name="mozTocId85331"></a>Release 2.3.0, TBD</h4> + <h5>Defects Fixed</h5> + <ul> + <li>AsconEngine: Fixed a buffering bug when decrypting across multiple ProcessBytes calls (ascon128a unaffected).</li> + </ul> + <h5>Additional Features and Functionality</h5> + <ul> + </ul> + <h5>Additional Notes</h5> + <ul> + <li> + See the (cumulative) list of GitHub pull requests that we have accepted at + <a href="https://github.com/bcgit/bc-csharp/pulls?q=is%3Apr+is%3Aclosed">bcgit/bc-csharp</a>. + </li> + </ul> + <h4><a class="mozTocH4" name="mozTocId85330"></a>Release 2.2.1, Friday April 21, 2023</h4> <h5>Defects Fixed</h5> <ul> diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs index 8fd49b03e..0f5ff49ce 100644 --- a/crypto/src/crypto/engines/AsconEngine.cs +++ b/crypto/src/crypto/engines/AsconEngine.cs @@ -345,12 +345,13 @@ namespace Org.BouncyCastle.Crypto.Engines return 0; } - if (m_bufPos >= ASCON_AEAD_RATE) + // NOTE: Need 'while' here because ASCON_AEAD_RATE < CRYPTO_ABYTES in some parameter sets + while (m_bufPos >= ASCON_AEAD_RATE) { - ProcessBufferDecrypt(m_buf, 0, outBytes, outOff); + ProcessBufferDecrypt(m_buf, 0, outBytes, outOff + resultLength); m_bufPos -= ASCON_AEAD_RATE; Array.Copy(m_buf, ASCON_AEAD_RATE, m_buf, 0, m_bufPos); - resultLength = ASCON_AEAD_RATE; + resultLength += ASCON_AEAD_RATE; available += ASCON_AEAD_RATE; if (len < available) @@ -429,12 +430,13 @@ namespace Org.BouncyCastle.Crypto.Engines return 0; } - if (m_bufPos >= ASCON_AEAD_RATE) + // NOTE: Need 'while' here because ASCON_AEAD_RATE < CRYPTO_ABYTES in some parameter sets + while (m_bufPos >= ASCON_AEAD_RATE) { - ProcessBufferDecrypt(m_buf, output); + ProcessBufferDecrypt(m_buf, output[resultLength..]); m_bufPos -= ASCON_AEAD_RATE; m_buf.AsSpan(0, m_bufPos).CopyFrom(m_buf.AsSpan(ASCON_AEAD_RATE)); - resultLength = ASCON_AEAD_RATE; + resultLength += ASCON_AEAD_RATE; available += ASCON_AEAD_RATE; if (input.Length < available) diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs index eabf7e043..400767df0 100644 --- a/crypto/test/src/crypto/test/AsconTest.cs +++ b/crypto/test/src/crypto/test/AsconTest.cs @@ -95,6 +95,24 @@ namespace Org.BouncyCastle.Crypto.Tests } [Test] + public void TestBufferingEngine_ascon128() + { + ImplTestBufferingEngine(AsconEngine.AsconParameters.ascon128); + } + + [Test] + public void TestBufferingEngine_ascon128a() + { + ImplTestBufferingEngine(AsconEngine.AsconParameters.ascon128a); + } + + [Test] + public void TestBufferingEngine_ascon80() + { + ImplTestBufferingEngine(AsconEngine.AsconParameters.ascon80pq); + } + + [Test] public void TestExceptionsDigest_AsconHash() { ImplTestExceptionsDigest(AsconDigest.AsconParameters.AsconHash); @@ -327,6 +345,58 @@ namespace Org.BouncyCastle.Crypto.Tests } } + private static void ImplTestBufferingEngine(AsconEngine.AsconParameters asconParameters) + { + Random random = new Random(); + + int plaintextLength = 256; + byte[] plaintext = new byte[plaintextLength]; + random.NextBytes(plaintext); + + var ascon0 = CreateEngine(asconParameters); + InitEngine(ascon0, true); + + byte[] ciphertext = new byte[ascon0.GetOutputSize(plaintextLength)]; + random.NextBytes(ciphertext); + + int ciphertextLength = ascon0.ProcessBytes(plaintext, 0, plaintextLength, ciphertext, 0); + ciphertextLength += ascon0.DoFinal(ciphertext, ciphertextLength); + + byte[] output = new byte[ciphertextLength]; + + // Encryption + for (int split = 1; split < plaintextLength; ++split) + { + var ascon = CreateEngine(asconParameters); + InitEngine(ascon, true); + + random.NextBytes(output); + + int length = ascon.ProcessBytes(plaintext, 0, split, output, 0); + length += ascon.ProcessBytes(plaintext, split, plaintextLength - split, output, length); + length += ascon.DoFinal(output, length); + + Assert.IsTrue(Arrays.AreEqual(ciphertext, 0, ciphertextLength, output, 0, length), + "encryption failed with split: " + split); + } + + // Decryption + for (int split = 1; split < ciphertextLength; ++split) + { + var ascon = CreateEngine(asconParameters); + InitEngine(ascon, false); + + random.NextBytes(output); + + int length = ascon.ProcessBytes(ciphertext, 0, split, output, 0); + length += ascon.ProcessBytes(ciphertext, split, ciphertextLength - split, output, length); + length += ascon.DoFinal(output, length); + + Assert.IsTrue(Arrays.AreEqual(plaintext, 0, plaintextLength, output, 0, length), + "decryption failed with split: " + split); + } + } + private static void ImplTestExceptionsDigest(AsconDigest.AsconParameters asconParameters) { var ascon = new AsconDigest(asconParameters); |