xref: /freebsd/sys/contrib/libsodium/src/libsodium/sodium/utils.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
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