Mailing List Archive

ChaCha20 Rekey Frequency
I'm wondering why the ChaCha20 cipher rekeys so frequently. At speed I'm
seeing rekeys every second or two. So I'm spending a large amount of
time in the rekey process. From what I've read about ChaCha20 it
shouldn't need to be rekeyed quite so frequently. Am I missing something
obvious?

Just curious more than anything else.

Chris
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
Chris Rapier:

> I'm wondering why the ChaCha20 cipher rekeys so frequently. At speed I'm
> seeing rekeys every second or two. So I'm spending a large amount of
> time in the rekey process. From what I've read about ChaCha20 it
> shouldn't need to be rekeyed quite so frequently. Am I missing something
> obvious?

That looks to be accidental.

The default rekey limit is set in ssh_set_newkeys():
/*
* The 2^(blocksize*2) limit is too expensive for 3DES,
* so enforce a 1GB limit for small blocksizes.
* See RFC4344 section 3.2.
*/
if (enc->block_size >= 16)
*max_blocks = (u_int64_t)1 << (enc->block_size*2);
else
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
if (state->rekey_limit)
*max_blocks = MINIMUM(*max_blocks,
state->rekey_limit / enc->block_size);

And the block size of chacha20-poly1305 is set to 8 bytes in
ciphers[]. As a result, chacha20-poly1305 is rekeyed every 1GB of
data as opposed to the 4GB limit of the AES-based ciphers.

--
Christian "naddy" Weisgerber naddy@mips.inka.de
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
I was wondering if there was something specific to the internal chacha20
cipher as opposed to OpenSSL implementation.

I can't just change the block size because it breaks compatibility. I
can do something like as a hack (though it would probably be better to
do it with the compat function):

if (strstr(enc->name, "chacha"))
*max_blocks = (u_int64_t)1 << (16*2);
else if (enc->block_size >= 16)
*max_blocks = (u_int64_t)1 << (enc->block_size*2);
else
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
if (state->rekey_limit)

to force it to reduce the rekey rate but I'm deeply unsure of what
impact that would have on the security of the cipher as it's
implemented. Especially the without-openssl internal implementation.

Chris

On 3/24/23 4:36 PM, Christian Weisgerber wrote:
> Chris Rapier:
>
>> I'm wondering why the ChaCha20 cipher rekeys so frequently. At speed I'm
>> seeing rekeys every second or two. So I'm spending a large amount of
>> time in the rekey process. From what I've read about ChaCha20 it
>> shouldn't need to be rekeyed quite so frequently. Am I missing something
>> obvious?
>
> That looks to be accidental.
>
> The default rekey limit is set in ssh_set_newkeys():
> /*
> * The 2^(blocksize*2) limit is too expensive for 3DES,
> * so enforce a 1GB limit for small blocksizes.
> * See RFC4344 section 3.2.
> */
> if (enc->block_size >= 16)
> *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> else
> *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> if (state->rekey_limit)
> *max_blocks = MINIMUM(*max_blocks,
> state->rekey_limit / enc->block_size);
>
> And the block size of chacha20-poly1305 is set to 8 bytes in
> ciphers[]. As a result, chacha20-poly1305 is rekeyed every 1GB of
> data as opposed to the 4GB limit of the AES-based ciphers.
>
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
On Wed, 29 Mar 2023, Chris Rapier wrote:

> I was wondering if there was something specific to the internal chacha20
> cipher as opposed to OpenSSL implementation.
>
> I can't just change the block size because it breaks compatibility. I can do
> something like as a hack (though it would probably be better to do it with the
> compat function):
>
> if (strstr(enc->name, "chacha"))
> *max_blocks = (u_int64_t)1 << (16*2);
> else if (enc->block_size >= 16)
> *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> else
> *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> if (state->rekey_limit)
>
> to force it to reduce the rekey rate but I'm deeply unsure of what impact that
> would have on the security of the cipher as it's implemented. Especially the
> without-openssl internal implementation.

This is what I'm playing with at the moment:

