9a6620ce45bef2baa64be45a419bcb850aa9d7c6
[tinc] / src / chacha-poly1305 / chachapoly.c
1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2015 Grigori Goronzy <goronzy@kinoho.net>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdint.h>
28 #include <assert.h>
29
30 #include "chachapoly.h"
31
32 /**
33  * Constant-time memory compare. This should help to protect against
34  * side-channel attacks.
35  *
36  * \param av input 1
37  * \param bv input 2
38  * \param n bytes to compare
39  * \return 0 if inputs are equal
40  */
41 static int memcmp_eq(const void *av, const void *bv, int n) {
42         const unsigned char *a = (const unsigned char *) av;
43         const unsigned char *b = (const unsigned char *) bv;
44         unsigned char res = 0;
45         int i;
46
47         for(i = 0; i < n; i++) {
48                 res |= *a ^ *b;
49                 a++;
50                 b++;
51         }
52
53         return res;
54 }
55
56 /**
57  * Poly1305 tag generation. This concatenates a string according to the rules
58  * outlined in RFC 7539 and calculates the tag.
59  *
60  * \param poly_key 32 byte secret one-time key for poly1305
61  * \param ad associated data
62  * \param ad_len associated data length in bytes
63  * \param ct ciphertext
64  * \param ct_len ciphertext length in bytes
65  * \param tag pointer to 16 bytes for tag storage
66  */
67 static void poly1305_get_tag(unsigned char *poly_key, const void *ad,
68                              int ad_len, const void *ct, int ct_len, unsigned char *tag) {
69         struct poly1305_context poly;
70         unsigned left_over;
71         uint64_t len;
72         unsigned char pad[16];
73
74         poly1305_init(&poly, poly_key);
75         memset(&pad, 0, sizeof(pad));
76
77         /* associated data and padding */
78         poly1305_update(&poly, ad, ad_len);
79         left_over = ad_len % 16;
80
81         if(left_over) {
82                 poly1305_update(&poly, pad, 16 - left_over);
83         }
84
85         /* payload and padding */
86         poly1305_update(&poly, ct, ct_len);
87         left_over = ct_len % 16;
88
89         if(left_over) {
90                 poly1305_update(&poly, pad, 16 - left_over);
91         }
92
93         /* lengths */
94         len = ad_len;
95         poly1305_update(&poly, (unsigned char *)&len, 8);
96         len = ct_len;
97         poly1305_update(&poly, (unsigned char *)&len, 8);
98
99         poly1305_finish(&poly, tag);
100 }
101
102 int chachapoly_init(struct chachapoly_ctx *ctx, const void *key, int key_len) {
103         assert(key_len == 128 || key_len == 256);
104
105         memset(ctx, 0, sizeof(*ctx));
106         chacha_keysetup(&ctx->cha_ctx, key, key_len);
107         return CHACHAPOLY_OK;
108 }
109
110 int chachapoly_crypt(struct chachapoly_ctx *ctx, const void *nonce,
111                      const void *ad, int ad_len, void *input, int input_len,
112                      void *output, void *tag, int tag_len, int encrypt) {
113         unsigned char poly_key[CHACHA_BLOCKLEN];
114         unsigned char calc_tag[POLY1305_TAGLEN];
115         const unsigned char one[4] = { 1, 0, 0, 0 };
116
117         /* initialize keystream and generate poly1305 key */
118         memset(poly_key, 0, sizeof(poly_key));
119         chacha_ivsetup(&ctx->cha_ctx, nonce, NULL);
120         chacha_encrypt_bytes(&ctx->cha_ctx, poly_key, poly_key, sizeof(poly_key));
121
122         /* check tag if decrypting */
123         if(encrypt == 0 && tag_len) {
124                 poly1305_get_tag(poly_key, ad, ad_len, input, input_len, calc_tag);
125
126                 if(memcmp_eq(calc_tag, tag, tag_len) != 0) {
127                         return CHACHAPOLY_INVALID_MAC;
128                 }
129         }
130
131         /* crypt data */
132         chacha_ivsetup(&ctx->cha_ctx, nonce, one);
133         chacha_encrypt_bytes(&ctx->cha_ctx, (unsigned char *)input,
134                              (unsigned char *)output, input_len);
135
136         /* add tag if encrypting */
137         if(encrypt && tag_len) {
138                 poly1305_get_tag(poly_key, ad, ad_len, output, input_len, calc_tag);
139                 memcpy(tag, calc_tag, tag_len);
140         }
141
142         return CHACHAPOLY_OK;
143 }
144
145 int chachapoly_crypt_short(struct chachapoly_ctx *ctx, const void *nonce,
146                            const void *ad, int ad_len, void *input, int input_len,
147                            void *output, void *tag, int tag_len, int encrypt) {
148         unsigned char keystream[CHACHA_BLOCKLEN];
149         unsigned char calc_tag[POLY1305_TAGLEN];
150         int i;
151
152         assert(input_len <= 32);
153
154         /* initialize keystream and generate poly1305 key */
155         memset(keystream, 0, sizeof(keystream));
156         chacha_ivsetup(&ctx->cha_ctx, nonce, NULL);
157         chacha_encrypt_bytes(&ctx->cha_ctx, keystream, keystream,
158                              sizeof(keystream));
159
160         /* check tag if decrypting */
161         if(encrypt == 0 && tag_len) {
162                 poly1305_get_tag(keystream, ad, ad_len, input, input_len, calc_tag);
163
164                 if(memcmp_eq(calc_tag, tag, tag_len) != 0) {
165                         return CHACHAPOLY_INVALID_MAC;
166                 }
167         }
168
169         /* crypt data */
170         for(i = 0; i < input_len; i++) {
171                 ((unsigned char *)output)[i] =
172                         ((unsigned char *)input)[i] ^ keystream[32 + i];
173         }
174
175         /* add tag if encrypting */
176         if(encrypt && tag_len) {
177                 poly1305_get_tag(keystream, ad, ad_len, output, input_len, calc_tag);
178                 memcpy(tag, calc_tag, tag_len);
179         }
180
181         return CHACHAPOLY_OK;
182 }