]> git.meshlink.io Git - meshlink/blob - src/chacha-poly1305/chacha-poly1305.c
Fix potential incorrect destruction of channels.
[meshlink] / src / chacha-poly1305 / chacha-poly1305.c
1 #include "../system.h"
2
3 #include "../xalloc.h"
4
5 #include "chacha.h"
6 #include "chacha-poly1305.h"
7 #include "poly1305.h"
8
9 struct chacha_poly1305_ctx {
10         struct chacha_ctx main_ctx, header_ctx;
11 };
12
13 chacha_poly1305_ctx_t *chacha_poly1305_init(void)
14 {
15         chacha_poly1305_ctx_t *ctx = xzalloc(sizeof *ctx);
16         return ctx;
17 }
18
19 void chacha_poly1305_exit(chacha_poly1305_ctx_t *ctx)
20 {
21         free(ctx);
22 }
23
24 bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key)
25 {
26         chacha_keysetup(&ctx->main_ctx, key, 256);
27         chacha_keysetup(&ctx->header_ctx, (uint8_t *)key + 32, 256);
28         return true;
29 }
30
31 static void put_u64(void *vp, uint64_t v)
32 {
33         uint8_t *p = (uint8_t *) vp;
34
35         p[0] = (uint8_t) (v >> 56) & 0xff;
36         p[1] = (uint8_t) (v >> 48) & 0xff;
37         p[2] = (uint8_t) (v >> 40) & 0xff;
38         p[3] = (uint8_t) (v >> 32) & 0xff;
39         p[4] = (uint8_t) (v >> 24) & 0xff;
40         p[5] = (uint8_t) (v >> 16) & 0xff;
41         p[6] = (uint8_t) (v >> 8) & 0xff;
42         p[7] = (uint8_t) v & 0xff;
43 }
44
45 bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
46         uint8_t seqbuf[8];
47         const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };      /* NB little-endian */
48         uint8_t poly_key[POLY1305_KEYLEN];
49
50         /*
51          * Run ChaCha20 once to generate the Poly1305 key. The IV is the
52          * packet sequence number.
53          */
54         memset(poly_key, 0, sizeof(poly_key));
55         put_u64(seqbuf, seqnr);
56         chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
57         chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
58
59         /* Set Chacha's block counter to 1 */
60         chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
61
62         chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
63         poly1305_auth((uint8_t *)outdata + inlen, outdata, inlen, poly_key);
64
65         if (outlen)
66                 *outlen = inlen + POLY1305_TAGLEN;
67
68         return true;
69 }
70
71 bool chacha_poly1305_verify(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen) {
72         uint8_t seqbuf[8];
73         uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
74
75         /*
76          * Run ChaCha20 once to generate the Poly1305 key. The IV is the
77          * packet sequence number.
78          */
79         memset(poly_key, 0, sizeof(poly_key));
80         put_u64(seqbuf, seqnr);
81         chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
82         chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
83
84         /* Check tag before anything else */
85         inlen -= POLY1305_TAGLEN;
86         const uint8_t *tag = (const uint8_t *)indata + inlen;
87
88         poly1305_auth(expected_tag, indata, inlen, poly_key);
89         if (memcmp(expected_tag, tag, POLY1305_TAGLEN))
90                 return false;
91
92         return true;
93 }
94
95 bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
96         uint8_t seqbuf[8];
97         const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };      /* NB little-endian */
98         uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
99
100         /*
101          * Run ChaCha20 once to generate the Poly1305 key. The IV is the
102          * packet sequence number.
103          */
104         memset(poly_key, 0, sizeof(poly_key));
105         put_u64(seqbuf, seqnr);
106         chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
107         chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
108
109         /* Set Chacha's block counter to 1 */
110         chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
111
112         /* Check tag before anything else */
113         inlen -= POLY1305_TAGLEN;
114         const uint8_t *tag = (const uint8_t *)indata + inlen;
115
116         poly1305_auth(expected_tag, indata, inlen, poly_key);
117         if (memcmp(expected_tag, tag, POLY1305_TAGLEN))
118                 return false;
119
120         chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
121
122         if (outlen)
123                 *outlen = inlen;
124
125         return true;
126 }
127
128 bool chacha_poly1305_encrypt_iv96(chacha_poly1305_ctx_t *ctx, const uint8_t *seqbuf, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
129         const uint8_t one[4] = { 1, 0, 0, 0 };  /* NB little-endian */
130         uint8_t poly_key[POLY1305_KEYLEN];
131
132         /*
133          * Run ChaCha20 once to generate the Poly1305 key. The IV is the
134          * packet sequence number.
135          */
136         memset(poly_key, 0, sizeof(poly_key));
137         chacha_ivsetup_96(&ctx->main_ctx, seqbuf, NULL);
138         chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
139
140         /* Set Chacha's block counter to 1 */
141         chacha_ivsetup_96(&ctx->main_ctx, seqbuf, one);
142
143         chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
144         poly1305_auth((uint8_t *)outdata + inlen, outdata, inlen, poly_key);
145
146         if (outlen)
147                 *outlen = inlen + POLY1305_TAGLEN;
148
149         return true;
150 }
151
152 bool chacha_poly1305_decrypt_iv96(chacha_poly1305_ctx_t *ctx, const uint8_t *seqbuf, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
153         const uint8_t one[4] = { 1, 0, 0, 0 };  /* NB little-endian */
154         uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
155
156         /*
157          * Run ChaCha20 once to generate the Poly1305 key. The IV is the
158          * packet sequence number.
159          */
160         memset(poly_key, 0, sizeof(poly_key));
161         chacha_ivsetup_96(&ctx->main_ctx, seqbuf, NULL);
162         chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
163
164         /* Set Chacha's block counter to 1 */
165         chacha_ivsetup_96(&ctx->main_ctx, seqbuf, one);
166
167         /* Check tag before anything else */
168         inlen -= POLY1305_TAGLEN;
169         const uint8_t *tag = (const uint8_t *)indata + inlen;
170
171         poly1305_auth(expected_tag, indata, inlen, poly_key);
172         if (memcmp(expected_tag, tag, POLY1305_TAGLEN))
173                 return false;
174
175         chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
176
177         if (outlen)
178                 *outlen = inlen;
179
180         return true;
181 }