diff --git a/cipher.c b/cipher.c
index c7664a3..ec6fa4f 100644
--- a/cipher.c
+++ b/cipher.c
@@ -150,6 +150,39 @@ cipher_blocksize(const struct sshcipher *c)
return (c->block_size);
}

+uint64_t
+cipher_rekey_blocks(const struct sshcipher *c)
+{
+ /*
+ * Chacha20-Poly1305 does not benefit from data-based rekeying,
+ * per "The Security of ChaCha20-Poly1305 in the Multi-user Setting",
+ * Degabriele, J. P., Govinden, J, Gunther, F. and Paterson K.
+ * ACM CCS 2021; https://eprint.iacr.org/2023/085.pdf
+ *
+ * Cryptanalysis aside, we do still want do need to prevent the SSH
+ * sequence number wrapping and also to rekey to provide some
+ * protection for long lived sessions against key disclosure at the
+ * endpoints, so arrange for rekeying every 2**32 blocks as the
+ * 128-bit block ciphers do (i.e. every 32GB data).
+ */
+ if ((c->flags & CFLAG_CHACHAPOLY) != 0)
+ return (uint64_t)1 << 32;
+ /*
+ * The 2^(blocksize*2) limit is too expensive for 3DES,
+ * so enforce a 1GB data limit for small blocksizes.
+ * See discussion in RFC4344 section 3.2.
+ */
+ if (c->block_size < 16)
+ return ((uint64_t)1 << 30) / c->block_size;
+ /*
+ * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
+ * before rekeying where L is the blocksize in bits.
+ * Most other ciphers have a 128 bit blocksize, so this equates to
+ * 2**32 blocks / 64GB data.
+ */
+ return (uint64_t)1 << (c->block_size * 2);
+}
+
u_int
cipher_keylen(const struct sshcipher *c)
{
diff --git a/cipher.h b/cipher.h
index 1a591cd..68be9ed 100644
--- a/cipher.h
+++ b/cipher.h
@@ -63,6 +63,7 @@ int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,
const u_char *, u_int);
void cipher_free(struct sshcipher_ctx *);
u_int cipher_blocksize(const struct sshcipher *);
+uint64_t cipher_rekey_blocks(const struct sshcipher *);
u_int cipher_keylen(const struct sshcipher *);
u_int cipher_seclen(const struct sshcipher *);
u_int cipher_authlen(const struct sshcipher *);
diff --git a/packet.c b/packet.c
index a71820f..377f608 100644
--- a/packet.c
+++ b/packet.c
@@ -55,6 +55,7 @@
#include <poll.h>
#include <signal.h>
#include <time.h>
+#include <util.h>

#ifdef WITH_ZLIB
#include <zlib.h>
@@ -850,6 +851,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
const char *wmsg;
int r, crypt_type;
const char *dir = mode == MODE_OUT ? "out" : "in";
+ char blocks_s[FMT_SCALED_STRSIZE], bytes_s[FMT_SCALED_STRSIZE];

debug2_f("mode %d", mode);

@@ -917,20 +919,18 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
}
comp->enabled = 1;
}
- /*
- * The 2^(blocksize*2) limit is too expensive for 3DES,
- * so enforce a 1GB limit for small blocksizes.
- * See RFC4344 section 3.2.
- */
- if (enc->block_size >= 16)
- *max_blocks = (u_int64_t)1 << (enc->block_size*2);
- else
- *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
+ *max_blocks = cipher_rekey_blocks(enc->cipher);
if (state->rekey_limit)
*max_blocks = MINIMUM(*max_blocks,
state->rekey_limit / enc->block_size);
- debug("rekey %s after %llu blocks", dir,
- (unsigned long long)*max_blocks);
+
+ strlcpy(blocks_s, "?", sizeof(blocks_s));
+ strlcpy(bytes_s, "?", sizeof(bytes_s));
+ if (*max_blocks * enc->block_size < LLONG_MAX) {
+ fmt_scaled((long long)*max_blocks, blocks_s);
+ fmt_scaled((long long)*max_blocks * enc->block_size, bytes_s);
+ }
+ debug("rekey %s after %s blocks / %sB data", dir, blocks_s, bytes_s);
return 0;
}

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
RE: [EXTERNAL] Re: ChaCha20 Rekey Frequency [ In reply to ]
I'm hardly an expert on this, but if I remember correctly, the rekey rate for good security is mostly dependent on the cipher block size. I left my reference books at home; so, I can't come up with a reference for you, but I would take Chris' "I'm deeply unsure of what impact that would have on the security of the cipher" comment seriously and switch to a cipher with a 128 bit block length (AES or Camelia).

