1*0ac341f1SConrad Meyer #ifndef __STDC_WANT_LIB_EXT1__
2*0ac341f1SConrad Meyer # define __STDC_WANT_LIB_EXT1__ 1
3*0ac341f1SConrad Meyer #endif
4*0ac341f1SConrad Meyer #include <assert.h>
5*0ac341f1SConrad Meyer #include <errno.h>
6*0ac341f1SConrad Meyer #include <limits.h>
7*0ac341f1SConrad Meyer #include <signal.h>
8*0ac341f1SConrad Meyer #include <stddef.h>
9*0ac341f1SConrad Meyer #include <stdint.h>
10*0ac341f1SConrad Meyer #include <stdlib.h>
11*0ac341f1SConrad Meyer #include <string.h>
12*0ac341f1SConrad Meyer
13*0ac341f1SConrad Meyer #ifdef HAVE_SYS_MMAN_H
14*0ac341f1SConrad Meyer # include <sys/mman.h>
15*0ac341f1SConrad Meyer #endif
16*0ac341f1SConrad Meyer
17*0ac341f1SConrad Meyer #ifdef _WIN32
18*0ac341f1SConrad Meyer # include <windows.h>
19*0ac341f1SConrad Meyer # include <wincrypt.h>
20*0ac341f1SConrad Meyer #else
21*0ac341f1SConrad Meyer # include <unistd.h>
22*0ac341f1SConrad Meyer #endif
23*0ac341f1SConrad Meyer
24*0ac341f1SConrad Meyer #ifndef HAVE_C_VARARRAYS
25*0ac341f1SConrad Meyer # ifdef HAVE_ALLOCA_H
26*0ac341f1SConrad Meyer # include <alloca.h>
27*0ac341f1SConrad Meyer # elif !defined(alloca)
28*0ac341f1SConrad Meyer # if defined(__clang__) || defined(__GNUC__)
29*0ac341f1SConrad Meyer # define alloca __builtin_alloca
30*0ac341f1SConrad Meyer # elif defined _AIX
31*0ac341f1SConrad Meyer # define alloca __alloca
32*0ac341f1SConrad Meyer # elif defined _MSC_VER
33*0ac341f1SConrad Meyer # include <malloc.h>
34*0ac341f1SConrad Meyer # define alloca _alloca
35*0ac341f1SConrad Meyer # else
36*0ac341f1SConrad Meyer # include <stddef.h>
37*0ac341f1SConrad Meyer # ifdef __cplusplus
38*0ac341f1SConrad Meyer extern "C"
39*0ac341f1SConrad Meyer # endif
40*0ac341f1SConrad Meyer void *alloca (size_t);
41*0ac341f1SConrad Meyer # endif
42*0ac341f1SConrad Meyer # endif
43*0ac341f1SConrad Meyer #endif
44*0ac341f1SConrad Meyer
45*0ac341f1SConrad Meyer #include "core.h"
46*0ac341f1SConrad Meyer #include "randombytes.h"
47*0ac341f1SConrad Meyer #include "utils.h"
48*0ac341f1SConrad Meyer
49*0ac341f1SConrad Meyer #ifndef ENOSYS
50*0ac341f1SConrad Meyer # define ENOSYS ENXIO
51*0ac341f1SConrad Meyer #endif
52*0ac341f1SConrad Meyer
53*0ac341f1SConrad Meyer #if defined(_WIN32) && \
54*0ac341f1SConrad Meyer (!defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
55*0ac341f1SConrad Meyer # define WINAPI_DESKTOP
56*0ac341f1SConrad Meyer #endif
57*0ac341f1SConrad Meyer
58*0ac341f1SConrad Meyer #define CANARY_SIZE 16U
59*0ac341f1SConrad Meyer #define GARBAGE_VALUE 0xdb
60*0ac341f1SConrad Meyer
61*0ac341f1SConrad Meyer #ifndef MAP_NOCORE
62*0ac341f1SConrad Meyer # define MAP_NOCORE 0
63*0ac341f1SConrad Meyer #endif
64*0ac341f1SConrad Meyer #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
65*0ac341f1SConrad Meyer # define MAP_ANON MAP_ANONYMOUS
66*0ac341f1SConrad Meyer #endif
67*0ac341f1SConrad Meyer #if defined(WINAPI_DESKTOP) || (defined(MAP_ANON) && defined(HAVE_MMAP)) || \
68*0ac341f1SConrad Meyer defined(HAVE_POSIX_MEMALIGN)
69*0ac341f1SConrad Meyer # define HAVE_ALIGNED_MALLOC
70*0ac341f1SConrad Meyer #endif
71*0ac341f1SConrad Meyer #if defined(HAVE_MPROTECT) && \
72*0ac341f1SConrad Meyer !(defined(PROT_NONE) && defined(PROT_READ) && defined(PROT_WRITE))
73*0ac341f1SConrad Meyer # undef HAVE_MPROTECT
74*0ac341f1SConrad Meyer #endif
75*0ac341f1SConrad Meyer #if defined(HAVE_ALIGNED_MALLOC) && \
76*0ac341f1SConrad Meyer (defined(WINAPI_DESKTOP) || defined(HAVE_MPROTECT))
77*0ac341f1SConrad Meyer # define HAVE_PAGE_PROTECTION
78*0ac341f1SConrad Meyer #endif
79*0ac341f1SConrad Meyer #if !defined(MADV_DODUMP) && defined(MADV_CORE)
80*0ac341f1SConrad Meyer # define MADV_DODUMP MADV_CORE
81*0ac341f1SConrad Meyer # define MADV_DONTDUMP MADV_NOCORE
82*0ac341f1SConrad Meyer #endif
83*0ac341f1SConrad Meyer
84*0ac341f1SConrad Meyer static size_t page_size;
85*0ac341f1SConrad Meyer static unsigned char canary[CANARY_SIZE];
86*0ac341f1SConrad Meyer
87*0ac341f1SConrad Meyer /* LCOV_EXCL_START */
88*0ac341f1SConrad Meyer #ifdef HAVE_WEAK_SYMBOLS
89*0ac341f1SConrad Meyer __attribute__((weak)) void
90*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memzero_lto(void *const pnt,
91*0ac341f1SConrad Meyer const size_t len);
92*0ac341f1SConrad Meyer __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_memzero_lto(void * const pnt,const size_t len)93*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memzero_lto(void *const pnt,
94*0ac341f1SConrad Meyer const size_t len)
95*0ac341f1SConrad Meyer {
96*0ac341f1SConrad Meyer (void) pnt; /* LCOV_EXCL_LINE */
97*0ac341f1SConrad Meyer (void) len; /* LCOV_EXCL_LINE */
98*0ac341f1SConrad Meyer }
99*0ac341f1SConrad Meyer #endif
100*0ac341f1SConrad Meyer /* LCOV_EXCL_STOP */
101*0ac341f1SConrad Meyer
102*0ac341f1SConrad Meyer void
sodium_memzero(void * const pnt,const size_t len)103*0ac341f1SConrad Meyer sodium_memzero(void *const pnt, const size_t len)
104*0ac341f1SConrad Meyer {
105*0ac341f1SConrad Meyer #ifdef _WIN32
106*0ac341f1SConrad Meyer SecureZeroMemory(pnt, len);
107*0ac341f1SConrad Meyer #elif defined(HAVE_MEMSET_S)
108*0ac341f1SConrad Meyer if (len > 0U && memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) {
109*0ac341f1SConrad Meyer sodium_misuse(); /* LCOV_EXCL_LINE */
110*0ac341f1SConrad Meyer }
111*0ac341f1SConrad Meyer #elif defined(HAVE_EXPLICIT_BZERO)
112*0ac341f1SConrad Meyer explicit_bzero(pnt, len);
113*0ac341f1SConrad Meyer #elif HAVE_WEAK_SYMBOLS
114*0ac341f1SConrad Meyer memset(pnt, 0, len);
115*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memzero_lto(pnt, len);
116*0ac341f1SConrad Meyer # ifdef HAVE_INLINE_ASM
117*0ac341f1SConrad Meyer __asm__ __volatile__ ("" : : "r"(pnt) : "memory");
118*0ac341f1SConrad Meyer # endif
119*0ac341f1SConrad Meyer #else
120*0ac341f1SConrad Meyer volatile unsigned char *volatile pnt_ =
121*0ac341f1SConrad Meyer (volatile unsigned char *volatile) pnt;
122*0ac341f1SConrad Meyer size_t i = (size_t) 0U;
123*0ac341f1SConrad Meyer
124*0ac341f1SConrad Meyer while (i < len) {
125*0ac341f1SConrad Meyer pnt_[i++] = 0U;
126*0ac341f1SConrad Meyer }
127*0ac341f1SConrad Meyer #endif
128*0ac341f1SConrad Meyer }
129*0ac341f1SConrad Meyer
130*0ac341f1SConrad Meyer void
sodium_stackzero(const size_t len)131*0ac341f1SConrad Meyer sodium_stackzero(const size_t len)
132*0ac341f1SConrad Meyer {
133*0ac341f1SConrad Meyer #ifdef HAVE_C_VARARRAYS
134*0ac341f1SConrad Meyer unsigned char fodder[len];
135*0ac341f1SConrad Meyer sodium_memzero(fodder, len);
136*0ac341f1SConrad Meyer #elif HAVE_ALLOCA
137*0ac341f1SConrad Meyer sodium_memzero(alloca(len), len);
138*0ac341f1SConrad Meyer #endif
139*0ac341f1SConrad Meyer }
140*0ac341f1SConrad Meyer
141*0ac341f1SConrad Meyer #ifdef HAVE_WEAK_SYMBOLS
142*0ac341f1SConrad Meyer __attribute__((weak)) void
143*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1,
144*0ac341f1SConrad Meyer const unsigned char *b2,
145*0ac341f1SConrad Meyer const size_t len);
146*0ac341f1SConrad Meyer __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char * b1,const unsigned char * b2,const size_t len)147*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1,
148*0ac341f1SConrad Meyer const unsigned char *b2,
149*0ac341f1SConrad Meyer const size_t len)
150*0ac341f1SConrad Meyer {
151*0ac341f1SConrad Meyer (void) b1;
152*0ac341f1SConrad Meyer (void) b2;
153*0ac341f1SConrad Meyer (void) len;
154*0ac341f1SConrad Meyer }
155*0ac341f1SConrad Meyer #endif
156*0ac341f1SConrad Meyer
157*0ac341f1SConrad Meyer int
sodium_memcmp(const void * const b1_,const void * const b2_,size_t len)158*0ac341f1SConrad Meyer sodium_memcmp(const void *const b1_, const void *const b2_, size_t len)
159*0ac341f1SConrad Meyer {
160*0ac341f1SConrad Meyer #ifdef HAVE_WEAK_SYMBOLS
161*0ac341f1SConrad Meyer const unsigned char *b1 = (const unsigned char *) b1_;
162*0ac341f1SConrad Meyer const unsigned char *b2 = (const unsigned char *) b2_;
163*0ac341f1SConrad Meyer #else
164*0ac341f1SConrad Meyer const volatile unsigned char *volatile b1 =
165*0ac341f1SConrad Meyer (const volatile unsigned char *volatile) b1_;
166*0ac341f1SConrad Meyer const volatile unsigned char *volatile b2 =
167*0ac341f1SConrad Meyer (const volatile unsigned char *volatile) b2_;
168*0ac341f1SConrad Meyer #endif
169*0ac341f1SConrad Meyer size_t i;
170*0ac341f1SConrad Meyer volatile unsigned char d = 0U;
171*0ac341f1SConrad Meyer
172*0ac341f1SConrad Meyer #if HAVE_WEAK_SYMBOLS
173*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_memcmp_lto(b1, b2, len);
174*0ac341f1SConrad Meyer #endif
175*0ac341f1SConrad Meyer for (i = 0U; i < len; i++) {
176*0ac341f1SConrad Meyer d |= b1[i] ^ b2[i];
177*0ac341f1SConrad Meyer }
178*0ac341f1SConrad Meyer return (1 & ((d - 1) >> 8)) - 1;
179*0ac341f1SConrad Meyer }
180*0ac341f1SConrad Meyer
181*0ac341f1SConrad Meyer #ifdef HAVE_WEAK_SYMBOLS
182*0ac341f1SConrad Meyer __attribute__((weak)) void
183*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1,
184*0ac341f1SConrad Meyer const unsigned char *b2,
185*0ac341f1SConrad Meyer const size_t len);
186*0ac341f1SConrad Meyer __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char * b1,const unsigned char * b2,const size_t len)187*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1,
188*0ac341f1SConrad Meyer const unsigned char *b2,
189*0ac341f1SConrad Meyer const size_t len)
190*0ac341f1SConrad Meyer {
191*0ac341f1SConrad Meyer (void) b1;
192*0ac341f1SConrad Meyer (void) b2;
193*0ac341f1SConrad Meyer (void) len;
194*0ac341f1SConrad Meyer }
195*0ac341f1SConrad Meyer #endif
196*0ac341f1SConrad Meyer
197*0ac341f1SConrad Meyer int
sodium_compare(const unsigned char * b1_,const unsigned char * b2_,size_t len)198*0ac341f1SConrad Meyer sodium_compare(const unsigned char *b1_, const unsigned char *b2_, size_t len)
199*0ac341f1SConrad Meyer {
200*0ac341f1SConrad Meyer #ifdef HAVE_WEAK_SYMBOLS
201*0ac341f1SConrad Meyer const unsigned char *b1 = b1_;
202*0ac341f1SConrad Meyer const unsigned char *b2 = b2_;
203*0ac341f1SConrad Meyer #else
204*0ac341f1SConrad Meyer const volatile unsigned char *volatile b1 =
205*0ac341f1SConrad Meyer (const volatile unsigned char *volatile) b1_;
206*0ac341f1SConrad Meyer const volatile unsigned char *volatile b2 =
207*0ac341f1SConrad Meyer (const volatile unsigned char *volatile) b2_;
208*0ac341f1SConrad Meyer #endif
209*0ac341f1SConrad Meyer size_t i;
210*0ac341f1SConrad Meyer volatile unsigned char gt = 0U;
211*0ac341f1SConrad Meyer volatile unsigned char eq = 1U;
212*0ac341f1SConrad Meyer uint16_t x1, x2;
213*0ac341f1SConrad Meyer
214*0ac341f1SConrad Meyer #if HAVE_WEAK_SYMBOLS
215*0ac341f1SConrad Meyer _sodium_dummy_symbol_to_prevent_compare_lto(b1, b2, len);
216*0ac341f1SConrad Meyer #endif
217*0ac341f1SConrad Meyer i = len;
218*0ac341f1SConrad Meyer while (i != 0U) {
219*0ac341f1SConrad Meyer i--;
220*0ac341f1SConrad Meyer x1 = b1[i];
221*0ac341f1SConrad Meyer x2 = b2[i];
222*0ac341f1SConrad Meyer gt |= ((x2 - x1) >> 8) & eq;
223*0ac341f1SConrad Meyer eq &= ((x2 ^ x1) - 1) >> 8;
224*0ac341f1SConrad Meyer }
225*0ac341f1SConrad Meyer return (int) (gt + gt + eq) - 1;
226*0ac341f1SConrad Meyer }
227*0ac341f1SConrad Meyer
228*0ac341f1SConrad Meyer int
sodium_is_zero(const unsigned char * n,const size_t nlen)229*0ac341f1SConrad Meyer sodium_is_zero(const unsigned char *n, const size_t nlen)
230*0ac341f1SConrad Meyer {
231*0ac341f1SConrad Meyer size_t i;
232*0ac341f1SConrad Meyer volatile unsigned char d = 0U;
233*0ac341f1SConrad Meyer
234*0ac341f1SConrad Meyer for (i = 0U; i < nlen; i++) {
235*0ac341f1SConrad Meyer d |= n[i];
236*0ac341f1SConrad Meyer }
237*0ac341f1SConrad Meyer return 1 & ((d - 1) >> 8);
238*0ac341f1SConrad Meyer }
239*0ac341f1SConrad Meyer
240*0ac341f1SConrad Meyer void
sodium_increment(unsigned char * n,const size_t nlen)241*0ac341f1SConrad Meyer sodium_increment(unsigned char *n, const size_t nlen)
242*0ac341f1SConrad Meyer {
243*0ac341f1SConrad Meyer size_t i = 0U;
244*0ac341f1SConrad Meyer uint_fast16_t c = 1U;
245*0ac341f1SConrad Meyer
246*0ac341f1SConrad Meyer #ifdef HAVE_AMD64_ASM
247*0ac341f1SConrad Meyer uint64_t t64, t64_2;
248*0ac341f1SConrad Meyer uint32_t t32;
249*0ac341f1SConrad Meyer
250*0ac341f1SConrad Meyer if (nlen == 12U) {
251*0ac341f1SConrad Meyer __asm__ __volatile__(
252*0ac341f1SConrad Meyer "xorq %[t64], %[t64] \n"
253*0ac341f1SConrad Meyer "xorl %[t32], %[t32] \n"
254*0ac341f1SConrad Meyer "stc \n"
255*0ac341f1SConrad Meyer "adcq %[t64], (%[out]) \n"
256*0ac341f1SConrad Meyer "adcl %[t32], 8(%[out]) \n"
257*0ac341f1SConrad Meyer : [t64] "=&r"(t64), [t32] "=&r"(t32)
258*0ac341f1SConrad Meyer : [out] "D"(n)
259*0ac341f1SConrad Meyer : "memory", "flags", "cc");
260*0ac341f1SConrad Meyer return;
261*0ac341f1SConrad Meyer } else if (nlen == 24U) {
262*0ac341f1SConrad Meyer __asm__ __volatile__(
263*0ac341f1SConrad Meyer "movq $1, %[t64] \n"
264*0ac341f1SConrad Meyer "xorq %[t64_2], %[t64_2] \n"
265*0ac341f1SConrad Meyer "addq %[t64], (%[out]) \n"
266*0ac341f1SConrad Meyer "adcq %[t64_2], 8(%[out]) \n"
267*0ac341f1SConrad Meyer "adcq %[t64_2], 16(%[out]) \n"
268*0ac341f1SConrad Meyer : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2)
269*0ac341f1SConrad Meyer : [out] "D"(n)
270*0ac341f1SConrad Meyer : "memory", "flags", "cc");
271*0ac341f1SConrad Meyer return;
272*0ac341f1SConrad Meyer } else if (nlen == 8U) {
273*0ac341f1SConrad Meyer __asm__ __volatile__("incq (%[out]) \n"
274*0ac341f1SConrad Meyer :
275*0ac341f1SConrad Meyer : [out] "D"(n)
276*0ac341f1SConrad Meyer : "memory", "flags", "cc");
277*0ac341f1SConrad Meyer return;
278*0ac341f1SConrad Meyer }
279*0ac341f1SConrad Meyer #endif
280*0ac341f1SConrad Meyer for (; i < nlen; i++) {
281*0ac341f1SConrad Meyer c += (uint_fast16_t) n[i];
282*0ac341f1SConrad Meyer n[i] = (unsigned char) c;
283*0ac341f1SConrad Meyer c >>= 8;
284*0ac341f1SConrad Meyer }
285*0ac341f1SConrad Meyer }
286*0ac341f1SConrad Meyer
287*0ac341f1SConrad Meyer void
sodium_add(unsigned char * a,const unsigned char * b,const size_t len)288*0ac341f1SConrad Meyer sodium_add(unsigned char *a, const unsigned char *b, const size_t len)
289*0ac341f1SConrad Meyer {
290*0ac341f1SConrad Meyer size_t i = 0U;
291*0ac341f1SConrad Meyer uint_fast16_t c = 0U;
292*0ac341f1SConrad Meyer
293*0ac341f1SConrad Meyer #ifdef HAVE_AMD64_ASM
294*0ac341f1SConrad Meyer uint64_t t64, t64_2, t64_3;
295*0ac341f1SConrad Meyer uint32_t t32;
296*0ac341f1SConrad Meyer
297*0ac341f1SConrad Meyer if (len == 12U) {
298*0ac341f1SConrad Meyer __asm__ __volatile__(
299*0ac341f1SConrad Meyer "movq (%[in]), %[t64] \n"
300*0ac341f1SConrad Meyer "movl 8(%[in]), %[t32] \n"
301*0ac341f1SConrad Meyer "addq %[t64], (%[out]) \n"
302*0ac341f1SConrad Meyer "adcl %[t32], 8(%[out]) \n"
303*0ac341f1SConrad Meyer : [t64] "=&r"(t64), [t32] "=&r"(t32)
304*0ac341f1SConrad Meyer : [in] "S"(b), [out] "D"(a)
305*0ac341f1SConrad Meyer : "memory", "flags", "cc");
306*0ac341f1SConrad Meyer return;
307*0ac341f1SConrad Meyer } else if (len == 24U) {
308*0ac341f1SConrad Meyer __asm__ __volatile__(
309*0ac341f1SConrad Meyer "movq (%[in]), %[t64] \n"
310*0ac341f1SConrad Meyer "movq 8(%[in]), %[t64_2] \n"
311*0ac341f1SConrad Meyer "movq 16(%[in]), %[t64_3] \n"
312*0ac341f1SConrad Meyer "addq %[t64], (%[out]) \n"
313*0ac341f1SConrad Meyer "adcq %[t64_2], 8(%[out]) \n"
314*0ac341f1SConrad Meyer "adcq %[t64_3], 16(%[out]) \n"
315*0ac341f1SConrad Meyer : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2), [t64_3] "=&r"(t64_3)
316*0ac341f1SConrad Meyer : [in] "S"(b), [out] "D"(a)
317*0ac341f1SConrad Meyer : "memory", "flags", "cc");
318*0ac341f1SConrad Meyer return;
319*0ac341f1SConrad Meyer } else if (len == 8U) {
320*0ac341f1SConrad Meyer __asm__ __volatile__(
321*0ac341f1SConrad Meyer "movq (%[in]), %[t64] \n"
322*0ac341f1SConrad Meyer "addq %[t64], (%[out]) \n"
323*0ac341f1SConrad Meyer : [t64] "=&r"(t64)
324*0ac341f1SConrad Meyer : [in] "S"(b), [out] "D"(a)
325*0ac341f1SConrad Meyer : "memory", "flags", "cc");
326*0ac341f1SConrad Meyer return;
327*0ac341f1SConrad Meyer }
328*0ac341f1SConrad Meyer #endif
329*0ac341f1SConrad Meyer for (; i < len; i++) {
330*0ac341f1SConrad Meyer c += (uint_fast16_t) a[i] + (uint_fast16_t) b[i];
331*0ac341f1SConrad Meyer a[i] = (unsigned char) c;
332*0ac341f1SConrad Meyer c >>= 8;
333*0ac341f1SConrad Meyer }
334*0ac341f1SConrad Meyer }
335*0ac341f1SConrad Meyer
336*0ac341f1SConrad Meyer int
_sodium_alloc_init(void)337*0ac341f1SConrad Meyer _sodium_alloc_init(void)
338*0ac341f1SConrad Meyer {
339*0ac341f1SConrad Meyer #ifdef HAVE_ALIGNED_MALLOC
340*0ac341f1SConrad Meyer # if defined(_SC_PAGESIZE)
341*0ac341f1SConrad Meyer long page_size_ = sysconf(_SC_PAGESIZE);
342*0ac341f1SConrad Meyer if (page_size_ > 0L) {
343*0ac341f1SConrad Meyer page_size = (size_t) page_size_;
344*0ac341f1SConrad Meyer }
345*0ac341f1SConrad Meyer # elif defined(WINAPI_DESKTOP)
346*0ac341f1SConrad Meyer SYSTEM_INFO si;
347*0ac341f1SConrad Meyer GetSystemInfo(&si);
348*0ac341f1SConrad Meyer page_size = (size_t) si.dwPageSize;
349*0ac341f1SConrad Meyer # endif
350*0ac341f1SConrad Meyer if (page_size < CANARY_SIZE || page_size < sizeof(size_t)) {
351*0ac341f1SConrad Meyer sodium_misuse(); /* LCOV_EXCL_LINE */
352*0ac341f1SConrad Meyer }
353*0ac341f1SConrad Meyer #endif
354*0ac341f1SConrad Meyer randombytes_buf(canary, sizeof canary);
355*0ac341f1SConrad Meyer
356*0ac341f1SConrad Meyer return 0;
357*0ac341f1SConrad Meyer }
358*0ac341f1SConrad Meyer
359*0ac341f1SConrad Meyer int
sodium_mlock(void * const addr,const size_t len)360*0ac341f1SConrad Meyer sodium_mlock(void *const addr, const size_t len)
361*0ac341f1SConrad Meyer {
362*0ac341f1SConrad Meyer #if defined(MADV_DONTDUMP) && defined(HAVE_MADVISE)
363*0ac341f1SConrad Meyer (void) madvise(addr, len, MADV_DONTDUMP);
364*0ac341f1SConrad Meyer #endif
365*0ac341f1SConrad Meyer #ifdef HAVE_MLOCK
366*0ac341f1SConrad Meyer return mlock(addr, len);
367*0ac341f1SConrad Meyer #elif defined(WINAPI_DESKTOP)
368*0ac341f1SConrad Meyer return -(VirtualLock(addr, len) == 0);
369*0ac341f1SConrad Meyer #else
370*0ac341f1SConrad Meyer errno = ENOSYS;
371*0ac341f1SConrad Meyer return -1;
372*0ac341f1SConrad Meyer #endif
373*0ac341f1SConrad Meyer }
374*0ac341f1SConrad Meyer
375*0ac341f1SConrad Meyer int
sodium_munlock(void * const addr,const size_t len)376*0ac341f1SConrad Meyer sodium_munlock(void *const addr, const size_t len)
377*0ac341f1SConrad Meyer {
378*0ac341f1SConrad Meyer sodium_memzero(addr, len);
379*0ac341f1SConrad Meyer #if defined(MADV_DODUMP) && defined(HAVE_MADVISE)
380*0ac341f1SConrad Meyer (void) madvise(addr, len, MADV_DODUMP);
381*0ac341f1SConrad Meyer #endif
382*0ac341f1SConrad Meyer #ifdef HAVE_MLOCK
383*0ac341f1SConrad Meyer return munlock(addr, len);
384*0ac341f1SConrad Meyer #elif defined(WINAPI_DESKTOP)
385*0ac341f1SConrad Meyer return -(VirtualUnlock(addr, len) == 0);
386*0ac341f1SConrad Meyer #else
387*0ac341f1SConrad Meyer errno = ENOSYS;
388*0ac341f1SConrad Meyer return -1;
389*0ac341f1SConrad Meyer #endif
390*0ac341f1SConrad Meyer }
391*0ac341f1SConrad Meyer
392*0ac341f1SConrad Meyer static int
_mprotect_noaccess(void * ptr,size_t size)393*0ac341f1SConrad Meyer _mprotect_noaccess(void *ptr, size_t size)
394*0ac341f1SConrad Meyer {
395*0ac341f1SConrad Meyer #ifdef HAVE_MPROTECT
396*0ac341f1SConrad Meyer return mprotect(ptr, size, PROT_NONE);
397*0ac341f1SConrad Meyer #elif defined(WINAPI_DESKTOP)
398*0ac341f1SConrad Meyer DWORD old;
399*0ac341f1SConrad Meyer return -(VirtualProtect(ptr, size, PAGE_NOACCESS, &old) == 0);
400*0ac341f1SConrad Meyer #else
401*0ac341f1SConrad Meyer errno = ENOSYS;
402*0ac341f1SConrad Meyer return -1;
403*0ac341f1SConrad Meyer #endif
404*0ac341f1SConrad Meyer }
405*0ac341f1SConrad Meyer
406*0ac341f1SConrad Meyer static int
_mprotect_readonly(void * ptr,size_t size)407*0ac341f1SConrad Meyer _mprotect_readonly(void *ptr, size_t size)
408*0ac341f1SConrad Meyer {
409*0ac341f1SConrad Meyer #ifdef HAVE_MPROTECT
410*0ac341f1SConrad Meyer return mprotect(ptr, size, PROT_READ);
411*0ac341f1SConrad Meyer #elif defined(WINAPI_DESKTOP)
412*0ac341f1SConrad Meyer DWORD old;
413*0ac341f1SConrad Meyer return -(VirtualProtect(ptr, size, PAGE_READONLY, &old) == 0);
414*0ac341f1SConrad Meyer #else
415*0ac341f1SConrad Meyer errno = ENOSYS;
416*0ac341f1SConrad Meyer return -1;
417*0ac341f1SConrad Meyer #endif
418*0ac341f1SConrad Meyer }
419*0ac341f1SConrad Meyer
420*0ac341f1SConrad Meyer static int
_mprotect_readwrite(void * ptr,size_t size)421*0ac341f1SConrad Meyer _mprotect_readwrite(void *ptr, size_t size)
422*0ac341f1SConrad Meyer {
423*0ac341f1SConrad Meyer #ifdef HAVE_MPROTECT
424*0ac341f1SConrad Meyer return mprotect(ptr, size, PROT_READ | PROT_WRITE);
425*0ac341f1SConrad Meyer #elif defined(WINAPI_DESKTOP)
426*0ac341f1SConrad Meyer DWORD old;
427*0ac341f1SConrad Meyer return -(VirtualProtect(ptr, size, PAGE_READWRITE, &old) == 0);
428*0ac341f1SConrad Meyer #else
429*0ac341f1SConrad Meyer errno = ENOSYS;
430*0ac341f1SConrad Meyer return -1;
431*0ac341f1SConrad Meyer #endif
432*0ac341f1SConrad Meyer }
433*0ac341f1SConrad Meyer
434*0ac341f1SConrad Meyer #ifdef HAVE_ALIGNED_MALLOC
435*0ac341f1SConrad Meyer
436*0ac341f1SConrad Meyer __attribute__((noreturn)) static void
_out_of_bounds(void)437*0ac341f1SConrad Meyer _out_of_bounds(void)
438*0ac341f1SConrad Meyer {
439*0ac341f1SConrad Meyer # ifdef SIGSEGV
440*0ac341f1SConrad Meyer raise(SIGSEGV);
441*0ac341f1SConrad Meyer # elif defined(SIGKILL)
442*0ac341f1SConrad Meyer raise(SIGKILL);
443*0ac341f1SConrad Meyer # endif
444*0ac341f1SConrad Meyer abort(); /* not something we want any higher-level API to catch */
445*0ac341f1SConrad Meyer } /* LCOV_EXCL_LINE */
446*0ac341f1SConrad Meyer
447*0ac341f1SConrad Meyer static inline size_t
_page_round(const size_t size)448*0ac341f1SConrad Meyer _page_round(const size_t size)
449*0ac341f1SConrad Meyer {
450*0ac341f1SConrad Meyer const size_t page_mask = page_size - 1U;
451*0ac341f1SConrad Meyer
452*0ac341f1SConrad Meyer return (size + page_mask) & ~page_mask;
453*0ac341f1SConrad Meyer }
454*0ac341f1SConrad Meyer
455*0ac341f1SConrad Meyer static __attribute__((malloc)) unsigned char *
_alloc_aligned(const size_t size)456*0ac341f1SConrad Meyer _alloc_aligned(const size_t size)
457*0ac341f1SConrad Meyer {
458*0ac341f1SConrad Meyer void *ptr;
459*0ac341f1SConrad Meyer
460*0ac341f1SConrad Meyer # if defined(MAP_ANON) && defined(HAVE_MMAP)
461*0ac341f1SConrad Meyer if ((ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
462*0ac341f1SConrad Meyer MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0)) ==
463*0ac341f1SConrad Meyer MAP_FAILED) {
464*0ac341f1SConrad Meyer ptr = NULL; /* LCOV_EXCL_LINE */
465*0ac341f1SConrad Meyer } /* LCOV_EXCL_LINE */
466*0ac341f1SConrad Meyer # elif defined(HAVE_POSIX_MEMALIGN)
467*0ac341f1SConrad Meyer if (posix_memalign(&ptr, page_size, size) != 0) {
468*0ac341f1SConrad Meyer ptr = NULL; /* LCOV_EXCL_LINE */
469*0ac341f1SConrad Meyer } /* LCOV_EXCL_LINE */
470*0ac341f1SConrad Meyer # elif defined(WINAPI_DESKTOP)
471*0ac341f1SConrad Meyer ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
472*0ac341f1SConrad Meyer # else
473*0ac341f1SConrad Meyer # error Bug
474*0ac341f1SConrad Meyer # endif
475*0ac341f1SConrad Meyer return (unsigned char *) ptr;
476*0ac341f1SConrad Meyer }
477*0ac341f1SConrad Meyer
478*0ac341f1SConrad Meyer static void
_free_aligned(unsigned char * const ptr,const size_t size)479*0ac341f1SConrad Meyer _free_aligned(unsigned char *const ptr, const size_t size)
480*0ac341f1SConrad Meyer {
481*0ac341f1SConrad Meyer # if defined(MAP_ANON) && defined(HAVE_MMAP)
482*0ac341f1SConrad Meyer (void) munmap(ptr, size);
483*0ac341f1SConrad Meyer # elif defined(HAVE_POSIX_MEMALIGN)
484*0ac341f1SConrad Meyer free(ptr);
485*0ac341f1SConrad Meyer # elif defined(WINAPI_DESKTOP)
486*0ac341f1SConrad Meyer VirtualFree(ptr, 0U, MEM_RELEASE);
487*0ac341f1SConrad Meyer # else
488*0ac341f1SConrad Meyer # error Bug
489*0ac341f1SConrad Meyer #endif
490*0ac341f1SConrad Meyer }
491*0ac341f1SConrad Meyer
492*0ac341f1SConrad Meyer static unsigned char *
_unprotected_ptr_from_user_ptr(void * const ptr)493*0ac341f1SConrad Meyer _unprotected_ptr_from_user_ptr(void *const ptr)
494*0ac341f1SConrad Meyer {
495*0ac341f1SConrad Meyer uintptr_t unprotected_ptr_u;
496*0ac341f1SConrad Meyer unsigned char *canary_ptr;
497*0ac341f1SConrad Meyer size_t page_mask;
498*0ac341f1SConrad Meyer
499*0ac341f1SConrad Meyer canary_ptr = ((unsigned char *) ptr) - sizeof canary;
500*0ac341f1SConrad Meyer page_mask = page_size - 1U;
501*0ac341f1SConrad Meyer unprotected_ptr_u = ((uintptr_t) canary_ptr & (uintptr_t) ~page_mask);
502*0ac341f1SConrad Meyer if (unprotected_ptr_u <= page_size * 2U) {
503*0ac341f1SConrad Meyer sodium_misuse(); /* LCOV_EXCL_LINE */
504*0ac341f1SConrad Meyer }
505*0ac341f1SConrad Meyer return (unsigned char *) unprotected_ptr_u;
506*0ac341f1SConrad Meyer }
507*0ac341f1SConrad Meyer
508*0ac341f1SConrad Meyer #endif /* HAVE_ALIGNED_MALLOC */
509*0ac341f1SConrad Meyer
510*0ac341f1SConrad Meyer #ifndef HAVE_ALIGNED_MALLOC
511*0ac341f1SConrad Meyer static __attribute__((malloc)) void *
_sodium_malloc(const size_t size)512*0ac341f1SConrad Meyer _sodium_malloc(const size_t size)
513*0ac341f1SConrad Meyer {
514*0ac341f1SConrad Meyer return malloc(size > (size_t) 0U ? size : (size_t) 1U);
515*0ac341f1SConrad Meyer }
516*0ac341f1SConrad Meyer #else
517*0ac341f1SConrad Meyer static __attribute__((malloc)) void *
_sodium_malloc(const size_t size)518*0ac341f1SConrad Meyer _sodium_malloc(const size_t size)
519*0ac341f1SConrad Meyer {
520*0ac341f1SConrad Meyer void *user_ptr;
521*0ac341f1SConrad Meyer unsigned char *base_ptr;
522*0ac341f1SConrad Meyer unsigned char *canary_ptr;
523*0ac341f1SConrad Meyer unsigned char *unprotected_ptr;
524*0ac341f1SConrad Meyer size_t size_with_canary;
525*0ac341f1SConrad Meyer size_t total_size;
526*0ac341f1SConrad Meyer size_t unprotected_size;
527*0ac341f1SConrad Meyer
528*0ac341f1SConrad Meyer if (size >= (size_t) SIZE_MAX - page_size * 4U) {
529*0ac341f1SConrad Meyer errno = ENOMEM;
530*0ac341f1SConrad Meyer return NULL;
531*0ac341f1SConrad Meyer }
532*0ac341f1SConrad Meyer if (page_size <= sizeof canary || page_size < sizeof unprotected_size) {
533*0ac341f1SConrad Meyer sodium_misuse(); /* LCOV_EXCL_LINE */
534*0ac341f1SConrad Meyer }
535*0ac341f1SConrad Meyer size_with_canary = (sizeof canary) + size;
536*0ac341f1SConrad Meyer unprotected_size = _page_round(size_with_canary);
537*0ac341f1SConrad Meyer total_size = page_size + page_size + unprotected_size + page_size;
538*0ac341f1SConrad Meyer if ((base_ptr = _alloc_aligned(total_size)) == NULL) {
539*0ac341f1SConrad Meyer return NULL; /* LCOV_EXCL_LINE */
540*0ac341f1SConrad Meyer }
541*0ac341f1SConrad Meyer unprotected_ptr = base_ptr + page_size * 2U;
542*0ac341f1SConrad Meyer _mprotect_noaccess(base_ptr + page_size, page_size);
543*0ac341f1SConrad Meyer # ifndef HAVE_PAGE_PROTECTION
544*0ac341f1SConrad Meyer memcpy(unprotected_ptr + unprotected_size, canary, sizeof canary);
545*0ac341f1SConrad Meyer # endif
546*0ac341f1SConrad Meyer _mprotect_noaccess(unprotected_ptr + unprotected_size, page_size);
547*0ac341f1SConrad Meyer sodium_mlock(unprotected_ptr, unprotected_size);
548*0ac341f1SConrad Meyer canary_ptr =
549*0ac341f1SConrad Meyer unprotected_ptr + _page_round(size_with_canary) - size_with_canary;
550*0ac341f1SConrad Meyer user_ptr = canary_ptr + sizeof canary;
551*0ac341f1SConrad Meyer memcpy(canary_ptr, canary, sizeof canary);
552*0ac341f1SConrad Meyer memcpy(base_ptr, &unprotected_size, sizeof unprotected_size);
553*0ac341f1SConrad Meyer _mprotect_readonly(base_ptr, page_size);
554*0ac341f1SConrad Meyer assert(_unprotected_ptr_from_user_ptr(user_ptr) == unprotected_ptr);
555*0ac341f1SConrad Meyer
556*0ac341f1SConrad Meyer return user_ptr;
557*0ac341f1SConrad Meyer }
558*0ac341f1SConrad Meyer #endif /* !HAVE_ALIGNED_MALLOC */
559*0ac341f1SConrad Meyer
560*0ac341f1SConrad Meyer __attribute__((malloc)) void *
sodium_malloc(const size_t size)561*0ac341f1SConrad Meyer sodium_malloc(const size_t size)
562*0ac341f1SConrad Meyer {
563*0ac341f1SConrad Meyer void *ptr;
564*0ac341f1SConrad Meyer
565*0ac341f1SConrad Meyer if ((ptr = _sodium_malloc(size)) == NULL) {
566*0ac341f1SConrad Meyer return NULL;
567*0ac341f1SConrad Meyer }
568*0ac341f1SConrad Meyer memset(ptr, (int) GARBAGE_VALUE, size);
569*0ac341f1SConrad Meyer
570*0ac341f1SConrad Meyer return ptr;
571*0ac341f1SConrad Meyer }
572*0ac341f1SConrad Meyer
573*0ac341f1SConrad Meyer __attribute__((malloc)) void *
sodium_allocarray(size_t count,size_t size)574*0ac341f1SConrad Meyer sodium_allocarray(size_t count, size_t size)
575*0ac341f1SConrad Meyer {
576*0ac341f1SConrad Meyer if (count > (size_t) 0U && size >= (size_t) SIZE_MAX / count) {
577*0ac341f1SConrad Meyer errno = ENOMEM;
578*0ac341f1SConrad Meyer return NULL;
579*0ac341f1SConrad Meyer }
580*0ac341f1SConrad Meyer return sodium_malloc(count * size);
581*0ac341f1SConrad Meyer }
582*0ac341f1SConrad Meyer
583*0ac341f1SConrad Meyer #ifndef HAVE_ALIGNED_MALLOC
584*0ac341f1SConrad Meyer void
sodium_free(void * ptr)585*0ac341f1SConrad Meyer sodium_free(void *ptr)
586*0ac341f1SConrad Meyer {
587*0ac341f1SConrad Meyer free(ptr);
588*0ac341f1SConrad Meyer }
589*0ac341f1SConrad Meyer #else
590*0ac341f1SConrad Meyer void
sodium_free(void * ptr)591*0ac341f1SConrad Meyer sodium_free(void *ptr)
592*0ac341f1SConrad Meyer {
593*0ac341f1SConrad Meyer unsigned char *base_ptr;
594*0ac341f1SConrad Meyer unsigned char *canary_ptr;
595*0ac341f1SConrad Meyer unsigned char *unprotected_ptr;
596*0ac341f1SConrad Meyer size_t total_size;
597*0ac341f1SConrad Meyer size_t unprotected_size;
598*0ac341f1SConrad Meyer
599*0ac341f1SConrad Meyer if (ptr == NULL) {
600*0ac341f1SConrad Meyer return;
601*0ac341f1SConrad Meyer }
602*0ac341f1SConrad Meyer canary_ptr = ((unsigned char *) ptr) - sizeof canary;
603*0ac341f1SConrad Meyer unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
604*0ac341f1SConrad Meyer base_ptr = unprotected_ptr - page_size * 2U;
605*0ac341f1SConrad Meyer memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
606*0ac341f1SConrad Meyer total_size = page_size + page_size + unprotected_size + page_size;
607*0ac341f1SConrad Meyer _mprotect_readwrite(base_ptr, total_size);
608*0ac341f1SConrad Meyer if (sodium_memcmp(canary_ptr, canary, sizeof canary) != 0) {
609*0ac341f1SConrad Meyer _out_of_bounds();
610*0ac341f1SConrad Meyer }
611*0ac341f1SConrad Meyer # ifndef HAVE_PAGE_PROTECTION
612*0ac341f1SConrad Meyer if (sodium_memcmp(unprotected_ptr + unprotected_size, canary,
613*0ac341f1SConrad Meyer sizeof canary) != 0) {
614*0ac341f1SConrad Meyer _out_of_bounds();
615*0ac341f1SConrad Meyer }
616*0ac341f1SConrad Meyer # endif
617*0ac341f1SConrad Meyer sodium_munlock(unprotected_ptr, unprotected_size);
618*0ac341f1SConrad Meyer _free_aligned(base_ptr, total_size);
619*0ac341f1SConrad Meyer }
620*0ac341f1SConrad Meyer #endif /* HAVE_ALIGNED_MALLOC */
621*0ac341f1SConrad Meyer
622*0ac341f1SConrad Meyer #ifndef HAVE_PAGE_PROTECTION
623*0ac341f1SConrad Meyer static int
_sodium_mprotect(void * ptr,int (* cb)(void * ptr,size_t size))624*0ac341f1SConrad Meyer _sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size))
625*0ac341f1SConrad Meyer {
626*0ac341f1SConrad Meyer (void) ptr;
627*0ac341f1SConrad Meyer (void) cb;
628*0ac341f1SConrad Meyer errno = ENOSYS;
629*0ac341f1SConrad Meyer return -1;
630*0ac341f1SConrad Meyer }
631*0ac341f1SConrad Meyer #else
632*0ac341f1SConrad Meyer static int
_sodium_mprotect(void * ptr,int (* cb)(void * ptr,size_t size))633*0ac341f1SConrad Meyer _sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size))
634*0ac341f1SConrad Meyer {
635*0ac341f1SConrad Meyer unsigned char *base_ptr;
636*0ac341f1SConrad Meyer unsigned char *unprotected_ptr;
637*0ac341f1SConrad Meyer size_t unprotected_size;
638*0ac341f1SConrad Meyer
639*0ac341f1SConrad Meyer unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
640*0ac341f1SConrad Meyer base_ptr = unprotected_ptr - page_size * 2U;
641*0ac341f1SConrad Meyer memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
642*0ac341f1SConrad Meyer
643*0ac341f1SConrad Meyer return cb(unprotected_ptr, unprotected_size);
644*0ac341f1SConrad Meyer }
645*0ac341f1SConrad Meyer #endif
646*0ac341f1SConrad Meyer
647*0ac341f1SConrad Meyer int
sodium_mprotect_noaccess(void * ptr)648*0ac341f1SConrad Meyer sodium_mprotect_noaccess(void *ptr)
649*0ac341f1SConrad Meyer {
650*0ac341f1SConrad Meyer return _sodium_mprotect(ptr, _mprotect_noaccess);
651*0ac341f1SConrad Meyer }
652*0ac341f1SConrad Meyer
653*0ac341f1SConrad Meyer int
sodium_mprotect_readonly(void * ptr)654*0ac341f1SConrad Meyer sodium_mprotect_readonly(void *ptr)
655*0ac341f1SConrad Meyer {
656*0ac341f1SConrad Meyer return _sodium_mprotect(ptr, _mprotect_readonly);
657*0ac341f1SConrad Meyer }
658*0ac341f1SConrad Meyer
659*0ac341f1SConrad Meyer int
sodium_mprotect_readwrite(void * ptr)660*0ac341f1SConrad Meyer sodium_mprotect_readwrite(void *ptr)
661*0ac341f1SConrad Meyer {
662*0ac341f1SConrad Meyer return _sodium_mprotect(ptr, _mprotect_readwrite);
663*0ac341f1SConrad Meyer }
664*0ac341f1SConrad Meyer
665*0ac341f1SConrad Meyer int
sodium_pad(size_t * padded_buflen_p,unsigned char * buf,size_t unpadded_buflen,size_t blocksize,size_t max_buflen)666*0ac341f1SConrad Meyer sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
667*0ac341f1SConrad Meyer size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
668*0ac341f1SConrad Meyer {
669*0ac341f1SConrad Meyer unsigned char *tail;
670*0ac341f1SConrad Meyer size_t i;
671*0ac341f1SConrad Meyer size_t xpadlen;
672*0ac341f1SConrad Meyer size_t xpadded_len;
673*0ac341f1SConrad Meyer volatile unsigned char mask;
674*0ac341f1SConrad Meyer unsigned char barrier_mask;
675*0ac341f1SConrad Meyer
676*0ac341f1SConrad Meyer if (blocksize <= 0U) {
677*0ac341f1SConrad Meyer return -1;
678*0ac341f1SConrad Meyer }
679*0ac341f1SConrad Meyer xpadlen = blocksize - 1U;
680*0ac341f1SConrad Meyer if ((blocksize & (blocksize - 1U)) == 0U) {
681*0ac341f1SConrad Meyer xpadlen -= unpadded_buflen & (blocksize - 1U);
682*0ac341f1SConrad Meyer } else {
683*0ac341f1SConrad Meyer xpadlen -= unpadded_buflen % blocksize;
684*0ac341f1SConrad Meyer }
685*0ac341f1SConrad Meyer if ((size_t) SIZE_MAX - unpadded_buflen <= xpadlen) {
686*0ac341f1SConrad Meyer sodium_misuse();
687*0ac341f1SConrad Meyer }
688*0ac341f1SConrad Meyer xpadded_len = unpadded_buflen + xpadlen;
689*0ac341f1SConrad Meyer if (xpadded_len >= max_buflen) {
690*0ac341f1SConrad Meyer return -1;
691*0ac341f1SConrad Meyer }
692*0ac341f1SConrad Meyer tail = &buf[xpadded_len];
693*0ac341f1SConrad Meyer if (padded_buflen_p != NULL) {
694*0ac341f1SConrad Meyer *padded_buflen_p = xpadded_len + 1U;
695*0ac341f1SConrad Meyer }
696*0ac341f1SConrad Meyer mask = 0U;
697*0ac341f1SConrad Meyer for (i = 0; i < blocksize; i++) {
698*0ac341f1SConrad Meyer barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> 8);
699*0ac341f1SConrad Meyer tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
700*0ac341f1SConrad Meyer mask |= barrier_mask;
701*0ac341f1SConrad Meyer }
702*0ac341f1SConrad Meyer return 0;
703*0ac341f1SConrad Meyer }
704*0ac341f1SConrad Meyer
705*0ac341f1SConrad Meyer int
sodium_unpad(size_t * unpadded_buflen_p,const unsigned char * buf,size_t padded_buflen,size_t blocksize)706*0ac341f1SConrad Meyer sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf,
707*0ac341f1SConrad Meyer size_t padded_buflen, size_t blocksize)
708*0ac341f1SConrad Meyer {
709*0ac341f1SConrad Meyer const unsigned char *tail;
710*0ac341f1SConrad Meyer unsigned char acc = 0U;
711*0ac341f1SConrad Meyer unsigned char c;
712*0ac341f1SConrad Meyer unsigned char valid = 0U;
713*0ac341f1SConrad Meyer volatile size_t pad_len = 0U;
714*0ac341f1SConrad Meyer size_t i;
715*0ac341f1SConrad Meyer size_t is_barrier;
716*0ac341f1SConrad Meyer
717*0ac341f1SConrad Meyer if (padded_buflen < blocksize || blocksize <= 0U) {
718*0ac341f1SConrad Meyer return -1;
719*0ac341f1SConrad Meyer }
720*0ac341f1SConrad Meyer tail = &buf[padded_buflen - 1U];
721*0ac341f1SConrad Meyer
722*0ac341f1SConrad Meyer for (i = 0U; i < blocksize; i++) {
723*0ac341f1SConrad Meyer c = tail[-i];
724*0ac341f1SConrad Meyer is_barrier =
725*0ac341f1SConrad Meyer (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
726*0ac341f1SConrad Meyer acc |= c;
727*0ac341f1SConrad Meyer pad_len |= i & (1U + ~is_barrier);
728*0ac341f1SConrad Meyer valid |= (unsigned char) is_barrier;
729*0ac341f1SConrad Meyer }
730*0ac341f1SConrad Meyer *unpadded_buflen_p = padded_buflen - 1U - pad_len;
731*0ac341f1SConrad Meyer
732*0ac341f1SConrad Meyer return (int) (valid - 1U);
733*0ac341f1SConrad Meyer }
734