1 
2 #include <assert.h>
3 #include <limits.h>
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include "core.h"
9 #include "crypto_core_hchacha20.h"
10 #include "crypto_onetimeauth_poly1305.h"
11 #include "crypto_secretbox_xchacha20poly1305.h"
12 #include "crypto_stream_chacha20.h"
13 #include "private/common.h"
14 #include "utils.h"
15 
16 #define crypto_secretbox_xchacha20poly1305_ZEROBYTES 32U
17 
18 int
crypto_secretbox_xchacha20poly1305_detached(unsigned char * c,unsigned char * mac,const unsigned char * m,unsigned long long mlen,const unsigned char * n,const unsigned char * k)19 crypto_secretbox_xchacha20poly1305_detached(unsigned char *c,
20                                             unsigned char *mac,
21                                             const unsigned char *m,
22                                             unsigned long long mlen,
23                                             const unsigned char *n,
24                                             const unsigned char *k)
25 {
26     crypto_onetimeauth_poly1305_state state;
27     unsigned char                     block0[64U];
28     unsigned char                     subkey[crypto_stream_chacha20_KEYBYTES];
29     unsigned long long                i;
30     unsigned long long                mlen0;
31 
32     crypto_core_hchacha20(subkey, n, k, NULL);
33 
34     if (((uintptr_t) c > (uintptr_t) m &&
35          (uintptr_t) c - (uintptr_t) m < mlen) ||
36         ((uintptr_t) m > (uintptr_t) c &&
37          (uintptr_t) m - (uintptr_t) c < mlen)) { /* LCOV_EXCL_LINE */
38         memmove(c, m, mlen);
39         m = c;
40     }
41     memset(block0, 0U, crypto_secretbox_xchacha20poly1305_ZEROBYTES);
42     COMPILER_ASSERT(64U >= crypto_secretbox_xchacha20poly1305_ZEROBYTES);
43     mlen0 = mlen;
44     if (mlen0 > 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES) {
45         mlen0 = 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES;
46     }
47     for (i = 0U; i < mlen0; i++) {
48         block0[i + crypto_secretbox_xchacha20poly1305_ZEROBYTES] = m[i];
49     }
50     crypto_stream_chacha20_xor(block0, block0,
51                                mlen0 + crypto_secretbox_xchacha20poly1305_ZEROBYTES,
52                                n + 16, subkey);
53     COMPILER_ASSERT(crypto_secretbox_xchacha20poly1305_ZEROBYTES >=
54                     crypto_onetimeauth_poly1305_KEYBYTES);
55     crypto_onetimeauth_poly1305_init(&state, block0);
56 
57     for (i = 0U; i < mlen0; i++) {
58         c[i] = block0[crypto_secretbox_xchacha20poly1305_ZEROBYTES + i];
59     }
60     sodium_memzero(block0, sizeof block0);
61     if (mlen > mlen0) {
62         crypto_stream_chacha20_xor_ic(c + mlen0, m + mlen0, mlen - mlen0,
63                                       n + 16, 1U, subkey);
64     }
65     sodium_memzero(subkey, sizeof subkey);
66 
67     crypto_onetimeauth_poly1305_update(&state, c, mlen);
68     crypto_onetimeauth_poly1305_final(&state, mac);
69     sodium_memzero(&state, sizeof state);
70 
71     return 0;
72 }
73 
74 int
crypto_secretbox_xchacha20poly1305_easy(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,const unsigned char * k)75 crypto_secretbox_xchacha20poly1305_easy(unsigned char *c,
76                                         const unsigned char *m,
77                                         unsigned long long mlen,
78                                         const unsigned char *n,
79                                         const unsigned char *k)
80 {
81     if (mlen > crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX) {
82         sodium_misuse();
83     }
84     return crypto_secretbox_xchacha20poly1305_detached
85         (c + crypto_secretbox_xchacha20poly1305_MACBYTES, c, m, mlen, n, k);
86 }
87 
88 int
crypto_secretbox_xchacha20poly1305_open_detached(unsigned char * m,const unsigned char * c,const unsigned char * mac,unsigned long long clen,const unsigned char * n,const unsigned char * k)89 crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m,
90                                                  const unsigned char *c,
91                                                  const unsigned char *mac,
92                                                  unsigned long long clen,
93                                                  const unsigned char *n,
94                                                  const unsigned char *k)
95 {
96     unsigned char      block0[64U];
97     unsigned char      subkey[crypto_stream_chacha20_KEYBYTES];
98     unsigned long long i;
99     unsigned long long mlen0;
100 
101     crypto_core_hchacha20(subkey, n, k, NULL);
102     crypto_stream_chacha20(block0, crypto_stream_chacha20_KEYBYTES,
103                            n + 16, subkey);
104     if (crypto_onetimeauth_poly1305_verify(mac, c, clen, block0) != 0) {
105         sodium_memzero(subkey, sizeof subkey);
106         return -1;
107     }
108     if (m == NULL) {
109         return 0;
110     }
111     if (((uintptr_t) c >= (uintptr_t) m &&
112          (uintptr_t) c - (uintptr_t) m < clen) ||
113         ((uintptr_t) m >= (uintptr_t) c &&
114          (uintptr_t) m - (uintptr_t) c < clen)) { /* LCOV_EXCL_LINE */
115         memmove(m, c, clen);
116         c = m;
117     }
118     mlen0 = clen;
119     if (mlen0 > 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES) {
120         mlen0 = 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES;
121     }
122     for (i = 0U; i < mlen0; i++) {
123         block0[crypto_secretbox_xchacha20poly1305_ZEROBYTES + i] = c[i];
124     }
125     crypto_stream_chacha20_xor(block0, block0,
126                               crypto_secretbox_xchacha20poly1305_ZEROBYTES + mlen0,
127                               n + 16, subkey);
128     for (i = 0U; i < mlen0; i++) {
129         m[i] = block0[i + crypto_secretbox_xchacha20poly1305_ZEROBYTES];
130     }
131     if (clen > mlen0) {
132         crypto_stream_chacha20_xor_ic(m + mlen0, c + mlen0, clen - mlen0,
133                                       n + 16, 1U, subkey);
134     }
135     sodium_memzero(subkey, sizeof subkey);
136 
137     return 0;
138 }
139 
140 int
crypto_secretbox_xchacha20poly1305_open_easy(unsigned char * m,const unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)141 crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m,
142                                              const unsigned char *c,
143                                              unsigned long long clen,
144                                              const unsigned char *n,
145                                              const unsigned char *k)
146 {
147     if (clen < crypto_secretbox_xchacha20poly1305_MACBYTES) {
148         return -1;
149     }
150     return crypto_secretbox_xchacha20poly1305_open_detached
151         (m, c + crypto_secretbox_xchacha20poly1305_MACBYTES, c,
152          clen - crypto_secretbox_xchacha20poly1305_MACBYTES, n, k);
153 }
154 
155 size_t
crypto_secretbox_xchacha20poly1305_keybytes(void)156 crypto_secretbox_xchacha20poly1305_keybytes(void)
157 {
158     return crypto_secretbox_xchacha20poly1305_KEYBYTES;
159 }
160 
161 size_t
crypto_secretbox_xchacha20poly1305_noncebytes(void)162 crypto_secretbox_xchacha20poly1305_noncebytes(void)
163 {
164     return crypto_secretbox_xchacha20poly1305_NONCEBYTES;
165 }
166 
167 size_t
crypto_secretbox_xchacha20poly1305_macbytes(void)168 crypto_secretbox_xchacha20poly1305_macbytes(void)
169 {
170     return crypto_secretbox_xchacha20poly1305_MACBYTES;
171 }
172 
173 size_t
crypto_secretbox_xchacha20poly1305_messagebytes_max(void)174 crypto_secretbox_xchacha20poly1305_messagebytes_max(void)
175 {
176     return crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX;
177 }
178