1 // SPDX-License-Identifier: GPL-2.0 OR MIT
3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5 * This is an implementation of the ChaCha20Poly1305 AEAD construction.
7 * Information: https://tools.ietf.org/html/rfc8439
10 #include <crypto/algapi.h>
11 #include <crypto/chacha20poly1305.h>
12 #include <crypto/chacha.h>
13 #include <crypto/poly1305.h>
14 #include <crypto/scatterwalk.h>
16 #include <asm/unaligned.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
20 #include <linux/module.h>
22 #define CHACHA_KEY_WORDS (CHACHA_KEY_SIZE / sizeof(u32))
24 static void chacha_load_key(u32
*k
, const u8
*in
)
26 k
[0] = get_unaligned_le32(in
);
27 k
[1] = get_unaligned_le32(in
+ 4);
28 k
[2] = get_unaligned_le32(in
+ 8);
29 k
[3] = get_unaligned_le32(in
+ 12);
30 k
[4] = get_unaligned_le32(in
+ 16);
31 k
[5] = get_unaligned_le32(in
+ 20);
32 k
[6] = get_unaligned_le32(in
+ 24);
33 k
[7] = get_unaligned_le32(in
+ 28);
36 static void xchacha_init(u32
*chacha_state
, const u8
*key
, const u8
*nonce
)
38 u32 k
[CHACHA_KEY_WORDS
];
39 u8 iv
[CHACHA_IV_SIZE
];
42 memcpy(iv
+ 8, nonce
+ 16, 8);
44 chacha_load_key(k
, key
);
46 /* Compute the subkey given the original key and first 128 nonce bits */
47 chacha_init(chacha_state
, k
, nonce
);
48 hchacha_block(chacha_state
, k
, 20);
50 chacha_init(chacha_state
, k
, iv
);
52 memzero_explicit(k
, sizeof(k
));
53 memzero_explicit(iv
, sizeof(iv
));
57 __chacha20poly1305_encrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
58 const u8
*ad
, const size_t ad_len
, u32
*chacha_state
)
60 const u8
*pad0
= page_address(ZERO_PAGE(0));
61 struct poly1305_desc_ctx poly1305_state
;
63 u8 block0
[POLY1305_KEY_SIZE
];
67 chacha20_crypt(chacha_state
, b
.block0
, pad0
, sizeof(b
.block0
));
68 poly1305_init(&poly1305_state
, b
.block0
);
70 poly1305_update(&poly1305_state
, ad
, ad_len
);
72 poly1305_update(&poly1305_state
, pad0
, 0x10 - (ad_len
& 0xf));
74 chacha20_crypt(chacha_state
, dst
, src
, src_len
);
76 poly1305_update(&poly1305_state
, dst
, src_len
);
78 poly1305_update(&poly1305_state
, pad0
, 0x10 - (src_len
& 0xf));
80 b
.lens
[0] = cpu_to_le64(ad_len
);
81 b
.lens
[1] = cpu_to_le64(src_len
);
82 poly1305_update(&poly1305_state
, (u8
*)b
.lens
, sizeof(b
.lens
));
84 poly1305_final(&poly1305_state
, dst
+ src_len
);
86 memzero_explicit(chacha_state
, CHACHA_STATE_WORDS
* sizeof(u32
));
87 memzero_explicit(&b
, sizeof(b
));
90 void chacha20poly1305_encrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
91 const u8
*ad
, const size_t ad_len
,
93 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
95 u32 chacha_state
[CHACHA_STATE_WORDS
];
96 u32 k
[CHACHA_KEY_WORDS
];
99 chacha_load_key(k
, key
);
102 iv
[1] = cpu_to_le64(nonce
);
104 chacha_init(chacha_state
, k
, (u8
*)iv
);
105 __chacha20poly1305_encrypt(dst
, src
, src_len
, ad
, ad_len
, chacha_state
);
107 memzero_explicit(iv
, sizeof(iv
));
108 memzero_explicit(k
, sizeof(k
));
110 EXPORT_SYMBOL(chacha20poly1305_encrypt
);
112 void xchacha20poly1305_encrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
113 const u8
*ad
, const size_t ad_len
,
114 const u8 nonce
[XCHACHA20POLY1305_NONCE_SIZE
],
115 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
117 u32 chacha_state
[CHACHA_STATE_WORDS
];
119 xchacha_init(chacha_state
, key
, nonce
);
120 __chacha20poly1305_encrypt(dst
, src
, src_len
, ad
, ad_len
, chacha_state
);
122 EXPORT_SYMBOL(xchacha20poly1305_encrypt
);
125 __chacha20poly1305_decrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
126 const u8
*ad
, const size_t ad_len
, u32
*chacha_state
)
128 const u8
*pad0
= page_address(ZERO_PAGE(0));
129 struct poly1305_desc_ctx poly1305_state
;
133 u8 block0
[POLY1305_KEY_SIZE
];
134 u8 mac
[POLY1305_DIGEST_SIZE
];
138 if (unlikely(src_len
< POLY1305_DIGEST_SIZE
))
141 chacha20_crypt(chacha_state
, b
.block0
, pad0
, sizeof(b
.block0
));
142 poly1305_init(&poly1305_state
, b
.block0
);
144 poly1305_update(&poly1305_state
, ad
, ad_len
);
146 poly1305_update(&poly1305_state
, pad0
, 0x10 - (ad_len
& 0xf));
148 dst_len
= src_len
- POLY1305_DIGEST_SIZE
;
149 poly1305_update(&poly1305_state
, src
, dst_len
);
151 poly1305_update(&poly1305_state
, pad0
, 0x10 - (dst_len
& 0xf));
153 b
.lens
[0] = cpu_to_le64(ad_len
);
154 b
.lens
[1] = cpu_to_le64(dst_len
);
155 poly1305_update(&poly1305_state
, (u8
*)b
.lens
, sizeof(b
.lens
));
157 poly1305_final(&poly1305_state
, b
.mac
);
159 ret
= crypto_memneq(b
.mac
, src
+ dst_len
, POLY1305_DIGEST_SIZE
);
161 chacha20_crypt(chacha_state
, dst
, src
, dst_len
);
163 memzero_explicit(&b
, sizeof(b
));
168 bool chacha20poly1305_decrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
169 const u8
*ad
, const size_t ad_len
,
171 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
173 u32 chacha_state
[CHACHA_STATE_WORDS
];
174 u32 k
[CHACHA_KEY_WORDS
];
178 chacha_load_key(k
, key
);
181 iv
[1] = cpu_to_le64(nonce
);
183 chacha_init(chacha_state
, k
, (u8
*)iv
);
184 ret
= __chacha20poly1305_decrypt(dst
, src
, src_len
, ad
, ad_len
,
187 memzero_explicit(chacha_state
, sizeof(chacha_state
));
188 memzero_explicit(iv
, sizeof(iv
));
189 memzero_explicit(k
, sizeof(k
));
192 EXPORT_SYMBOL(chacha20poly1305_decrypt
);
194 bool xchacha20poly1305_decrypt(u8
*dst
, const u8
*src
, const size_t src_len
,
195 const u8
*ad
, const size_t ad_len
,
196 const u8 nonce
[XCHACHA20POLY1305_NONCE_SIZE
],
197 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
199 u32 chacha_state
[CHACHA_STATE_WORDS
];
201 xchacha_init(chacha_state
, key
, nonce
);
202 return __chacha20poly1305_decrypt(dst
, src
, src_len
, ad
, ad_len
,
205 EXPORT_SYMBOL(xchacha20poly1305_decrypt
);
208 bool chacha20poly1305_crypt_sg_inplace(struct scatterlist
*src
,
209 const size_t src_len
,
210 const u8
*ad
, const size_t ad_len
,
212 const u8 key
[CHACHA20POLY1305_KEY_SIZE
],
215 const u8
*pad0
= page_address(ZERO_PAGE(0));
216 struct poly1305_desc_ctx poly1305_state
;
217 u32 chacha_state
[CHACHA_STATE_WORDS
];
218 struct sg_mapping_iter miter
;
225 u32 k
[CHACHA_KEY_WORDS
];
228 u8 block0
[POLY1305_KEY_SIZE
];
229 u8 chacha_stream
[CHACHA_BLOCK_SIZE
];
231 u8 mac
[2][POLY1305_DIGEST_SIZE
];
236 if (WARN_ON(src_len
> INT_MAX
))
239 chacha_load_key(b
.k
, key
);
242 b
.iv
[1] = cpu_to_le64(nonce
);
244 chacha_init(chacha_state
, b
.k
, (u8
*)b
.iv
);
245 chacha20_crypt(chacha_state
, b
.block0
, pad0
, sizeof(b
.block0
));
246 poly1305_init(&poly1305_state
, b
.block0
);
248 if (unlikely(ad_len
)) {
249 poly1305_update(&poly1305_state
, ad
, ad_len
);
251 poly1305_update(&poly1305_state
, pad0
, 0x10 - (ad_len
& 0xf));
254 flags
= SG_MITER_TO_SG
| SG_MITER_ATOMIC
;
256 sg_miter_start(&miter
, src
, sg_nents(src
), flags
);
258 for (sl
= src_len
; sl
> 0 && sg_miter_next(&miter
); sl
-= miter
.length
) {
259 u8
*addr
= miter
.addr
;
260 size_t length
= min_t(size_t, sl
, miter
.length
);
263 poly1305_update(&poly1305_state
, addr
, length
);
265 if (unlikely(partial
)) {
266 size_t l
= min(length
, CHACHA_BLOCK_SIZE
- partial
);
268 crypto_xor(addr
, b
.chacha_stream
+ partial
, l
);
269 partial
= (partial
+ l
) & (CHACHA_BLOCK_SIZE
- 1);
275 if (likely(length
>= CHACHA_BLOCK_SIZE
|| length
== sl
)) {
278 if (unlikely(length
< sl
))
279 l
&= ~(CHACHA_BLOCK_SIZE
- 1);
280 chacha20_crypt(chacha_state
, addr
, addr
, l
);
285 if (unlikely(length
> 0)) {
286 chacha20_crypt(chacha_state
, b
.chacha_stream
, pad0
,
288 crypto_xor(addr
, b
.chacha_stream
, length
);
293 poly1305_update(&poly1305_state
, miter
.addr
,
294 min_t(size_t, sl
, miter
.length
));
298 poly1305_update(&poly1305_state
, pad0
, 0x10 - (src_len
& 0xf));
300 b
.lens
[0] = cpu_to_le64(ad_len
);
301 b
.lens
[1] = cpu_to_le64(src_len
);
302 poly1305_update(&poly1305_state
, (u8
*)b
.lens
, sizeof(b
.lens
));
304 if (likely(sl
<= -POLY1305_DIGEST_SIZE
)) {
306 poly1305_final(&poly1305_state
,
307 miter
.addr
+ miter
.length
+ sl
);
310 poly1305_final(&poly1305_state
, b
.mac
[0]);
311 ret
= !crypto_memneq(b
.mac
[0],
312 miter
.addr
+ miter
.length
+ sl
,
313 POLY1305_DIGEST_SIZE
);
317 sg_miter_stop(&miter
);
319 if (unlikely(sl
> -POLY1305_DIGEST_SIZE
)) {
320 poly1305_final(&poly1305_state
, b
.mac
[1]);
321 scatterwalk_map_and_copy(b
.mac
[encrypt
], src
, src_len
,
322 sizeof(b
.mac
[1]), encrypt
);
324 !crypto_memneq(b
.mac
[0], b
.mac
[1], POLY1305_DIGEST_SIZE
);
327 memzero_explicit(chacha_state
, sizeof(chacha_state
));
328 memzero_explicit(&b
, sizeof(b
));
333 bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist
*src
, size_t src_len
,
334 const u8
*ad
, const size_t ad_len
,
336 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
338 return chacha20poly1305_crypt_sg_inplace(src
, src_len
, ad
, ad_len
,
341 EXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace
);
343 bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist
*src
, size_t src_len
,
344 const u8
*ad
, const size_t ad_len
,
346 const u8 key
[CHACHA20POLY1305_KEY_SIZE
])
348 if (unlikely(src_len
< POLY1305_DIGEST_SIZE
))
351 return chacha20poly1305_crypt_sg_inplace(src
,
352 src_len
- POLY1305_DIGEST_SIZE
,
353 ad
, ad_len
, nonce
, key
, 0);
355 EXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace
);
357 static int __init
mod_init(void)
359 if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
) &&
360 WARN_ON(!chacha20poly1305_selftest()))
365 module_init(mod_init
);
366 MODULE_LICENSE("GPL v2");
367 MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction");
368 MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");