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