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

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

commit 1c5987d4130f5883795d0098c69cf04cc619b11b
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Sun Jul 11 23:35:29 2021 +0200

    [SSHD-1191] Abstract session: correct rekey block count limit
    
    Follow the recommendation from RFC 4344: if the cipher block size
    is smaller than 16, re-key after 1GB of data.[1] Otherwise, we'd
    re-key far too often; for instance with a block size of 8 after 64k
    blocks, i.e., after 512kB of data. Note that chacha20-poly1305 has
    a block size of 8.
    
    OpenSSH uses the same implementation.[2]
    
    [1] https://datatracker.ietf.org/doc/html/rfc4344#section-3.2
    [2]https://github.com/openssh/openssh-portable/blob/99981d5f/packet.c#L940
---
 .../common/session/helpers/AbstractSession.java    | 49 ++++++++++++++++++----
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
index 14da167..ffd0d2c 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
@@ -1760,16 +1760,10 @@ public abstract class AbstractSession extends 
SessionHelper {
         // TODO add support for configurable compression level
         inCompression.init(Compression.Type.Inflater, -1);
 
-        // see https://tools.ietf.org/html/rfc4344#section-3.2
-        // select the lowest cipher size
-        int avgCipherBlockSize = Math.min(inCipherSize, outCipherSize);
-        long recommendedByteRekeyBlocks = 1L << Math.min((avgCipherBlockSize * 
Byte.SIZE) / 4,
-                63); // in case (block-size / 4) > 63
-        long effectiveRekeyBlocksCount = 
CoreModuleProperties.REKEY_BLOCKS_LIMIT.getRequired(this);
-        maxRekeyBlocks.set(effectiveRekeyBlocksCount > 0 ? 
effectiveRekeyBlocksCount : recommendedByteRekeyBlocks);
+        maxRekeyBlocks.set(determineRekeyBlockLimit(inCipherSize, 
outCipherSize));
         if (debugEnabled) {
-            log.debug("receiveNewKeys({}) inCipher={}, outCipher={}, 
recommended blocks limit={}, actual={}",
-                    this, inCipher, outCipher, recommendedByteRekeyBlocks, 
maxRekeyBlocks);
+            log.debug("receiveNewKeys({}) inCipher={}, outCipher={}, blocks 
limit={}", this, inCipher, outCipher,
+                    maxRekeyBlocks);
         }
 
         inBytesCount.set(0L);
@@ -1783,6 +1777,43 @@ public abstract class AbstractSession extends 
SessionHelper {
     }
 
     /**
+     * Compute the number of blocks after which we should re-key again. See 
RFC 4344.
+     *
+     * @param  inCipherBlockSize  block size of the input cipher
+     * @param  outCipherBlockSize block size of the output cipher
+     * @return                    the number of block after which re-keying 
occur at the latest
+     * @see                       <a href= 
"https://tools.ietf.org/html/rfc4344#section-3.2";>RFC 4344, section 3.2</a>
+     */
+    protected long determineRekeyBlockLimit(int inCipherBlockSize, int 
outCipherBlockSize) {
+        // see https://tools.ietf.org/html/rfc4344#section-3.2
+        // select the lowest cipher size
+        long rekeyBlocksLimit = 
CoreModuleProperties.REKEY_BLOCKS_LIMIT.getRequired(this);
+        if (rekeyBlocksLimit <= 0) {
+            // Default per RFC 4344
+            int minCipherBlockBytes = Math.min(inCipherSize, outCipherSize);
+            if (minCipherBlockBytes >= 16) {
+                rekeyBlocksLimit = 1L << Math.min(minCipherBlockBytes * 2, 63);
+            } else {
+                // With a block size of 8 we'd end up with 2^16. That would 
re-key very often.
+                // RFC 4344: "If L is less than 128 [...], then, although it 
may be too
+                // expensive to rekey every 2**(L/4) blocks, it is still 
advisable for SSH
+                // implementations to follow the original recommendation in 
[RFC4253]: rekey at
+                // least once for every gigabyte of transmitted data."
+                //
+                // Note that chacha20-poly1305 has a block size of 8. The 
OpenSSH recommendation
+                // is: "ChaCha20 must never reuse a {key, nonce} for 
encryption nor may it be
+                // used to encrypt more than 2^70 bytes under the same {key, 
nonce}. The
+                // SSH Transport protocol (RFC4253) recommends a far more 
conservative
+                // rekeying every 1GB of data sent or received. If this 
recommendation
+                // is followed, then chacha20-poly1...@openssh.com requires no 
special
+                // handling in this area."
+                rekeyBlocksLimit = (1L << 30) / minCipherBlockBytes; // 1GB
+            }
+        }
+        return rekeyBlocksLimit;
+    }
+
+    /**
      * Send a {@code SSH_MSG_UNIMPLEMENTED} packet. This packet should contain 
the sequence id of the unsupported
      * packet: this number is assumed to be the last packet received.
      *

Reply via email to