From: openssh-unix-dev <openssh-unix-dev-bounces+herbie.robinson=stratus.com@mindrot.org> On Behalf Of Damien Miller
Sent: Wednesday, March 29, 2023 2:38 PM
To: Chris Rapier <rapier@psc.edu>
Cc: Christian Weisgerber <naddy@mips.inka.de>; openssh-unix-dev@mindrot.org
Subject: [EXTERNAL] Re: ChaCha20 Rekey Frequency

[.EXTERNAL SENDER: This email originated from outside of Stratus Technologies. Do not click links or open attachments unless you recognize the sender and know the content is safe.]

On Wed, 29 Mar 2023, Chris Rapier wrote:

> I was wondering if there was something specific to the internal chacha20
> cipher as opposed to OpenSSL implementation.
>
> I can't just change the block size because it breaks compatibility. I can do
> something like as a hack (though it would probably be better to do it with the
> compat function):
>
> if (strstr(enc->name, "chacha"))
> *max_blocks = (u_int64_t)1 << (16*2);
> else if (enc->block_size >= 16)
> *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> else
> *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> if (state->rekey_limit)
>
> to force it to reduce the rekey rate but I'm deeply unsure of what impact that
> would have on the security of the cipher as it's implemented. Especially the
> without-openssl internal implementation.

This is what I'm playing with at the moment:

diff --git a/cipher.c b/cipher.c
index c7664a3..ec6fa4f 100644
--- a/cipher.c
+++ b/cipher.c
@@ -150,6 +150,39 @@ cipher_blocksize(const struct sshcipher *c)
return (c->block_size);
}

+uint64_t
+cipher_rekey_blocks(const struct sshcipher *c)
+{
+ /*
+ * Chacha20-Poly1305 does not benefit from data-based rekeying,
+ * per "The Security of ChaCha20-Poly1305 in the Multi-user Setting",
+ * Degabriele, J. P., Govinden, J, Gunther, F. and Paterson K.
+ * ACM CCS 2021; https://eprint.iacr.org/2023/085.pdf<https://eprint.iacr.org/2023/085.pdf>
+ *
+ * Cryptanalysis aside, we do still want do need to prevent the SSH
+ * sequence number wrapping and also to rekey to provide some
+ * protection for long lived sessions against key disclosure at the
+ * endpoints, so arrange for rekeying every 2**32 blocks as the
+ * 128-bit block ciphers do (i.e. every 32GB data).
+ */
+ if ((c->flags & CFLAG_CHACHAPOLY) != 0)
+ return (uint64_t)1 << 32;
+ /*
+ * The 2^(blocksize*2) limit is too expensive for 3DES,
+ * so enforce a 1GB data limit for small blocksizes.
+ * See discussion in RFC4344 section 3.2.
+ */
+ if (c->block_size < 16)
+ return ((uint64_t)1 << 30) / c->block_size;
+ /*
+ * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
+ * before rekeying where L is the blocksize in bits.
+ * Most other ciphers have a 128 bit blocksize, so this equates to
+ * 2**32 blocks / 64GB data.
+ */
+ return (uint64_t)1 << (c->block_size * 2);
+}
+
u_int
cipher_keylen(const struct sshcipher *c)
{
diff --git a/cipher.h b/cipher.h
index 1a591cd..68be9ed 100644
--- a/cipher.h
+++ b/cipher.h
@@ -63,6 +63,7 @@ int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,
const u_char *, u_int);
void cipher_free(struct sshcipher_ctx *);
u_int cipher_blocksize(const struct sshcipher *);
+uint64_t cipher_rekey_blocks(const struct sshcipher *);
u_int cipher_keylen(const struct sshcipher *);
u_int cipher_seclen(const struct sshcipher *);
u_int cipher_authlen(const struct sshcipher *);
diff --git a/packet.c b/packet.c
index a71820f..377f608 100644
--- a/packet.c
+++ b/packet.c
@@ -55,6 +55,7 @@
#include <poll.h>
#include <signal.h>
#include <time.h>
+#include <util.h>

