Update copyright year
[openssl.git] / providers / implementations / ciphers / cipher_chacha20_poly1305_hw.c
1 /*
2  * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 /* chacha20_poly1305 cipher implementation */
11
12 #include "internal/endian.h"
13 #include "cipher_chacha20_poly1305.h"
14
15 static int chacha_poly1305_tls_init(PROV_CIPHER_CTX *bctx,
16                                     unsigned char *aad, size_t alen)
17 {
18     unsigned int len;
19     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
20
21     if (alen != EVP_AEAD_TLS1_AAD_LEN)
22         return 0;
23
24     memcpy(ctx->tls_aad, aad, EVP_AEAD_TLS1_AAD_LEN);
25     len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 | aad[EVP_AEAD_TLS1_AAD_LEN - 1];
26     aad = ctx->tls_aad;
27     if (!bctx->enc) {
28         if (len < POLY1305_BLOCK_SIZE)
29             return 0;
30         len -= POLY1305_BLOCK_SIZE; /* discount attached tag */
31         aad[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);
32         aad[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;
33     }
34     ctx->tls_payload_length = len;
35
36     /* merge record sequence number as per RFC7905 */
37     ctx->chacha.counter[1] = ctx->nonce[0];
38     ctx->chacha.counter[2] = ctx->nonce[1] ^ CHACHA_U8TOU32(aad);
39     ctx->chacha.counter[3] = ctx->nonce[2] ^ CHACHA_U8TOU32(aad+4);
40     ctx->mac_inited = 0;
41
42     return POLY1305_BLOCK_SIZE;         /* tag length */
43 }
44
45 static int chacha_poly1305_tls_iv_set_fixed(PROV_CIPHER_CTX *bctx,
46                                             unsigned char *fixed, size_t flen)
47 {
48     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
49
50     if (flen != CHACHA20_POLY1305_IVLEN)
51         return 0;
52     ctx->nonce[0] = ctx->chacha.counter[1] = CHACHA_U8TOU32(fixed);
53     ctx->nonce[1] = ctx->chacha.counter[2] = CHACHA_U8TOU32(fixed + 4);
54     ctx->nonce[2] = ctx->chacha.counter[3] = CHACHA_U8TOU32(fixed + 8);
55     return 1;
56 }
57
58
59 static int chacha20_poly1305_initkey(PROV_CIPHER_CTX *bctx,
60                                      const unsigned char *key, size_t keylen)
61 {
62     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
63
64     ctx->len.aad = 0;
65     ctx->len.text = 0;
66     ctx->aad = 0;
67     ctx->mac_inited = 0;
68     ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
69
70     if (bctx->enc)
71         return ossl_chacha20_einit(&ctx->chacha, key, keylen, NULL, 0);
72     else
73         return ossl_chacha20_dinit(&ctx->chacha, key, keylen, NULL, 0);
74 }
75
76 static int chacha20_poly1305_initiv(PROV_CIPHER_CTX *bctx)
77 {
78     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
79     unsigned char tempiv[CHACHA_CTR_SIZE] = { 0 };
80     int ret = 1;
81
82     ctx->len.aad = 0;
83     ctx->len.text = 0;
84     ctx->aad = 0;
85     ctx->mac_inited = 0;
86     ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
87
88         /* pad on the left */
89     if (ctx->nonce_len <= CHACHA_CTR_SIZE) {
90             memcpy(tempiv + CHACHA_CTR_SIZE - ctx->nonce_len, bctx->oiv,
91                    ctx->nonce_len);
92
93         if (bctx->enc)
94             ret = ossl_chacha20_einit(&ctx->chacha, NULL, 0,
95                                       tempiv, sizeof(tempiv));
96         else
97             ret = ossl_chacha20_dinit(&ctx->chacha, NULL, 0,
98                                       tempiv, sizeof(tempiv));
99         ctx->nonce[0] = ctx->chacha.counter[1];
100         ctx->nonce[1] = ctx->chacha.counter[2];
101         ctx->nonce[2] = ctx->chacha.counter[3];
102         bctx->iv_set = 1;
103     }
104     return ret;
105 }
106
107 #if !defined(OPENSSL_SMALL_FOOTPRINT)
108
109 # if defined(POLY1305_ASM) && (defined(__x86_64) || defined(__x86_64__) \
110      || defined(_M_AMD64) || defined(_M_X64))
111 #  define XOR128_HELPERS
112 void *xor128_encrypt_n_pad(void *out, const void *inp, void *otp, size_t len);
113 void *xor128_decrypt_n_pad(void *out, const void *inp, void *otp, size_t len);
114 static const unsigned char zero[4 * CHACHA_BLK_SIZE] = { 0 };
115 # else
116 static const unsigned char zero[2 * CHACHA_BLK_SIZE] = { 0 };
117 # endif
118
119 static int chacha20_poly1305_tls_cipher(PROV_CIPHER_CTX *bctx,
120                                         unsigned char *out,
121                                         size_t *out_padlen,
122                                         const unsigned char *in, size_t len)
123 {
124     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
125     POLY1305 *poly = &ctx->poly1305;
126     size_t tail, tohash_len, buf_len, plen = ctx->tls_payload_length;
127     unsigned char *buf, *tohash, *ctr, storage[sizeof(zero) + 32];
128
129     DECLARE_IS_ENDIAN;
130
131     buf = storage + ((0 - (size_t)storage) & 15);   /* align */
132     ctr = buf + CHACHA_BLK_SIZE;
133     tohash = buf + CHACHA_BLK_SIZE - POLY1305_BLOCK_SIZE;
134
135 # ifdef XOR128_HELPERS
136     if (plen <= 3 * CHACHA_BLK_SIZE) {
137         ctx->chacha.counter[0] = 0;
138         buf_len = (plen + 2 * CHACHA_BLK_SIZE - 1) & (0 - CHACHA_BLK_SIZE);
139         ChaCha20_ctr32(buf, zero, buf_len, ctx->chacha.key.d, ctx->chacha.counter);
140         Poly1305_Init(poly, buf);
141         ctx->chacha.partial_len = 0;
142         memcpy(tohash, ctx->tls_aad, POLY1305_BLOCK_SIZE);
143         tohash_len = POLY1305_BLOCK_SIZE;
144         ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
145         ctx->len.text = plen;
146
147         if (plen) {
148             if (bctx->enc)
149                 ctr = xor128_encrypt_n_pad(out, in, ctr, plen);
150             else
151                 ctr = xor128_decrypt_n_pad(out, in, ctr, plen);
152
153             in += plen;
154             out += plen;
155             tohash_len = (size_t)(ctr - tohash);
156         }
157     }
158 # else
159     if (plen <= CHACHA_BLK_SIZE) {
160         size_t i;
161
162         ctx->chacha.counter[0] = 0;
163         ChaCha20_ctr32(buf, zero, (buf_len = 2 * CHACHA_BLK_SIZE),
164                        ctx->chacha.key.d, ctx->chacha.counter);
165         Poly1305_Init(poly, buf);
166         ctx->chacha.partial_len = 0;
167         memcpy(tohash, ctx->tls_aad, POLY1305_BLOCK_SIZE);
168         tohash_len = POLY1305_BLOCK_SIZE;
169         ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
170         ctx->len.text = plen;
171
172         if (bctx->enc) {
173             for (i = 0; i < plen; i++)
174                 out[i] = ctr[i] ^= in[i];
175         } else {
176             for (i = 0; i < plen; i++) {
177                 unsigned char c = in[i];
178
179                 out[i] = ctr[i] ^ c;
180                 ctr[i] = c;
181             }
182         }
183
184         in += i;
185         out += i;
186
187         tail = (0 - i) & (POLY1305_BLOCK_SIZE - 1);
188         memset(ctr + i, 0, tail);
189         ctr += i + tail;
190         tohash_len += i + tail;
191     }
192 # endif
193     else {
194         ctx->chacha.counter[0] = 0;
195         ChaCha20_ctr32(buf, zero, (buf_len = CHACHA_BLK_SIZE),
196                        ctx->chacha.key.d, ctx->chacha.counter);
197         Poly1305_Init(poly, buf);
198         ctx->chacha.counter[0] = 1;
199         ctx->chacha.partial_len = 0;
200         Poly1305_Update(poly, ctx->tls_aad, POLY1305_BLOCK_SIZE);
201         tohash = ctr;
202         tohash_len = 0;
203         ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
204         ctx->len.text = plen;
205
206         if (bctx->enc) {
207             ChaCha20_ctr32(out, in, plen, ctx->chacha.key.d, ctx->chacha.counter);
208             Poly1305_Update(poly, out, plen);
209         } else {
210             Poly1305_Update(poly, in, plen);
211             ChaCha20_ctr32(out, in, plen, ctx->chacha.key.d, ctx->chacha.counter);
212         }
213
214         in += plen;
215         out += plen;
216         tail = (0 - plen) & (POLY1305_BLOCK_SIZE - 1);
217         Poly1305_Update(poly, zero, tail);
218     }
219
220     if (IS_LITTLE_ENDIAN) {
221         memcpy(ctr, (unsigned char *)&ctx->len, POLY1305_BLOCK_SIZE);
222     } else {
223         ctr[0]  = (unsigned char)(ctx->len.aad);
224         ctr[1]  = (unsigned char)(ctx->len.aad>>8);
225         ctr[2]  = (unsigned char)(ctx->len.aad>>16);
226         ctr[3]  = (unsigned char)(ctx->len.aad>>24);
227         ctr[4]  = (unsigned char)(ctx->len.aad>>32);
228         ctr[5]  = (unsigned char)(ctx->len.aad>>40);
229         ctr[6]  = (unsigned char)(ctx->len.aad>>48);
230         ctr[7]  = (unsigned char)(ctx->len.aad>>56);
231
232         ctr[8]  = (unsigned char)(ctx->len.text);
233         ctr[9]  = (unsigned char)(ctx->len.text>>8);
234         ctr[10] = (unsigned char)(ctx->len.text>>16);
235         ctr[11] = (unsigned char)(ctx->len.text>>24);
236         ctr[12] = (unsigned char)(ctx->len.text>>32);
237         ctr[13] = (unsigned char)(ctx->len.text>>40);
238         ctr[14] = (unsigned char)(ctx->len.text>>48);
239         ctr[15] = (unsigned char)(ctx->len.text>>56);
240     }
241     tohash_len += POLY1305_BLOCK_SIZE;
242
243     Poly1305_Update(poly, tohash, tohash_len);
244     OPENSSL_cleanse(buf, buf_len);
245     Poly1305_Final(poly, bctx->enc ? ctx->tag : tohash);
246
247     ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
248
249     if (bctx->enc) {
250         memcpy(out, ctx->tag, POLY1305_BLOCK_SIZE);
251     } else {
252         if (CRYPTO_memcmp(tohash, in, POLY1305_BLOCK_SIZE)) {
253             if (len > POLY1305_BLOCK_SIZE)
254                 memset(out - (len - POLY1305_BLOCK_SIZE), 0,
255                        len - POLY1305_BLOCK_SIZE);
256             return 0;
257         }
258         /* Strip the tag */
259         len -= POLY1305_BLOCK_SIZE;
260     }
261
262     *out_padlen = len;
263     return 1;
264 }
265 #else
266 static const unsigned char zero[CHACHA_BLK_SIZE] = { 0 };
267 #endif /* OPENSSL_SMALL_FOOTPRINT */
268
269 static int chacha20_poly1305_aead_cipher(PROV_CIPHER_CTX *bctx,
270                                          unsigned char *out, size_t *outl,
271                                          const unsigned char *in, size_t inl)
272 {
273     PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)bctx;
274     POLY1305 *poly = &ctx->poly1305;
275     size_t rem, plen = ctx->tls_payload_length;
276     size_t olen = 0;
277     int rv = 0;
278
279     DECLARE_IS_ENDIAN;
280
281     if (!ctx->mac_inited) {
282         if (plen != NO_TLS_PAYLOAD_LENGTH && out != NULL) {
283             if (inl != plen + POLY1305_BLOCK_SIZE)
284                 return 0;
285 #if !defined(OPENSSL_SMALL_FOOTPRINT)
286             return chacha20_poly1305_tls_cipher(bctx, out, outl, in, inl);
287 #endif
288         }
289
290         ctx->chacha.counter[0] = 0;
291         ChaCha20_ctr32(ctx->chacha.buf, zero, CHACHA_BLK_SIZE,
292                        ctx->chacha.key.d, ctx->chacha.counter);
293         Poly1305_Init(poly, ctx->chacha.buf);
294         ctx->chacha.counter[0] = 1;
295         ctx->chacha.partial_len = 0;
296         ctx->len.aad = ctx->len.text = 0;
297         ctx->mac_inited = 1;
298         if (plen != NO_TLS_PAYLOAD_LENGTH) {
299             Poly1305_Update(poly, ctx->tls_aad, EVP_AEAD_TLS1_AAD_LEN);
300             ctx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
301             ctx->aad = 1;
302         }
303     }
304
305     if (in != NULL) { /* aad or text */
306         if (out == NULL) { /* aad */
307             Poly1305_Update(poly, in, inl);
308             ctx->len.aad += inl;
309             ctx->aad = 1;
310             goto finish;
311         } else { /* plain- or ciphertext */
312             if (ctx->aad) { /* wrap up aad */
313                 if ((rem = (size_t)ctx->len.aad % POLY1305_BLOCK_SIZE))
314                     Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem);
315                 ctx->aad = 0;
316             }
317
318             ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
319             if (plen == NO_TLS_PAYLOAD_LENGTH)
320                 plen = inl;
321             else if (inl != plen + POLY1305_BLOCK_SIZE)
322                 goto err;
323
324             if (bctx->enc) { /* plaintext */
325                 ctx->chacha.base.hw->cipher(&ctx->chacha.base, out, in, plen);
326                 Poly1305_Update(poly, out, plen);
327                 in += plen;
328                 out += plen;
329                 ctx->len.text += plen;
330             } else { /* ciphertext */
331                 Poly1305_Update(poly, in, plen);
332                 ctx->chacha.base.hw->cipher(&ctx->chacha.base, out, in, plen);
333                 in += plen;
334                 out += plen;
335                 ctx->len.text += plen;
336             }
337         }
338     }
339     /* explicit final, or tls mode */
340     if (in == NULL || inl != plen) {
341
342         unsigned char temp[POLY1305_BLOCK_SIZE];
343
344         if (ctx->aad) {                        /* wrap up aad */
345             if ((rem = (size_t)ctx->len.aad % POLY1305_BLOCK_SIZE))
346                 Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem);
347             ctx->aad = 0;
348         }
349
350         if ((rem = (size_t)ctx->len.text % POLY1305_BLOCK_SIZE))
351             Poly1305_Update(poly, zero, POLY1305_BLOCK_SIZE - rem);
352
353         if (IS_LITTLE_ENDIAN) {
354             Poly1305_Update(poly, (unsigned char *)&ctx->len,
355                             POLY1305_BLOCK_SIZE);
356         } else {
357             temp[0]  = (unsigned char)(ctx->len.aad);
358             temp[1]  = (unsigned char)(ctx->len.aad>>8);
359             temp[2]  = (unsigned char)(ctx->len.aad>>16);
360             temp[3]  = (unsigned char)(ctx->len.aad>>24);
361             temp[4]  = (unsigned char)(ctx->len.aad>>32);
362             temp[5]  = (unsigned char)(ctx->len.aad>>40);
363             temp[6]  = (unsigned char)(ctx->len.aad>>48);
364             temp[7]  = (unsigned char)(ctx->len.aad>>56);
365             temp[8]  = (unsigned char)(ctx->len.text);
366             temp[9]  = (unsigned char)(ctx->len.text>>8);
367             temp[10] = (unsigned char)(ctx->len.text>>16);
368             temp[11] = (unsigned char)(ctx->len.text>>24);
369             temp[12] = (unsigned char)(ctx->len.text>>32);
370             temp[13] = (unsigned char)(ctx->len.text>>40);
371             temp[14] = (unsigned char)(ctx->len.text>>48);
372             temp[15] = (unsigned char)(ctx->len.text>>56);
373             Poly1305_Update(poly, temp, POLY1305_BLOCK_SIZE);
374         }
375         Poly1305_Final(poly, bctx->enc ? ctx->tag : temp);
376         ctx->mac_inited = 0;
377
378         if (in != NULL && inl != plen) {
379             if (bctx->enc) {
380                 memcpy(out, ctx->tag, POLY1305_BLOCK_SIZE);
381             } else {
382                 if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {
383                     memset(out - plen, 0, plen);
384                     goto err;
385                 }
386                 /* Strip the tag */
387                 inl -= POLY1305_BLOCK_SIZE;
388             }
389         }
390         else if (!bctx->enc) {
391             if (CRYPTO_memcmp(temp, ctx->tag, ctx->tag_len))
392                 goto err;
393         }
394     }
395 finish:
396     olen = inl;
397     rv = 1;
398 err:
399     *outl = olen;
400     return rv;
401 }
402
403 static const PROV_CIPHER_HW_CHACHA20_POLY1305 chacha20poly1305_hw =
404 {
405     { chacha20_poly1305_initkey, NULL },
406     chacha20_poly1305_aead_cipher,
407     chacha20_poly1305_initiv,
408     chacha_poly1305_tls_init,
409     chacha_poly1305_tls_iv_set_fixed
410 };
411
412 const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20_poly1305(size_t keybits)
413 {
414     return (PROV_CIPHER_HW *)&chacha20poly1305_hw;
415 }