summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2020-03-09 13:01:18 +0100
committerNiels Möller <nisse@lysator.liu.se>2020-03-09 19:09:18 +0100
commit2176ccc158d220f2884a10980266899c495b77be (patch)
treeb911b0287da426c48957d6c47c125c8c697e1126
parenta9894036fc5e3c972d751ea28e64e23ddc77fc37 (diff)
downloadnettle-2176ccc158d220f2884a10980266899c495b77be.tar.gz
chacha: add variant that treats counter value as 32-bit
The ChaCha-Poly1305 implementation previously used the chacha_crypt function that assumes the block counter is 64-bit long, while RFC 8439 defines that the counter is 32-bit long. Although this should be fine as long as up to 256 gigabytes of data is encrypted with the same key, it would be nice to use a separate functions (chacha_set_counter32 and chacha_crypt32) that assume the counter is 32-bit long. Signed-off-by: Daiki Ueno <dueno@redhat.com>
-rw-r--r--chacha-crypt.c32
-rw-r--r--chacha-poly1305.c4
-rw-r--r--chacha-set-nonce.c6
-rw-r--r--chacha.h10
-rw-r--r--nettle.texinfo31
-rw-r--r--testsuite/chacha-test.c34
6 files changed, 111 insertions, 6 deletions
diff --git a/chacha-crypt.c b/chacha-crypt.c
index 63d799ce..0bb44ed9 100644
--- a/chacha-crypt.c
+++ b/chacha-crypt.c
@@ -85,3 +85,35 @@ chacha_crypt(struct chacha_ctx *ctx,
m += CHACHA_BLOCK_SIZE;
}
}
+
+void
+chacha_crypt32(struct chacha_ctx *ctx,
+ size_t length,
+ uint8_t *c,
+ const uint8_t *m)
+{
+ if (!length)
+ return;
+
+ for (;;)
+ {
+ uint32_t x[_CHACHA_STATE_LENGTH];
+
+ _chacha_core (x, ctx->state, CHACHA_ROUNDS);
+
+ ++ctx->state[12];
+
+ /* stopping at 2^70 length per nonce is user's responsibility */
+
+ if (length <= CHACHA_BLOCK_SIZE)
+ {
+ memxor3 (c, m, x, length);
+ return;
+ }
+ memxor3 (c, m, x, CHACHA_BLOCK_SIZE);
+
+ length -= CHACHA_BLOCK_SIZE;
+ c += CHACHA_BLOCK_SIZE;
+ m += CHACHA_BLOCK_SIZE;
+ }
+}
diff --git a/chacha-poly1305.c b/chacha-poly1305.c
index 974a5022..a15fef0c 100644
--- a/chacha-poly1305.c
+++ b/chacha-poly1305.c
@@ -130,7 +130,7 @@ chacha_poly1305_encrypt (struct chacha_poly1305_ctx *ctx,
assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0);
poly1305_pad (ctx);
- chacha_crypt (&ctx->chacha, length, dst, src);
+ chacha_crypt32 (&ctx->chacha, length, dst, src);
poly1305_update (ctx, length, dst);
ctx->data_size += length;
}
@@ -146,7 +146,7 @@ chacha_poly1305_decrypt (struct chacha_poly1305_ctx *ctx,
poly1305_pad (ctx);
poly1305_update (ctx, length, src);
- chacha_crypt (&ctx->chacha, length, dst, src);
+ chacha_crypt32 (&ctx->chacha, length, dst, src);
ctx->data_size += length;
}
diff --git a/chacha-set-nonce.c b/chacha-set-nonce.c
index 2c34e498..1547aea1 100644
--- a/chacha-set-nonce.c
+++ b/chacha-set-nonce.c
@@ -75,3 +75,9 @@ chacha_set_counter(struct chacha_ctx *ctx, const uint8_t *counter)
ctx->state[12] = LE_READ_UINT32(counter + 0);
ctx->state[13] = LE_READ_UINT32(counter + 4);
}
+
+void
+chacha_set_counter32(struct chacha_ctx *ctx, const uint8_t *counter)
+{
+ ctx->state[12] = LE_READ_UINT32(counter + 0);
+}
diff --git a/chacha.h b/chacha.h
index 440fe968..fe28b835 100644
--- a/chacha.h
+++ b/chacha.h
@@ -47,7 +47,9 @@ extern "C" {
#define chacha_set_nonce nettle_chacha_set_nonce
#define chacha_set_nonce96 nettle_chacha_set_nonce96
#define chacha_set_counter nettle_chacha_set_counter
+#define chacha_set_counter32 nettle_chacha_set_counter32
#define chacha_crypt nettle_chacha_crypt
+#define chacha_crypt32 nettle_chacha_crypt32
/* Currently, only 256-bit keys are supported. */
#define CHACHA_KEY_SIZE 32
@@ -55,6 +57,7 @@ extern "C" {
#define CHACHA_NONCE_SIZE 8
#define CHACHA_NONCE96_SIZE 12
#define CHACHA_COUNTER_SIZE 8
+#define CHACHA_COUNTER32_SIZE 4
#define _CHACHA_STATE_LENGTH 16
@@ -87,9 +90,16 @@ void
chacha_set_counter(struct chacha_ctx *ctx, const uint8_t *counter);
void
+chacha_set_counter32(struct chacha_ctx *ctx, const uint8_t *counter);
+
+void
chacha_crypt(struct chacha_ctx *ctx, size_t length,
uint8_t *dst, const uint8_t *src);
+void
+chacha_crypt32(struct chacha_ctx *ctx, size_t length,
+ uint8_t *dst, const uint8_t *src);
+
#ifdef __cplusplus
}
#endif
diff --git a/nettle.texinfo b/nettle.texinfo
index 0b339f51..fe44f6af 100644
--- a/nettle.texinfo
+++ b/nettle.texinfo
@@ -1700,6 +1700,37 @@ all but the last call @emph{must} use a length that is a multiple of
@code{CHACHA_BLOCK_SIZE}.
@end deftypefun
+@subsubsection 32-bit counter variant
+
+While the original paper uses 64-bit counter value, the variant defined
+in @cite{RFC 8439} uses 32-bit counter value. This variant is
+particularly useful for @pxref{ChaCha-Poly1305} AEAD construction, which
+supports 12-octet nonces.
+
+@defvr Constant CHACHA_NONCE96_SIZE
+Size of the nonce, 12.
+@end defvr
+
+@defvr Constant CHACHA_COUNTER32_SIZE
+Size of the counter, 4.
+@end defvr
+
+@deftypefun void chacha_set_nonce96 (struct chacha_ctx *@var{ctx}, const uint8_t *@var{nonce})
+Sets the nonce. This is similar to the above @code{chacha_set_nonce},
+but the input is always of size @code{CHACHA_NONCE96_SIZE}, 12 octets.
+@end deftypefun
+
+@deftypefun void chacha_set_counter32 (struct chacha_ctx *@var{ctx}, const uint8_t *@var{counter})
+Sets the block counter. This is similar to the above @code{chacha_set_counter},
+but the input is always of size @code{CHACHA_COUNTER32_SIZE}, 4 octets.
+@end deftypefun
+
+@deftypefun void chacha_crypt32 (struct chacha_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
+Encrypts or decrypts the data of a message, using ChaCha. This is similar to the
+above @code{chacha_crypt}, but it assumes the internal counter value is 32-bit
+long and the nonce is 96-bit long.
+@end deftypefun
+
@subsection DES
@cindex DES
DES is the old Data Encryption Standard, specified by NIST. It uses a
diff --git a/testsuite/chacha-test.c b/testsuite/chacha-test.c
index 6875d4bb..fb8f1db7 100644
--- a/testsuite/chacha-test.c
+++ b/testsuite/chacha-test.c
@@ -71,9 +71,23 @@ _test_chacha(const struct tstring *key, const struct tstring *nonce,
die ("Bad nonce size %u.\n", (unsigned) nonce->length);
if (counter)
- chacha_set_counter(&ctx, counter->data);
+ {
+ if (counter->length == CHACHA_COUNTER_SIZE)
+ {
+ ASSERT (nonce->length == CHACHA_NONCE_SIZE);
+ chacha_set_counter(&ctx, counter->data);
+ }
+ else if (counter->length == CHACHA_COUNTER32_SIZE)
+ {
+ ASSERT (nonce->length == CHACHA_NONCE96_SIZE);
+ chacha_set_counter32(&ctx, counter->data);
+ }
+ }
- chacha_crypt (&ctx, length, data, data);
+ if (nonce->length == CHACHA_NONCE_SIZE)
+ chacha_crypt (&ctx, length, data, data);
+ else
+ chacha_crypt32 (&ctx, length, data, data);
ASSERT (data[-1] == 17);
ASSERT (data[length] == 17);
@@ -666,8 +680,20 @@ test_main(void)
"b5129cd1de164eb9 cbd083e8a2503c4e"),
20);
- /* This is identical to the 96-bit nonce test, but it manually sets
- the counter value */
+ /* This is identical to the above 96-bit nonce test, but it manually
+ sets the 32-bit counter value */
+ test_chacha_with_counter(SHEX("0001020304050607 08090a0b0c0d0e0f"
+ "1011121314151617 18191a1b1c1d1e1f"),
+ SHEX("000000090000004a 00000000"),
+ SHEX("10f1e7e4d13b5915 500fdd1fa32071c4"
+ "c7d1f4c733c06803 0422aa9ac3d46c4e"
+ "d2826446079faa09 14c2d705d98b02a2"
+ "b5129cd1de164eb9 cbd083e8a2503c4e"),
+ 20,
+ SHEX("01000000"));
+
+ /* This is identical to the above 96-bit nonce test, but it manually
+ sets the 64-bit counter value */
test_chacha_with_counter(SHEX("0001020304050607 08090a0b0c0d0e0f"
"1011121314151617 18191a1b1c1d1e1f"),
SHEX("0000004a00000000"),