#ifdef WITH_ZLIB
#include <zlib.h>
@@ -850,6 +851,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
const char *wmsg;
int r, crypt_type;
const char *dir = mode == MODE_OUT ? "out" : "in";
+ char blocks_s[FMT_SCALED_STRSIZE], bytes_s[FMT_SCALED_STRSIZE];

debug2_f("mode %d", mode);

@@ -917,20 +919,18 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
}
comp->enabled = 1;
}
- /*
- * The 2^(blocksize*2) limit is too expensive for 3DES,
- * so enforce a 1GB limit for small blocksizes.
- * See RFC4344 section 3.2.
- */
- if (enc->block_size >= 16)
- *max_blocks = (u_int64_t)1 << (enc->block_size*2);
- else
- *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
+ *max_blocks = cipher_rekey_blocks(enc->cipher);
if (state->rekey_limit)
*max_blocks = MINIMUM(*max_blocks,
state->rekey_limit / enc->block_size);
- debug("rekey %s after %llu blocks", dir,
- (unsigned long long)*max_blocks);
+
+ strlcpy(blocks_s, "?", sizeof(blocks_s));
+ strlcpy(bytes_s, "?", sizeof(bytes_s));
+ if (*max_blocks * enc->block_size < LLONG_MAX) {
+ fmt_scaled((long long)*max_blocks, blocks_s);
+ fmt_scaled((long long)*max_blocks * enc->block_size, bytes_s);
+ }
+ debug("rekey %s after %s blocks / %sB data", dir, blocks_s, bytes_s);
return 0;
}

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org<mailto:openssh-unix-dev@mindrot.org>
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev<https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
RE: [EXTERNAL] Re: ChaCha20 Rekey Frequency [ In reply to ]
That's true for block ciphers, but ChaCha20+poly1305 is a stream cipher.

On Wed, 29 Mar 2023, Robinson, Herbie wrote:

