1 
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <string.h>
6 
7 #include "core.h"
8 #include "crypto_aead_chacha20poly1305.h"
9 #include "crypto_aead_xchacha20poly1305.h"
10 #include "crypto_core_hchacha20.h"
11 #include "crypto_onetimeauth_poly1305.h"
12 #include "crypto_stream_chacha20.h"
13 #include "crypto_verify_16.h"
14 #include "randombytes.h"
15 #include "utils.h"
16 
17 #include "private/chacha20_ietf_ext.h"
18 #include "private/common.h"
19 
20 static const unsigned char _pad0[16] = { 0 };
crypto_aead_chacha20poly1305_encrypt_detached(unsigned char * c,unsigned char * mac,unsigned long long * maclen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)21 
22 static int
23 _encrypt_detached(unsigned char *c,
24                   unsigned char *mac,
25                   unsigned long long *maclen_p,
26                   const unsigned char *m,
27                   unsigned long long mlen,
28                   const unsigned char *ad,
29                   unsigned long long adlen,
30                   const unsigned char *nsec,
31                   const unsigned char *npub,
32                   const unsigned char *k)
33 {
34     crypto_onetimeauth_poly1305_state state;
35     unsigned char                     block0[64U];
36     unsigned char                     slen[8U];
37 
38     (void) nsec;
39     crypto_stream_chacha20_ietf_ext(block0, sizeof block0, npub, k);
40     crypto_onetimeauth_poly1305_init(&state, block0);
41     sodium_memzero(block0, sizeof block0);
42 
43     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
44     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
45 
46     crypto_stream_chacha20_ietf_ext_xor_ic(c, m, mlen, npub, 1U, k);
47 
48     crypto_onetimeauth_poly1305_update(&state, c, mlen);
49     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
50 
51     STORE64_LE(slen, (uint64_t) adlen);
52     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
53 
54     STORE64_LE(slen, (uint64_t) mlen);
55     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
56 
57     crypto_onetimeauth_poly1305_final(&state, mac);
58     sodium_memzero(&state, sizeof state);
59 
60     if (maclen_p != NULL) {
61         *maclen_p = crypto_aead_chacha20poly1305_ietf_ABYTES;
62     }
63     return 0;
64 }
65 
66 static int
67 _decrypt_detached(unsigned char *m,
68                   unsigned char *nsec,
69                   const unsigned char *c,
70                   unsigned long long clen,
71                   const unsigned char *mac,
72                   const unsigned char *ad,
73                   unsigned long long adlen,
74                   const unsigned char *npub,
75                   const unsigned char *k)
76 {
77     crypto_onetimeauth_poly1305_state state;
78     unsigned char                     block0[64U];
79     unsigned char                     slen[8U];
80     unsigned char                     computed_mac[crypto_aead_chacha20poly1305_ietf_ABYTES];
81     unsigned long long                mlen;
82     int                               ret;
83 
84     (void) nsec;
85     crypto_stream_chacha20_ietf_ext(block0, sizeof block0, npub, k);
86     crypto_onetimeauth_poly1305_init(&state, block0);
87     sodium_memzero(block0, sizeof block0);
88 
89     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
90     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
91 
crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char * c,unsigned char * mac,unsigned long long * maclen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)92     mlen = clen;
93     crypto_onetimeauth_poly1305_update(&state, c, mlen);
94     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
95 
96     STORE64_LE(slen, (uint64_t) adlen);
97     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
98 
99     STORE64_LE(slen, (uint64_t) mlen);
100     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
101 
102     crypto_onetimeauth_poly1305_final(&state, computed_mac);
103     sodium_memzero(&state, sizeof state);
104 
105     COMPILER_ASSERT(sizeof computed_mac == 16U);
106     ret = crypto_verify_16(computed_mac, mac);
107     sodium_memzero(computed_mac, sizeof computed_mac);
108     if (m == NULL) {
109         return ret;
110     }
111     if (ret != 0) {
112         memset(m, 0, mlen);
113         return -1;
114     }
115     crypto_stream_chacha20_ietf_ext_xor_ic(m, c, mlen, npub, 1U, k);
116 
117     return 0;
118 }
119 
120 int
121 crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c,
122                                                     unsigned char *mac,
123                                                     unsigned long long *maclen_p,
124                                                     const unsigned char *m,
125                                                     unsigned long long mlen,
126                                                     const unsigned char *ad,
127                                                     unsigned long long adlen,
128                                                     const unsigned char *nsec,
129                                                     const unsigned char *npub,
130                                                     const unsigned char *k)
131 {
132     unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES];
133     unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 };
134     int           ret;
135 
crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char * c,unsigned long long * clen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)136     crypto_core_hchacha20(k2, npub, k, NULL);
137     memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES,
138            crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4);
139     ret = _encrypt_detached(c, mac, maclen_p, m, mlen, ad, adlen,
140                             nsec, npub2, k2);
141     sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES);
142 
143     return ret;
144 }
145 
146 int
147 crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c,
148                                            unsigned long long *clen_p,
149                                            const unsigned char *m,
150                                            unsigned long long mlen,
151                                            const unsigned char *ad,
152                                            unsigned long long adlen,
153                                            const unsigned char *nsec,
154                                            const unsigned char *npub,
155                                            const unsigned char *k)
156 {
157     unsigned long long clen = 0ULL;
158     int                ret;
159 
160     if (mlen > crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX) {
161         sodium_misuse();
162     }
163     ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached
164         (c, c + mlen, NULL, m, mlen, ad, adlen, nsec, npub, k);
165     if (clen_p != NULL) {
166         if (ret == 0) {
crypto_aead_chacha20poly1305_decrypt_detached(unsigned char * m,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * mac,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)167             clen = mlen + crypto_aead_xchacha20poly1305_ietf_ABYTES;
168         }
169         *clen_p = clen;
170     }
171     return ret;
172 }
173 
174 int
175 crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m,
176                                                     unsigned char *nsec,
177                                                     const unsigned char *c,
178                                                     unsigned long long clen,
179                                                     const unsigned char *mac,
180                                                     const unsigned char *ad,
181                                                     unsigned long long adlen,
182                                                     const unsigned char *npub,
183                                                     const unsigned char *k)
184 {
185     unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES];
186     unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 };
187     int           ret;
188 
189     crypto_core_hchacha20(k2, npub, k, NULL);
190     memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES,
191            crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4);
192     ret = _decrypt_detached(m, nsec, c, clen, mac, ad, adlen, npub2, k2);
193     sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES);
194 
195     return ret;
196 }
197 
198 int
199 crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m,
200                                            unsigned long long *mlen_p,
201                                            unsigned char *nsec,
202                                            const unsigned char *c,
203                                            unsigned long long clen,
204                                            const unsigned char *ad,
205                                            unsigned long long adlen,
206                                            const unsigned char *npub,
207                                            const unsigned char *k)
208 {
209     unsigned long long mlen = 0ULL;
210     int                ret  = -1;
211 
212     if (clen >= crypto_aead_xchacha20poly1305_ietf_ABYTES) {
213         ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached
214             (m, nsec,
215              c, clen - crypto_aead_xchacha20poly1305_ietf_ABYTES,
216              c + clen - crypto_aead_xchacha20poly1305_ietf_ABYTES,
crypto_aead_chacha20poly1305_decrypt(unsigned char * m,unsigned long long * mlen_p,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)217              ad, adlen, npub, k);
218     }
219     if (mlen_p != NULL) {
220         if (ret == 0) {
221             mlen = clen - crypto_aead_xchacha20poly1305_ietf_ABYTES;
222         }
223         *mlen_p = mlen;
224     }
225     return ret;
226 }
227 
228 size_t
229 crypto_aead_xchacha20poly1305_ietf_keybytes(void)
230 {
231     return crypto_aead_xchacha20poly1305_ietf_KEYBYTES;
232 }
233 
234 size_t
235 crypto_aead_xchacha20poly1305_ietf_npubbytes(void)
236 {
237     return crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
238 }
239 
240 size_t
241 crypto_aead_xchacha20poly1305_ietf_nsecbytes(void)
242 {
243     return crypto_aead_xchacha20poly1305_ietf_NSECBYTES;
244 }
245 
246 size_t
crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char * m,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * mac,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)247 crypto_aead_xchacha20poly1305_ietf_abytes(void)
248 {
249     return crypto_aead_xchacha20poly1305_ietf_ABYTES;
250 }
251 
252 size_t
253 crypto_aead_xchacha20poly1305_ietf_messagebytes_max(void)
254 {
255     return crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX;
256 }
257 
258 void
259 crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES])
260 {
261     randombytes_buf(k, crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
262 }
263