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_hsalsa20.h"
10 #include "crypto_onetimeauth_poly1305.h"
11 #include "crypto_secretbox.h"
12 #include "crypto_stream_salsa20.h"
13 #include "private/common.h"
14 #include "utils.h"
15 
16 int
17 crypto_secretbox_detached(unsigned char *c, unsigned char *mac,
18                           const unsigned char *m,
19                           unsigned long long mlen, const unsigned char *n,
20                           const unsigned char *k)
21 {
22     crypto_onetimeauth_poly1305_state state;
23     unsigned char                     block0[64U];
24     unsigned char                     subkey[crypto_stream_salsa20_KEYBYTES];
25     unsigned long long                i;
26     unsigned long long                mlen0;
27 
28     crypto_core_hsalsa20(subkey, n, k, NULL);
29 
30     if (((uintptr_t) c > (uintptr_t) m &&
31          (uintptr_t) c - (uintptr_t) m < mlen) ||
32         ((uintptr_t) m > (uintptr_t) c &&
33          (uintptr_t) m - (uintptr_t) c < mlen)) { /* LCOV_EXCL_LINE */
34         memmove(c, m, mlen);
35         m = c;
36     }
37     memset(block0, 0U, crypto_secretbox_ZEROBYTES);
38     COMPILER_ASSERT(64U >= crypto_secretbox_ZEROBYTES);
39     mlen0 = mlen;
40     if (mlen0 > 64U - crypto_secretbox_ZEROBYTES) {
41         mlen0 = 64U - crypto_secretbox_ZEROBYTES;
42     }
43     for (i = 0U; i < mlen0; i++) {
44         block0[i + crypto_secretbox_ZEROBYTES] = m[i];
45     }
46     crypto_stream_salsa20_xor(block0, block0,
47                               mlen0 + crypto_secretbox_ZEROBYTES,
48                               n + 16, subkey);
49     COMPILER_ASSERT(crypto_secretbox_ZEROBYTES >=
50                     crypto_onetimeauth_poly1305_KEYBYTES);
51     crypto_onetimeauth_poly1305_init(&state, block0);
52 
53     for (i = 0U; i < mlen0; i++) {
54         c[i] = block0[crypto_secretbox_ZEROBYTES + i];
55     }
56     sodium_memzero(block0, sizeof block0);
57     if (mlen > mlen0) {
58         crypto_stream_salsa20_xor_ic(c + mlen0, m + mlen0, mlen - mlen0,
59                                      n + 16, 1U, subkey);
60     }
61     sodium_memzero(subkey, sizeof subkey);
62 
63     crypto_onetimeauth_poly1305_update(&state, c, mlen);
64     crypto_onetimeauth_poly1305_final(&state, mac);
65     sodium_memzero(&state, sizeof state);
66 
67     return 0;
68 }
69 
70 int
71 crypto_secretbox_easy(unsigned char *c, const unsigned char *m,
72                       unsigned long long mlen, const unsigned char *n,
73                       const unsigned char *k)
74 {
75     if (mlen > crypto_secretbox_MESSAGEBYTES_MAX) {
76         sodium_misuse();
77     }
78     return crypto_secretbox_detached(c + crypto_secretbox_MACBYTES,
79                                      c, m, mlen, n, k);
80 }
81 
82 int
83 crypto_secretbox_open_detached(unsigned char *m, const unsigned char *c,
84                                const unsigned char *mac,
85                                unsigned long long clen,
86                                const unsigned char *n,
87                                const unsigned char *k)
88 {
89     unsigned char      block0[64U];
90     unsigned char      subkey[crypto_stream_salsa20_KEYBYTES];
91     unsigned long long i;
92     unsigned long long mlen0;
93 
94     crypto_core_hsalsa20(subkey, n, k, NULL);
95     crypto_stream_salsa20(block0, crypto_stream_salsa20_KEYBYTES,
96                           n + 16, subkey);
97     if (crypto_onetimeauth_poly1305_verify(mac, c, clen, block0) != 0) {
98         sodium_memzero(subkey, sizeof subkey);
99         return -1;
100     }
101     if (m == NULL) {
102         return 0;
103     }
104     if (((uintptr_t) c >= (uintptr_t) m &&
105          (uintptr_t) c - (uintptr_t) m < clen) ||
106         ((uintptr_t) m >= (uintptr_t) c &&
107          (uintptr_t) m - (uintptr_t) c < clen)) { /* LCOV_EXCL_LINE */
108         memmove(m, c, clen);
109         c = m;
110     }
111     mlen0 = clen;
112     if (mlen0 > 64U - crypto_secretbox_ZEROBYTES) {
113         mlen0 = 64U - crypto_secretbox_ZEROBYTES;
114     }
115     for (i = 0U; i < mlen0; i++) {
116         block0[crypto_secretbox_ZEROBYTES + i] = c[i];
117     }
118     crypto_stream_salsa20_xor(block0, block0,
119                               crypto_secretbox_ZEROBYTES + mlen0,
120                               n + 16, subkey);
121     for (i = 0U; i < mlen0; i++) {
122         m[i] = block0[i + crypto_secretbox_ZEROBYTES];
123     }
124     if (clen > mlen0) {
125         crypto_stream_salsa20_xor_ic(m + mlen0, c + mlen0, clen - mlen0,
126                                      n + 16, 1U, subkey);
127     }
128     sodium_memzero(subkey, sizeof subkey);
129 
130     return 0;
131 }
132 
133 int
134 crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c,
135                            unsigned long long clen, const unsigned char *n,
136                            const unsigned char *k)
137 {
138     if (clen < crypto_secretbox_MACBYTES) {
139         return -1;
140     }
141     return crypto_secretbox_open_detached(m, c + crypto_secretbox_MACBYTES, c,
142                                           clen - crypto_secretbox_MACBYTES,
143                                           n, k);
144 }
145