>
> I?m hardly an expert on this, but if I remember correctly, the rekey rate
> for good security is mostly dependent on the cipher block size.? I left my
> reference books at home; so, I can?t come up with a reference for you, but I
> would take Chris? ?I'm deeply unsure of what impact that would have on the
> security of the cipher? comment seriously and switch to a cipher with a 128
> bit block length (AES or Camelia).
>
> ?
>
> From: openssh-unix-dev
> <openssh-unix-dev-bounces+herbie.robinson=stratus.com@mindrot.org> On Behalf
> Of Damien Miller
> Sent: Wednesday, March 29, 2023 2:38 PM
> To: Chris Rapier <rapier@psc.edu>
> Cc: Christian Weisgerber <naddy@mips.inka.de>; openssh-unix-dev@mindrot.org
> Subject: [EXTERNAL] Re: ChaCha20 Rekey Frequency
>
> ?
>
> [.EXTERNAL SENDER: This email originated from outside of Stratus
> Technologies. Do not click links or open attachments unless you recognize
> the sender and know the content is safe.]
>
> On Wed, 29 Mar 2023, Chris Rapier wrote:
>
> > I was wondering if there was something specific to the internal chacha20
> > cipher as opposed to OpenSSL implementation.
> >
> > I can't just change the block size because it breaks compatibility. I can
> do
> > something like as a hack (though it would probably be better to do it with
> the
> > compat function):
> >
> > if (strstr(enc->name, "chacha"))
> > *max_blocks = (u_int64_t)1 << (16*2);
> > else if (enc->block_size >= 16)
> > *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> > else
> > *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> > if (state->rekey_limit)
> >
> > to force it to reduce the rekey rate but I'm deeply unsure of what impact
> that
> > would have on the security of the cipher as it's implemented. Especially
> the
> > without-openssl internal implementation.
>
> This is what I'm playing with at the moment:
>
> diff --git a/cipher.c b/cipher.c
> index c7664a3..ec6fa4f 100644
> --- a/cipher.c
> +++ b/cipher.c
> @@ -150,6 +150,39 @@ cipher_blocksize(const struct sshcipher *c)
> return (c->block_size);
> }
>
> +uint64_t
> +cipher_rekey_blocks(const struct sshcipher *c)
> +{
> + /*
> + * Chacha20-Poly1305 does not benefit from data-based rekeying,
> + * per "The Security of ChaCha20-Poly1305 in the Multi-user Setting",
> + * Degabriele, J. P., Govinden, J, Gunther, F. and Paterson K.
> + * ACM CCS 2021; https://eprint.iacr.org/2023/085.pdf
> + *
> + * Cryptanalysis aside, we do still want do need to prevent the SSH
> + * sequence number wrapping and also to rekey to provide some
> + * protection for long lived sessions against key disclosure at the
> + * endpoints, so arrange for rekeying every 2**32 blocks as the
> + * 128-bit block ciphers do (i.e. every 32GB data).
> + */
> + if ((c->flags & CFLAG_CHACHAPOLY) != 0)
> + return (uint64_t)1 << 32;
> + /*
> + * The 2^(blocksize*2) limit is too expensive for 3DES,
> + * so enforce a 1GB data limit for small blocksizes.
> + * See discussion in RFC4344 section 3.2.
> + */
> + if (c->block_size < 16)
> + return ((uint64_t)1 << 30) / c->block_size;
> + /*
> + * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
> + * before rekeying where L is the blocksize in bits.
> + * Most other ciphers have a 128 bit blocksize, so this equates to
> + * 2**32 blocks / 64GB data.
> + */
> + return (uint64_t)1 << (c->block_size * 2);
> +}
> +
> u_int
> cipher_keylen(const struct sshcipher *c)
> {
> diff --git a/cipher.h b/cipher.h
> index 1a591cd..68be9ed 100644
> --- a/cipher.h
> +++ b/cipher.h
> @@ -63,6 +63,7 @@ int cipher_get_length(struct sshcipher_ctx *, u_int *,
> u_int,
> const u_char *, u_int);
> void cipher_free(struct sshcipher_ctx *);
> u_int cipher_blocksize(const struct sshcipher *);
> +uint64_t cipher_rekey_blocks(const struct sshcipher *);
> u_int cipher_keylen(const struct sshcipher *);
> u_int cipher_seclen(const struct sshcipher *);
> u_int cipher_authlen(const struct sshcipher *);
> diff --git a/packet.c b/packet.c
> index a71820f..377f608 100644
> --- a/packet.c
> +++ b/packet.c
> @@ -55,6 +55,7 @@
> #include <poll.h>
> #include <signal.h>
> #include <time.h>
> +#include <util.h>
>
> #ifdef WITH_ZLIB
> #include <zlib.h>
> @@ -850,6 +851,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
> const char *wmsg;
> int r, crypt_type;
> const char *dir = mode == MODE_OUT ? "out" : "in";
> + char blocks_s[FMT_SCALED_STRSIZE], bytes_s[FMT_SCALED_STRSIZE];
>
> debug2_f("mode %d", mode);
>
> @@ -917,20 +919,18 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
> }
> comp->enabled = 1;
> }
> - /*
> - * The 2^(blocksize*2) limit is too expensive for 3DES,
> - * so enforce a 1GB limit for small blocksizes.
> - * See RFC4344 section 3.2.
> - */
> - if (enc->block_size >= 16)
> - *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> - else
> - *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> + *max_blocks = cipher_rekey_blocks(enc->cipher);
> if (state->rekey_limit)
> *max_blocks = MINIMUM(*max_blocks,
> state->rekey_limit / enc->block_size);
> - debug("rekey %s after %llu blocks", dir,
> - (unsigned long long)*max_blocks);
> +
> + strlcpy(blocks_s, "?", sizeof(blocks_s));
> + strlcpy(bytes_s, "?", sizeof(bytes_s));
> + if (*max_blocks * enc->block_size < LLONG_MAX) {
> + fmt_scaled((long long)*max_blocks, blocks_s);
> + fmt_scaled((long long)*max_blocks * enc->block_size, bytes_s);
> + }
> + debug("rekey %s after %s blocks / %sB data", dir, blocks_s, bytes_s);
> return 0;
> }
>
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev@mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
>
>
>
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
RE: [EXTERNAL] Re: ChaCha20 Rekey Frequency [ In reply to ]
Ah, with an internal block size [Is that what one calls it?] of 64 bytes.

