diff options
author | Eric Biggers <ebiggers@google.com> | 2018-11-16 20:26:18 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-11-20 01:26:55 -0500 |
commit | dd333449d0fb667c5250c42488a7e90470e16c77 (patch) | |
tree | 4377def3ee5095c9d866430d20cffcabbe7f90fd | |
parent | 3d234b3313cd12157946522fe35f5a4574f31169 (diff) |
crypto: chacha20-generic - add HChaCha20 library function
Refactor the unkeyed permutation part of chacha20_block() into its own
function, then add hchacha20_block() which is the ChaCha equivalent of
HSalsa20 and is an intermediate step towards XChaCha20 (see
https://cr.yp.to/snuffle/xsalsa-20081128.pdf). HChaCha20 skips the
final addition of the initial state, and outputs only certain words of
the state. It should not be used for streaming directly.
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Martin Willi <martin@strongswan.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | include/crypto/chacha20.h | 2 | ||||
-rw-r--r-- | lib/chacha20.c | 50 |
2 files changed, 46 insertions, 6 deletions
diff --git a/include/crypto/chacha20.h b/include/crypto/chacha20.h index 2d3129442a52..56073814eef0 100644 --- a/include/crypto/chacha20.h +++ b/include/crypto/chacha20.h | |||
@@ -20,6 +20,8 @@ struct chacha20_ctx { | |||
20 | }; | 20 | }; |
21 | 21 | ||
22 | void chacha20_block(u32 *state, u8 *stream); | 22 | void chacha20_block(u32 *state, u8 *stream); |
23 | void hchacha20_block(const u32 *in, u32 *out); | ||
24 | |||
23 | void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv); | 25 | void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv); |
24 | int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, | 26 | int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, |
25 | unsigned int keysize); | 27 | unsigned int keysize); |
diff --git a/lib/chacha20.c b/lib/chacha20.c index d907fec6a9ed..6a484e16171d 100644 --- a/lib/chacha20.c +++ b/lib/chacha20.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * ChaCha20 256-bit cipher algorithm, RFC7539 | 2 | * The "hash function" used as the core of the ChaCha20 stream cipher (RFC7539) |
3 | * | 3 | * |
4 | * Copyright (C) 2015 Martin Willi | 4 | * Copyright (C) 2015 Martin Willi |
5 | * | 5 | * |
@@ -16,14 +16,10 @@ | |||
16 | #include <asm/unaligned.h> | 16 | #include <asm/unaligned.h> |
17 | #include <crypto/chacha20.h> | 17 | #include <crypto/chacha20.h> |
18 | 18 | ||
19 | void chacha20_block(u32 *state, u8 *stream) | 19 | static void chacha20_permute(u32 *x) |
20 | { | 20 | { |
21 | u32 x[16]; | ||
22 | int i; | 21 | int i; |
23 | 22 | ||
24 | for (i = 0; i < ARRAY_SIZE(x); i++) | ||
25 | x[i] = state[i]; | ||
26 | |||
27 | for (i = 0; i < 20; i += 2) { | 23 | for (i = 0; i < 20; i += 2) { |
28 | x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16); | 24 | x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16); |
29 | x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16); | 25 | x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16); |
@@ -65,6 +61,25 @@ void chacha20_block(u32 *state, u8 *stream) | |||
65 | x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7); | 61 | x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7); |
66 | x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7); | 62 | x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7); |
67 | } | 63 | } |
64 | } | ||
65 | |||
66 | /** | ||
67 | * chacha20_block - generate one keystream block and increment block counter | ||
68 | * @state: input state matrix (16 32-bit words) | ||
69 | * @stream: output keystream block (64 bytes) | ||
70 | * | ||
71 | * This is the ChaCha20 core, a function from 64-byte strings to 64-byte | ||
72 | * strings. The caller has already converted the endianness of the input. This | ||
73 | * function also handles incrementing the block counter in the input matrix. | ||
74 | */ | ||
75 | void chacha20_block(u32 *state, u8 *stream) | ||
76 | { | ||
77 | u32 x[16]; | ||
78 | int i; | ||
79 | |||
80 | memcpy(x, state, 64); | ||
81 | |||
82 | chacha20_permute(x); | ||
68 | 83 | ||
69 | for (i = 0; i < ARRAY_SIZE(x); i++) | 84 | for (i = 0; i < ARRAY_SIZE(x); i++) |
70 | put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); | 85 | put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); |
@@ -72,3 +87,26 @@ void chacha20_block(u32 *state, u8 *stream) | |||
72 | state[12]++; | 87 | state[12]++; |
73 | } | 88 | } |
74 | EXPORT_SYMBOL(chacha20_block); | 89 | EXPORT_SYMBOL(chacha20_block); |
90 | |||
91 | /** | ||
92 | * hchacha20_block - abbreviated ChaCha20 core, for XChaCha20 | ||
93 | * @in: input state matrix (16 32-bit words) | ||
94 | * @out: output (8 32-bit words) | ||
95 | * | ||
96 | * HChaCha20 is the ChaCha equivalent of HSalsa20 and is an intermediate step | ||
97 | * towards XChaCha20 (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf). | ||
98 | * HChaCha20 skips the final addition of the initial state, and outputs only | ||
99 | * certain words of the state. It should not be used for streaming directly. | ||
100 | */ | ||
101 | void hchacha20_block(const u32 *in, u32 *out) | ||
102 | { | ||
103 | u32 x[16]; | ||
104 | |||
105 | memcpy(x, in, 64); | ||
106 | |||
107 | chacha20_permute(x); | ||
108 | |||
109 | memcpy(&out[0], &x[0], 16); | ||
110 | memcpy(&out[4], &x[12], 16); | ||
111 | } | ||
112 | EXPORT_SYMBOL(hchacha20_block); | ||