This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch dev_3.0
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 1693f478f3463510000a403cc2e1e272bb502b84
Author: Thomas Wolf <[email protected]>
AuthorDate: Wed Oct 15 19:10:04 2025 +0200

    ChaCha20: simplify initializing the Poly1305 Mac
    
    Just get a full block from ChaCha20 to increment the block counter
    instead of re-initializing the ChaCha20 cipher. This also has the
    advantage that getting the second 32 bytes overwrites the first
    32 bytes and thus clears the Mac key.
---
 .../sshd/common/cipher/AbstractChaCha20Cipher.java |  2 ++
 .../apache/sshd/common/cipher/ChaCha20Cipher.java  |  1 -
 .../sshd/common/cipher/ChaCha20CipherFactory.java  | 23 ++++++++++------------
 3 files changed, 12 insertions(+), 14 deletions(-)

diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/cipher/AbstractChaCha20Cipher.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/cipher/AbstractChaCha20Cipher.java
index b7db12141..95409d1a3 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/cipher/AbstractChaCha20Cipher.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/cipher/AbstractChaCha20Cipher.java
@@ -24,6 +24,8 @@ package org.apache.sshd.common.cipher;
  */
 public abstract class AbstractChaCha20Cipher implements Cipher {
 
+    protected static final int BLOCK_BYTES = 64;
+
     protected AbstractChaCha20Cipher() {
         super();
     }
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/cipher/ChaCha20Cipher.java 
b/sshd-common/src/main/java/org/apache/sshd/common/cipher/ChaCha20Cipher.java
index e4ebde8b6..9e170c2c9 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/cipher/ChaCha20Cipher.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/cipher/ChaCha20Cipher.java
@@ -99,7 +99,6 @@ public class ChaCha20Cipher extends AbstractChaCha20Cipher {
     }
 
     protected static class ChaChaEngine {
-        private static final int BLOCK_BYTES = 64;
         private static final int BLOCK_INTS = BLOCK_BYTES / Integer.BYTES;
         private static final int KEY_OFFSET = 4;
         private static final int KEY_BYTES = 32;
diff --git 
a/sshd-common/src/main/java11/org/apache/sshd/common/cipher/ChaCha20CipherFactory.java
 
b/sshd-common/src/main/java11/org/apache/sshd/common/cipher/ChaCha20CipherFactory.java
index d7a3eb6c5..dfffc2b33 100644
--- 
a/sshd-common/src/main/java11/org/apache/sshd/common/cipher/ChaCha20CipherFactory.java
+++ 
b/sshd-common/src/main/java11/org/apache/sshd/common/cipher/ChaCha20CipherFactory.java
@@ -131,7 +131,7 @@ public final class ChaCha20CipherFactory implements 
Supplier<Cipher> {
             AlgorithmParameterSpec algorithmParameterSpec = new 
ChaCha20ParameterSpec(nonce, 0);
             k1 = new SecretKeySpec(Arrays.copyOfRange(key, 0, 32), "ChaCha20");
             bodyEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k1, 
algorithmParameterSpec);
-            mac.init(computePolyMacKey());
+            init(mac, bodyEngine);
 
             k2 = new SecretKeySpec(Arrays.copyOfRange(key, 32, 64), 
"ChaCha20");
             headerEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k2, 
algorithmParameterSpec);
@@ -179,23 +179,20 @@ public final class ChaCha20CipherFactory implements 
Supplier<Cipher> {
             BufferUtils.putUInt(counter, nonce, 8, 4);
             AlgorithmParameterSpec algorithmParameterSpec = new 
ChaCha20ParameterSpec(nonce, 0);
             bodyEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k1, 
algorithmParameterSpec);
-            mac.init(computePolyMacKey());
+            init(mac, bodyEngine);
             headerEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k2,
                     algorithmParameterSpec);
         }
 
-        private byte[] computePolyMacKey() throws GeneralSecurityException {
+        private void init(Mac mac, javax.crypto.Cipher engine) throws 
Exception {
+            // Getting a full block from ChaCha20 increments its block counter 
(from 0 to 1), so the cipher
+            // is set up correctly as a side-effect. The extra bytes gotten 
are simply discarded.
+            //
+            // Note that AbstractChaCha20Cipher.BLOCK_BYTES == 2 * 
Poly1305Mac.KEY_BYTES.
             byte[] block = new byte[Poly1305Mac.KEY_BYTES];
-            bodyEngine.update(block, 0, block.length, block);
-            // JDK does not like re-initialization with same key and nonce, 
even if the counter is different.
-            // But it only checks the latest nonce. So trick it:
-            nonce[0] ^= 1;
-            AlgorithmParameterSpec next = new ChaCha20ParameterSpec(nonce, 1);
-            bodyEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k1, next);
-            nonce[0] ^= 1;
-            next = new ChaCha20ParameterSpec(nonce, 1);
-            bodyEngine.init(mode == Mode.Encrypt ? 
javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, k1, next);
-            return block;
+            engine.update(block, 0, block.length, block);
+            mac.init(block);
+            engine.update(block, 0, block.length, block);
         }
     }
 

Reply via email to