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 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 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 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 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 156 crypto_secretbox_xchacha20poly1305_keybytes(void) 157 { 158 return crypto_secretbox_xchacha20poly1305_KEYBYTES; 159 } 160 161 size_t 162 crypto_secretbox_xchacha20poly1305_noncebytes(void) 163 { 164 return crypto_secretbox_xchacha20poly1305_NONCEBYTES; 165 } 166 167 size_t 168 crypto_secretbox_xchacha20poly1305_macbytes(void) 169 { 170 return crypto_secretbox_xchacha20poly1305_MACBYTES; 171 } 172 173 size_t 174 crypto_secretbox_xchacha20poly1305_messagebytes_max(void) 175 { 176 return crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX; 177 } 178