Path: blob/main/crypto/openssl/include/internal/constant_time.h
34879 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);100101102static ossl_inline unsigned int constant_time_msb(unsigned int a)103{104return 0 - (a >> (sizeof(a) * 8 - 1));105}106107108static ossl_inline uint32_t constant_time_msb_32(uint32_t a)109{110return 0 - (a >> 31);111}112113static ossl_inline uint64_t constant_time_msb_64(uint64_t a)114{115return 0 - (a >> 63);116}117118static ossl_inline size_t constant_time_msb_s(size_t a)119{120return 0 - (a >> (sizeof(a) * 8 - 1));121}122123static ossl_inline unsigned int constant_time_lt(unsigned int a,124unsigned int b)125{126return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));127}128129static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)130{131return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));132}133134static ossl_inline unsigned char constant_time_lt_8(unsigned int a,135unsigned int b)136{137return (unsigned char)constant_time_lt(a, b);138}139140static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b)141{142return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b)));143}144145static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)146{147return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));148}149150#ifdef BN_ULONG151static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)152{153#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)154BN_ULONG r;155__asm__("" : "=r"(r) : "0"(a));156#else157volatile BN_ULONG r = a;158#endif159return r;160}161162static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)163{164return 0 - (a >> (sizeof(a) * 8 - 1));165}166167static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)168{169return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));170}171172static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)173{174return constant_time_msb_bn(~a & (a - 1));175}176177static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,178BN_ULONG b)179{180return constant_time_is_zero_bn(a ^ b);181}182183static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,184BN_ULONG a,185BN_ULONG b)186{187return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);188}189#endif190191static ossl_inline unsigned int constant_time_ge(unsigned int a,192unsigned int b)193{194return ~constant_time_lt(a, b);195}196197static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)198{199return ~constant_time_lt_s(a, b);200}201202static ossl_inline unsigned char constant_time_ge_8(unsigned int a,203unsigned int b)204{205return (unsigned char)constant_time_ge(a, b);206}207208static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)209{210return (unsigned char)constant_time_ge_s(a, b);211}212213static ossl_inline unsigned int constant_time_is_zero(unsigned int a)214{215return constant_time_msb(~a & (a - 1));216}217218static ossl_inline size_t constant_time_is_zero_s(size_t a)219{220return constant_time_msb_s(~a & (a - 1));221}222223static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)224{225return (unsigned char)constant_time_is_zero(a);226}227228static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)229{230return constant_time_msb_32(~a & (a - 1));231}232233static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)234{235return constant_time_msb_64(~a & (a - 1));236}237238static ossl_inline unsigned int constant_time_eq(unsigned int a,239unsigned int b)240{241return constant_time_is_zero(a ^ b);242}243244static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)245{246return constant_time_is_zero_s(a ^ b);247}248249static ossl_inline unsigned char constant_time_eq_8(unsigned int a,250unsigned int b)251{252return (unsigned char)constant_time_eq(a, b);253}254255static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)256{257return (unsigned char)constant_time_eq_s(a, b);258}259260static ossl_inline unsigned int constant_time_eq_int(int a, int b)261{262return constant_time_eq((unsigned)(a), (unsigned)(b));263}264265static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)266{267return constant_time_eq_8((unsigned)(a), (unsigned)(b));268}269270/*271* Returns the value unmodified, but avoids optimizations.272* The barriers prevent the compiler from narrowing down the273* possible value range of the mask and ~mask in the select274* statements, which avoids the recognition of the select275* and turning it into a conditional load or branch.276*/277static ossl_inline unsigned int value_barrier(unsigned int a)278{279#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)280unsigned int r;281__asm__("" : "=r"(r) : "0"(a));282#else283volatile unsigned int r = a;284#endif285return r;286}287288/* Convenience method for uint32_t. */289static ossl_inline uint32_t value_barrier_32(uint32_t a)290{291#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)292uint32_t r;293__asm__("" : "=r"(r) : "0"(a));294#else295volatile uint32_t r = a;296#endif297return r;298}299300/* Convenience method for uint64_t. */301static ossl_inline uint64_t value_barrier_64(uint64_t a)302{303#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)304uint64_t r;305__asm__("" : "=r"(r) : "0"(a));306#else307volatile uint64_t r = a;308#endif309return r;310}311312/* Convenience method for size_t. */313static ossl_inline size_t value_barrier_s(size_t a)314{315#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)316size_t r;317__asm__("" : "=r"(r) : "0"(a));318#else319volatile size_t r = a;320#endif321return r;322}323324/* Convenience method for unsigned char. */325static ossl_inline unsigned char value_barrier_8(unsigned char a)326{327#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)328unsigned char r;329__asm__("" : "=r"(r) : "0"(a));330#else331volatile unsigned char r = a;332#endif333return r;334}335336static ossl_inline unsigned int constant_time_select(unsigned int mask,337unsigned int a,338unsigned int b)339{340return (value_barrier(mask) & a) | (value_barrier(~mask) & b);341}342343static ossl_inline size_t constant_time_select_s(size_t mask,344size_t a,345size_t b)346{347return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);348}349350static ossl_inline unsigned char constant_time_select_8(unsigned char mask,351unsigned char a,352unsigned char b)353{354return (unsigned char)constant_time_select(mask, a, b);355}356357static ossl_inline int constant_time_select_int(unsigned int mask, int a,358int b)359{360return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));361}362363static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)364{365return (int)constant_time_select((unsigned)mask, (unsigned)(a),366(unsigned)(b));367}368369static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,370uint32_t b)371{372return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);373}374375static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,376uint64_t b)377{378return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);379}380381/*382* mask must be 0xFFFFFFFF or 0x00000000.383*384* if (mask) {385* uint32_t tmp = *a;386*387* *a = *b;388* *b = tmp;389* }390*/391static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,392uint32_t *b)393{394uint32_t xor = *a ^ *b;395396xor &= value_barrier_32(mask);397*a ^= xor;398*b ^= xor;399}400401/*402* mask must be 0xFFFFFFFF or 0x00000000.403*404* if (mask) {405* uint64_t tmp = *a;406*407* *a = *b;408* *b = tmp;409* }410*/411static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,412uint64_t *b)413{414uint64_t xor = *a ^ *b;415416xor &= value_barrier_64(mask);417*a ^= xor;418*b ^= xor;419}420421/*422* mask must be 0xFF or 0x00.423* "constant time" is per len.424*425* if (mask) {426* unsigned char tmp[len];427*428* memcpy(tmp, a, len);429* memcpy(a, b);430* memcpy(b, tmp);431* }432*/433static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,434unsigned char *a,435unsigned char *b,436size_t len)437{438size_t i;439unsigned char tmp;440441for (i = 0; i < len; i++) {442tmp = a[i] ^ b[i];443tmp &= value_barrier_8(mask);444a[i] ^= tmp;445b[i] ^= tmp;446}447}448449/*450* table is a two dimensional array of bytes. Each row has rowsize elements.451* Copies row number idx into out. rowsize and numrows are not considered452* private.453*/454static ossl_inline void constant_time_lookup(void *out,455const void *table,456size_t rowsize,457size_t numrows,458size_t idx)459{460size_t i, j;461const unsigned char *tablec = (const unsigned char *)table;462unsigned char *outc = (unsigned char *)out;463unsigned char mask;464465memset(out, 0, rowsize);466467/* Note idx may underflow - but that is well defined */468for (i = 0; i < numrows; i++, idx--) {469mask = (unsigned char)constant_time_is_zero_s(idx);470for (j = 0; j < rowsize; j++)471*(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);472}473}474475/*476* Expected usage pattern is to unconditionally set error and then477* wipe it if there was no actual error. |clear| is 1 or 0.478*/479void err_clear_last_constant_time(int clear);480481#endif /* OSSL_INTERNAL_CONSTANT_TIME_H */482483484