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
crypto_secretbox_detached(unsigned char * c,unsigned char * mac,const unsigned char * m,unsigned long long mlen,const unsigned char * n,const unsigned char * k)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
crypto_secretbox_easy(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,const unsigned char * k)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
crypto_secretbox_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)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
crypto_secretbox_open_easy(unsigned char * m,const unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)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