From: Damien Miller <djm@mindrot.org>
Sent: Wednesday, March 29, 2023 3:08 PM
To: Robinson, Herbie <Herbie.Robinson@stratus.com>
Cc: Chris Rapier <rapier@psc.edu>; Christian Weisgerber <naddy@mips.inka.de>; openssh-unix-dev@mindrot.org
Subject: RE: [EXTERNAL] Re: ChaCha20 Rekey Frequency

[.EXTERNAL SENDER: This email originated from outside of Stratus Technologies. Do not click links or open attachments unless you recognize the sender and know the content is safe.]

That's true for block ciphers, but ChaCha20+poly1305 is a stream cipher.

On Wed, 29 Mar 2023, Robinson, Herbie wrote:

>
> I'm hardly an expert on this, but if I remember correctly, the rekey rate
> for good security is mostly dependent on the cipher block size. I left my
> reference books at home; so, I can't come up with a reference for you, but I
> would take Chris' "I'm deeply unsure of what impact that would have on the
> security of the cipher" comment seriously and switch to a cipher with a 128
> bit block length (AES or Camelia).
>
>
>
> From: openssh-unix-dev
> <openssh-unix-dev-bounces+herbie.robinson=stratus.com@mindrot.org<mailto:openssh-unix-dev-bounces+herbie.robinson=stratus.com@mindrot.org>> On Behalf
> Of Damien Miller
> Sent: Wednesday, March 29, 2023 2:38 PM
> To: Chris Rapier <rapier@psc.edu<mailto:rapier@psc.edu>>
> Cc: Christian Weisgerber <naddy@mips.inka.de<mailto:naddy@mips.inka.de>>; openssh-unix-dev@mindrot.org<mailto:openssh-unix-dev@mindrot.org>
> Subject: [EXTERNAL] Re: ChaCha20 Rekey Frequency
>
>
>
> [.EXTERNAL SENDER: This email originated from outside of Stratus
> Technologies. Do not click links or open attachments unless you recognize
> the sender and know the content is safe.]
>
> On Wed, 29 Mar 2023, Chris Rapier wrote:
>
> > I was wondering if there was something specific to the internal chacha20
> > cipher as opposed to OpenSSL implementation.
> >
> > I can't just change the block size because it breaks compatibility. I can
> do
> > something like as a hack (though it would probably be better to do it with
> the
> > compat function):
> >
> > if (strstr(enc->name, "chacha"))
> > *max_blocks = (u_int64_t)1 << (16*2);
> > else if (enc->block_size >= 16)
> > *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> > else
> > *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> > if (state->rekey_limit)
> >
> > to force it to reduce the rekey rate but I'm deeply unsure of what impact
> that
> > would have on the security of the cipher as it's implemented. Especially
> the
> > without-openssl internal implementation.
>
> This is what I'm playing with at the moment:
>
> diff --git a/cipher.c b/cipher.c
> index c7664a3..ec6fa4f 100644
> --- a/cipher.c
> +++ b/cipher.c
> @@ -150,6 +150,39 @@ cipher_blocksize(const struct sshcipher *c)
> return (c->block_size);
> }
>
> +uint64_t
> +cipher_rekey_blocks(const struct sshcipher *c)
> +{
> + /*
> + * Chacha20-Poly1305 does not benefit from data-based rekeying,
> + * per "The Security of ChaCha20-Poly1305 in the Multi-user Setting",
> + * Degabriele, J. P., Govinden, J, Gunther, F. and Paterson K.
> + * ACM CCS 2021; https://eprint.iacr.org/2023/085.pdf<https://eprint.iacr.org/2023/085.pdf>
> + *
> + * Cryptanalysis aside, we do still want do need to prevent the SSH
> + * sequence number wrapping and also to rekey to provide some
> + * protection for long lived sessions against key disclosure at the
> + * endpoints, so arrange for rekeying every 2**32 blocks as the
> + * 128-bit block ciphers do (i.e. every 32GB data).
> + */
> + if ((c->flags & CFLAG_CHACHAPOLY) != 0)
> + return (uint64_t)1 << 32;
> + /*
> + * The 2^(blocksize*2) limit is too expensive for 3DES,
> + * so enforce a 1GB data limit for small blocksizes.
> + * See discussion in RFC4344 section 3.2.
> + */
> + if (c->block_size < 16)
> + return ((uint64_t)1 << 30) / c->block_size;
> + /*
> + * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
> + * before rekeying where L is the blocksize in bits.
> + * Most other ciphers have a 128 bit blocksize, so this equates to
> + * 2**32 blocks / 64GB data.
> + */
> + return (uint64_t)1 << (c->block_size * 2);
> +}
> +
> u_int
> cipher_keylen(const struct sshcipher *c)
> {
> diff --git a/cipher.h b/cipher.h
> index 1a591cd..68be9ed 100644
> --- a/cipher.h
> +++ b/cipher.h
> @@ -63,6 +63,7 @@ int cipher_get_length(struct sshcipher_ctx *, u_int *,
> u_int,
> const u_char *, u_int);
> void cipher_free(struct sshcipher_ctx *);
> u_int cipher_blocksize(const struct sshcipher *);
> +uint64_t cipher_rekey_blocks(const struct sshcipher *);
> u_int cipher_keylen(const struct sshcipher *);
> u_int cipher_seclen(const struct sshcipher *);
> u_int cipher_authlen(const struct sshcipher *);
> diff --git a/packet.c b/packet.c
> index a71820f..377f608 100644
> --- a/packet.c
> +++ b/packet.c
> @@ -55,6 +55,7 @@
> #include <poll.h>
> #include <signal.h>
> #include <time.h>
> +#include <util.h>
>
> #ifdef WITH_ZLIB
> #include <zlib.h>
> @@ -850,6 +851,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
> const char *wmsg;
> int r, crypt_type;
> const char *dir = mode == MODE_OUT ? "out" : "in";
> + char blocks_s[FMT_SCALED_STRSIZE], bytes_s[FMT_SCALED_STRSIZE];
>
> debug2_f("mode %d", mode);
>
> @@ -917,20 +919,18 @@ ssh_set_newkeys(struct ssh *ssh, int mode)
> }
> comp->enabled = 1;
> }
> - /*
> - * The 2^(blocksize*2) limit is too expensive for 3DES,
> - * so enforce a 1GB limit for small blocksizes.
> - * See RFC4344 section 3.2.
> - */
> - if (enc->block_size >= 16)
> - *max_blocks = (u_int64_t)1 << (enc->block_size*2);
> - else
> - *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
> + *max_blocks = cipher_rekey_blocks(enc->cipher);
> if (state->rekey_limit)
> *max_blocks = MINIMUM(*max_blocks,
> state->rekey_limit / enc->block_size);
> - debug("rekey %s after %llu blocks", dir,
> - (unsigned long long)*max_blocks);
> +
> + strlcpy(blocks_s, "?", sizeof(blocks_s));
> + strlcpy(bytes_s, "?", sizeof(bytes_s));
> + if (*max_blocks * enc->block_size < LLONG_MAX) {
> + fmt_scaled((long long)*max_blocks, blocks_s);
> + fmt_scaled((long long)*max_blocks * enc->block_size, bytes_s);
> + }
> + debug("rekey %s after %s blocks / %sB data", dir, blocks_s, bytes_s);
> return 0;
> }
>
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev@mindrot.org<mailto:openssh-unix-dev@mindrot.org>
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev<https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>
>
>
>
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
Hi Damien,

