summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-04-27 15:07:36 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-04-27 15:07:36 +0700
commit31da29d6869989dd0b049596df77c0c8aef37e8f (patch)
treeb84ab2b2804ecad48be4c592c87e3abf836082d5
parentAdd default case to switch statements (diff)
downloadBouncyCastle.NET-ed25519-31da29d6869989dd0b049596df77c0c8aef37e8f.tar.xz
Fix Ascon decryption buffering bug
- add test coverage for all buffer splits
-rw-r--r--crypto/Readme.html18
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs14
-rw-r--r--crypto/test/src/crypto/test/AsconTest.cs70
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);