Path: blob/main/crypto/openssl/include/internal/constant_time.h
103835 views
/*1* Copyright 2014-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#ifndef OSSL_INTERNAL_CONSTANT_TIME_H10#define OSSL_INTERNAL_CONSTANT_TIME_H11#pragma once1213#include <stdlib.h>14#include <string.h>15#include <openssl/e_os2.h> /* For 'ossl_inline' */1617/*-18* The boolean methods return a bitmask of all ones (0xff...f) for true19* and 0 for false. This is useful for choosing a value based on the result20* of a conditional in constant time. For example,21* if (a < b) {22* c = a;23* } else {24* c = b;25* }26* can be written as27* unsigned int lt = constant_time_lt(a, b);28* c = constant_time_select(lt, a, b);29*/3031/* Returns the given value with the MSB copied to all the other bits. */32static ossl_inline unsigned int constant_time_msb(unsigned int a);33/* Convenience method for uint32_t. */34static ossl_inline uint32_t constant_time_msb_32(uint32_t a);35/* Convenience method for uint64_t. */36static ossl_inline uint64_t constant_time_msb_64(uint64_t a);3738/* Returns 0xff..f if a < b and 0 otherwise. */39static ossl_inline unsigned int constant_time_lt(unsigned int a,40unsigned int b);41/* Convenience method for getting an 8-bit mask. */42static ossl_inline unsigned char constant_time_lt_8(unsigned int a,43unsigned int b);44/* Convenience method for uint32_t. */45static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b);4647/* Convenience method for uint64_t. */48static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b);4950/* Returns 0xff..f if a >= b and 0 otherwise. */51static ossl_inline unsigned int constant_time_ge(unsigned int a,52unsigned int b);53/* Convenience method for getting an 8-bit mask. */54static ossl_inline unsigned char constant_time_ge_8(unsigned int a,55unsigned int b);5657/* Returns 0xff..f if a == 0 and 0 otherwise. */58static ossl_inline unsigned int constant_time_is_zero(unsigned int a);59/* Convenience method for getting an 8-bit mask. */60static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a);61/* Convenience method for getting a 32-bit mask. */62static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a);6364/* Returns 0xff..f if a == b and 0 otherwise. */65static ossl_inline unsigned int constant_time_eq(unsigned int a,66unsigned int b);67/* Convenience method for getting an 8-bit mask. */68static ossl_inline unsigned char constant_time_eq_8(unsigned int a,69unsigned int b);70/* Signed integers. */71static ossl_inline unsigned int constant_time_eq_int(int a, int b);72/* Convenience method for getting an 8-bit mask. */73static ossl_inline unsigned char constant_time_eq_int_8(int a, int b);7475/*-76* Returns (mask & a) | (~mask & b).77*78* When |mask| is all 1s or all 0s (as returned by the methods above),79* the select methods return either |a| (if |mask| is nonzero) or |b|80* (if |mask| is zero).81*/82static ossl_inline unsigned int constant_time_select(unsigned int mask,83unsigned int a,84unsigned int b);85/* Convenience method for unsigned chars. */86static ossl_inline unsigned char constant_time_select_8(unsigned char mask,87unsigned char a,88unsigned char b);8990/* Convenience method for uint32_t. */91static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,92uint32_t b);9394/* Convenience method for uint64_t. */95static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,96uint64_t b);97/* Convenience method for signed integers. */98static ossl_inline int constant_time_select_int(unsigned int mask, int a,99int b);100101static ossl_inline unsigned int constant_time_msb(unsigned int a)102{103return 0 - (a >> (sizeof(a) * 8 - 1));104}105106static ossl_inline uint32_t constant_time_msb_32(uint32_t a)107{108return 0 - (a >> 31);109}110111static ossl_inline uint64_t constant_time_msb_64(uint64_t a)112{113return 0 - (a >> 63);114}115116static ossl_inline size_t constant_time_msb_s(size_t a)117{118return 0 - (a >> (sizeof(a) * 8 - 1));119}120121static ossl_inline unsigned int constant_time_lt(unsigned int a,122unsigned int b)123{124return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));125}126127static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)128{129return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));130}131132static ossl_inline unsigned char constant_time_lt_8(unsigned int a,133unsigned int b)134{135return (unsigned char)constant_time_lt(a, b);136}137138static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b)139{140return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b)));141}142143static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)144{145return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));146}147148#ifdef BN_ULONG149static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)150{151#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)152BN_ULONG r;153__asm__("" : "=r"(r) : "0"(a));154#else155volatile BN_ULONG r = a;156#endif157return r;158}159160static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)161{162return 0 - (a >> (sizeof(a) * 8 - 1));163}164165static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)166{167return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));168}169170static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)171{172return constant_time_msb_bn(~a & (a - 1));173}174175static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,176BN_ULONG b)177{178return constant_time_is_zero_bn(a ^ b);179}180181static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,182BN_ULONG a,183BN_ULONG b)184{185return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);186}187#endif188189static ossl_inline unsigned int constant_time_ge(unsigned int a,190unsigned int b)191{192return ~constant_time_lt(a, b);193}194195static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)196{197return ~constant_time_lt_s(a, b);198}199200static ossl_inline unsigned char constant_time_ge_8(unsigned int a,201unsigned int b)202{203return (unsigned char)constant_time_ge(a, b);204}205206static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)207{208return (unsigned char)constant_time_ge_s(a, b);209}210211static ossl_inline unsigned int constant_time_is_zero(unsigned int a)212{213return constant_time_msb(~a & (a - 1));214}215216static ossl_inline size_t constant_time_is_zero_s(size_t a)217{218return constant_time_msb_s(~a & (a - 1));219}220221static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)222{223return (unsigned char)constant_time_is_zero(a);224}225226static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)227{228return constant_time_msb_32(~a & (a - 1));229}230231static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)232{233return constant_time_msb_64(~a & (a - 1));234}235236static ossl_inline unsigned int constant_time_eq(unsigned int a,237unsigned int b)238{239return constant_time_is_zero(a ^ b);240}241242static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)243{244return constant_time_is_zero_s(a ^ b);245}246247static ossl_inline unsigned char constant_time_eq_8(unsigned int a,248unsigned int b)249{250return (unsigned char)constant_time_eq(a, b);251}252253static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)254{255return (unsigned char)constant_time_eq_s(a, b);256}257258static ossl_inline unsigned int constant_time_eq_int(int a, int b)259{260return constant_time_eq((unsigned)(a), (unsigned)(b));261}262263static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)264{265return constant_time_eq_8((unsigned)(a), (unsigned)(b));266}267268/*269* Returns the value unmodified, but avoids optimizations.270* The barriers prevent the compiler from narrowing down the271* possible value range of the mask and ~mask in the select272* statements, which avoids the recognition of the select273* and turning it into a conditional load or branch.274*/275static ossl_inline unsigned int value_barrier(unsigned int a)276{277#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)278unsigned int r;279__asm__("" : "=r"(r) : "0"(a));280#else281volatile unsigned int r = a;282#endif283return r;284}285286/* Convenience method for uint32_t. */287static ossl_inline uint32_t value_barrier_32(uint32_t a)288{289#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)290uint32_t r;291__asm__("" : "=r"(r) : "0"(a));292#else293volatile uint32_t r = a;294#endif295return r;296}297298/* Convenience method for uint64_t. */299static ossl_inline uint64_t value_barrier_64(uint64_t a)300{301#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)302uint64_t r;303__asm__("" : "=r"(r) : "0"(a));304#else305volatile uint64_t r = a;306#endif307return r;308}309310/* Convenience method for size_t. */311static ossl_inline size_t value_barrier_s(size_t a)312{313#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)314size_t r;315__asm__("" : "=r"(r) : "0"(a));316#else317volatile size_t r = a;318#endif319return r;320}321322/* Convenience method for unsigned char. */323static ossl_inline unsigned char value_barrier_8(unsigned char a)324{325#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)326unsigned char r;327__asm__("" : "=r"(r) : "0"(a));328#else329volatile unsigned char r = a;330#endif331return r;332}333334static ossl_inline unsigned int constant_time_select(unsigned int mask,335unsigned int a,336unsigned int b)337{338return (value_barrier(mask) & a) | (value_barrier(~mask) & b);339}340341static ossl_inline size_t constant_time_select_s(size_t mask,342size_t a,343size_t b)344{345return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);346}347348static ossl_inline unsigned char constant_time_select_8(unsigned char mask,349unsigned char a,350unsigned char b)351{352return (unsigned char)constant_time_select(mask, a, b);353}354355static ossl_inline int constant_time_select_int(unsigned int mask, int a,356int b)357{358return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));359}360361static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)362{363return (int)constant_time_select((unsigned)mask, (unsigned)(a),364(unsigned)(b));365}366367static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,368uint32_t b)369{370return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);371}372373static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,374uint64_t b)375{376return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);377}378379/*380* mask must be 0xFFFFFFFF or 0x00000000.381*382* if (mask) {383* uint32_t tmp = *a;384*385* *a = *b;386* *b = tmp;387* }388*/389static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,390uint32_t *b)391{392uint32_t xor = *a ^ *b;393394xor&= value_barrier_32(mask);395*a ^= xor;396*b ^= xor;397}398399/*400* mask must be 0xFFFFFFFF or 0x00000000.401*402* if (mask) {403* uint64_t tmp = *a;404*405* *a = *b;406* *b = tmp;407* }408*/409static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,410uint64_t *b)411{412uint64_t xor = *a ^ *b;413414xor&= value_barrier_64(mask);415*a ^= xor;416*b ^= xor;417}418419/*420* mask must be 0xFF or 0x00.421* "constant time" is per len.422*423* if (mask) {424* unsigned char tmp[len];425*426* memcpy(tmp, a, len);427* memcpy(a, b);428* memcpy(b, tmp);429* }430*/431static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,432unsigned char *a,433unsigned char *b,434size_t len)435{436size_t i;437unsigned char tmp;438439for (i = 0; i < len; i++) {440tmp = a[i] ^ b[i];441tmp &= value_barrier_8(mask);442a[i] ^= tmp;443b[i] ^= tmp;444}445}446447/*448* table is a two dimensional array of bytes. Each row has rowsize elements.449* Copies row number idx into out. rowsize and numrows are not considered450* private.451*/452static ossl_inline void constant_time_lookup(void *out,453const void *table,454size_t rowsize,455size_t numrows,456size_t idx)457{458size_t i, j;459const unsigned char *tablec = (const unsigned char *)table;460unsigned char *outc = (unsigned char *)out;461unsigned char mask;462463memset(out, 0, rowsize);464465/* Note idx may underflow - but that is well defined */466for (i = 0; i < numrows; i++, idx--) {467mask = (unsigned char)constant_time_is_zero_s(idx);468for (j = 0; j < rowsize; j++)469*(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);470}471}472473/*474* Expected usage pattern is to unconditionally set error and then475* wipe it if there was no actual error. |clear| is 1 or 0.476*/477void err_clear_last_constant_time(int clear);478479#endif /* OSSL_INTERNAL_CONSTANT_TIME_H */480481482