>This is what I'm playing with at the moment:

if you’re playing with this currently anyway, shouldn’t…

>+ /*
>+ * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
>+ * before rekeying where L is the blocksize in bits.
>+ * Most other ciphers have a 128 bit blocksize, so this equates to
>+ * 2**32 blocks / 64GB data.
>+ */
>+ return (uint64_t)1 << (c->block_size * 2);

… this get an upper bound? This is UB for 256-bit blocksizes
at least…

bye,
//mirabilos
--
Infrastrukturexperte • tarent solutions GmbH
Am Dickobskreuz 10, D-53121 Bonn • http://www.tarent.de/
Telephon +49 228 54881-393 • Fax: +49 228 54881-235
HRB AG Bonn 5168 • USt-ID (VAT): DE122264941
Geschäftsführer: Dr. Stefan Barth, Kai Ebenrett, Boris Esser, Alexander Steeg

****************************************************
/?\ The UTF-8 Ribbon
? ? Campaign against Mit dem tarent-Newsletter nichts mehr verpassen:
 ?  HTML eMail! Also, https://www.tarent.de/newsletter
? ? header encryption!
****************************************************
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
RE: [EXTERNAL] Re: ChaCha20 Rekey Frequency [ In reply to ]
On Wed, 29 Mar 2023, Robinson, Herbie wrote:

>
> Ah, with an internal block size [Is that what one calls it?] of 64 bytes.

The "block size" in SSH terms is mostly an artifact of the SSH protocol
being designed around (mostly) block ciphers, with mandatory padding etc.

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
On Wed, 29 Mar 2023, Thorsten Glaser wrote:

> Hi Damien,
>
> >This is what I'm playing with at the moment:
>
> if you’re playing with this currently anyway, shouldn’t…
>
> >+ /*
> >+ * Otherwise, use the RFC4344 s3.2 recommendation of 2**(L/4) blocks
> >+ * before rekeying where L is the blocksize in bits.
> >+ * Most other ciphers have a 128 bit blocksize, so this equates to
> >+ * 2**32 blocks / 64GB data.
> >+ */
> >+ return (uint64_t)1 << (c->block_size * 2);
>
> … this get an upper bound? This is UB for 256-bit blocksizes
> at least…

block sizes in struct sshcipher are in bytes, not bits
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
On Thu, 30 Mar 2023, Damien Miller wrote:

>> >+ return (uint64_t)1 << (c->block_size * 2);
>>
>> … this get an upper bound? This is UB for 256-bit blocksizes
>> at least…
>
>block sizes in struct sshcipher are in bytes, not bits

Yes, exactly.

256 bit = 32 bytes; 32*2 = 64; (uint64_t)1 << 64 is UB.

bye,
//mirabilos
--
Infrastrukturexperte • tarent solutions GmbH
Am Dickobskreuz 10, D-53121 Bonn • http://www.tarent.de/
Telephon +49 228 54881-393 • Fax: +49 228 54881-235
HRB AG Bonn 5168 • USt-ID (VAT): DE122264941
Geschäftsführer: Dr. Stefan Barth, Kai Ebenrett, Boris Esser, Alexander Steeg

****************************************************
/?\ The UTF-8 Ribbon
? ? Campaign against Mit dem tarent-Newsletter nichts mehr verpassen:
 ?  HTML eMail! Also, https://www.tarent.de/newsletter
? ? header encryption!
****************************************************
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: ChaCha20 Rekey Frequency [ In reply to ]
On Thu, 30 Mar 2023, Thorsten Glaser wrote:

> On Thu, 30 Mar 2023, Damien Miller wrote:
>
> >> >+ return (uint64_t)1 << (c->block_size * 2);
> >>
> >> … this get an upper bound? This is UB for 256-bit blocksizes
> >> at least…
> >
> >block sizes in struct sshcipher are in bytes, not bits
>
> Yes, exactly.
>
> 256 bit = 32 bytes; 32*2 = 64; (uint64_t)1 << 64 is UB.

oops yes

there are no 256-bit block ciphers specified for SSH anyway and none are
likely to be specified any time soon; wide block ciphers are rare outside
of storage encryption
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev