117f01e99SJung-uk Kim /* 2*44096ebdSEnji Cooper * Copyright 2014-2024 The OpenSSL Project Authors. All Rights Reserved. 317f01e99SJung-uk Kim * 4b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 517f01e99SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 617f01e99SJung-uk Kim * in the file LICENSE in the source distribution or at 717f01e99SJung-uk Kim * https://www.openssl.org/source/license.html 817f01e99SJung-uk Kim */ 917f01e99SJung-uk Kim 1017f01e99SJung-uk Kim #ifndef OSSL_INTERNAL_CONSTANT_TIME_H 1117f01e99SJung-uk Kim # define OSSL_INTERNAL_CONSTANT_TIME_H 12b077aed3SPierre Pronchery # pragma once 1317f01e99SJung-uk Kim 1417f01e99SJung-uk Kim # include <stdlib.h> 1517f01e99SJung-uk Kim # include <string.h> 1617f01e99SJung-uk Kim # include <openssl/e_os2.h> /* For 'ossl_inline' */ 1717f01e99SJung-uk Kim 1817f01e99SJung-uk Kim /*- 1917f01e99SJung-uk Kim * The boolean methods return a bitmask of all ones (0xff...f) for true 2017f01e99SJung-uk Kim * and 0 for false. This is useful for choosing a value based on the result 2117f01e99SJung-uk Kim * of a conditional in constant time. For example, 2217f01e99SJung-uk Kim * if (a < b) { 2317f01e99SJung-uk Kim * c = a; 2417f01e99SJung-uk Kim * } else { 2517f01e99SJung-uk Kim * c = b; 2617f01e99SJung-uk Kim * } 2717f01e99SJung-uk Kim * can be written as 2817f01e99SJung-uk Kim * unsigned int lt = constant_time_lt(a, b); 2917f01e99SJung-uk Kim * c = constant_time_select(lt, a, b); 3017f01e99SJung-uk Kim */ 3117f01e99SJung-uk Kim 3217f01e99SJung-uk Kim /* Returns the given value with the MSB copied to all the other bits. */ 3317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_msb(unsigned int a); 3417f01e99SJung-uk Kim /* Convenience method for uint32_t. */ 3517f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_msb_32(uint32_t a); 3617f01e99SJung-uk Kim /* Convenience method for uint64_t. */ 3717f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_msb_64(uint64_t a); 3817f01e99SJung-uk Kim 3917f01e99SJung-uk Kim /* Returns 0xff..f if a < b and 0 otherwise. */ 4017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_lt(unsigned int a, 4117f01e99SJung-uk Kim unsigned int b); 4217f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */ 4317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_lt_8(unsigned int a, 4417f01e99SJung-uk Kim unsigned int b); 4517f01e99SJung-uk Kim /* Convenience method for uint64_t. */ 4617f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b); 4717f01e99SJung-uk Kim 4817f01e99SJung-uk Kim /* Returns 0xff..f if a >= b and 0 otherwise. */ 4917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a, 5017f01e99SJung-uk Kim unsigned int b); 5117f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */ 5217f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a, 5317f01e99SJung-uk Kim unsigned int b); 5417f01e99SJung-uk Kim 5517f01e99SJung-uk Kim /* Returns 0xff..f if a == 0 and 0 otherwise. */ 5617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a); 5717f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */ 5817f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a); 5917f01e99SJung-uk Kim /* Convenience method for getting a 32-bit mask. */ 6017f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a); 6117f01e99SJung-uk Kim 6217f01e99SJung-uk Kim /* Returns 0xff..f if a == b and 0 otherwise. */ 6317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a, 6417f01e99SJung-uk Kim unsigned int b); 6517f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */ 6617f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a, 6717f01e99SJung-uk Kim unsigned int b); 6817f01e99SJung-uk Kim /* Signed integers. */ 6917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b); 7017f01e99SJung-uk Kim /* Convenience method for getting an 8-bit mask. */ 7117f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b); 7217f01e99SJung-uk Kim 7317f01e99SJung-uk Kim /*- 7417f01e99SJung-uk Kim * Returns (mask & a) | (~mask & b). 7517f01e99SJung-uk Kim * 7617f01e99SJung-uk Kim * When |mask| is all 1s or all 0s (as returned by the methods above), 7717f01e99SJung-uk Kim * the select methods return either |a| (if |mask| is nonzero) or |b| 7817f01e99SJung-uk Kim * (if |mask| is zero). 7917f01e99SJung-uk Kim */ 8017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask, 8117f01e99SJung-uk Kim unsigned int a, 8217f01e99SJung-uk Kim unsigned int b); 8317f01e99SJung-uk Kim /* Convenience method for unsigned chars. */ 8417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask, 8517f01e99SJung-uk Kim unsigned char a, 8617f01e99SJung-uk Kim unsigned char b); 8717f01e99SJung-uk Kim 8817f01e99SJung-uk Kim /* Convenience method for uint32_t. */ 8917f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, 9017f01e99SJung-uk Kim uint32_t b); 9117f01e99SJung-uk Kim 9217f01e99SJung-uk Kim /* Convenience method for uint64_t. */ 9317f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, 9417f01e99SJung-uk Kim uint64_t b); 9517f01e99SJung-uk Kim /* Convenience method for signed integers. */ 9617f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a, 9717f01e99SJung-uk Kim int b); 9817f01e99SJung-uk Kim 9917f01e99SJung-uk Kim 10017f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_msb(unsigned int a) 10117f01e99SJung-uk Kim { 10217f01e99SJung-uk Kim return 0 - (a >> (sizeof(a) * 8 - 1)); 10317f01e99SJung-uk Kim } 10417f01e99SJung-uk Kim 10517f01e99SJung-uk Kim 10617f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_msb_32(uint32_t a) 10717f01e99SJung-uk Kim { 10817f01e99SJung-uk Kim return 0 - (a >> 31); 10917f01e99SJung-uk Kim } 11017f01e99SJung-uk Kim 11117f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_msb_64(uint64_t a) 11217f01e99SJung-uk Kim { 11317f01e99SJung-uk Kim return 0 - (a >> 63); 11417f01e99SJung-uk Kim } 11517f01e99SJung-uk Kim 11617f01e99SJung-uk Kim static ossl_inline size_t constant_time_msb_s(size_t a) 11717f01e99SJung-uk Kim { 11817f01e99SJung-uk Kim return 0 - (a >> (sizeof(a) * 8 - 1)); 11917f01e99SJung-uk Kim } 12017f01e99SJung-uk Kim 12117f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_lt(unsigned int a, 12217f01e99SJung-uk Kim unsigned int b) 12317f01e99SJung-uk Kim { 12417f01e99SJung-uk Kim return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b))); 12517f01e99SJung-uk Kim } 12617f01e99SJung-uk Kim 12717f01e99SJung-uk Kim static ossl_inline size_t constant_time_lt_s(size_t a, size_t b) 12817f01e99SJung-uk Kim { 12917f01e99SJung-uk Kim return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b))); 13017f01e99SJung-uk Kim } 13117f01e99SJung-uk Kim 13217f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_lt_8(unsigned int a, 13317f01e99SJung-uk Kim unsigned int b) 13417f01e99SJung-uk Kim { 13517f01e99SJung-uk Kim return (unsigned char)constant_time_lt(a, b); 13617f01e99SJung-uk Kim } 13717f01e99SJung-uk Kim 13817f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b) 13917f01e99SJung-uk Kim { 14017f01e99SJung-uk Kim return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b))); 14117f01e99SJung-uk Kim } 14217f01e99SJung-uk Kim 143*44096ebdSEnji Cooper #ifdef BN_ULONG 144*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a) 145*44096ebdSEnji Cooper { 146*44096ebdSEnji Cooper return 0 - (a >> (sizeof(a) * 8 - 1)); 147*44096ebdSEnji Cooper } 148*44096ebdSEnji Cooper 149*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b) 150*44096ebdSEnji Cooper { 151*44096ebdSEnji Cooper return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b))); 152*44096ebdSEnji Cooper } 153*44096ebdSEnji Cooper 154*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a) 155*44096ebdSEnji Cooper { 156*44096ebdSEnji Cooper return constant_time_msb_bn(~a & (a - 1)); 157*44096ebdSEnji Cooper } 158*44096ebdSEnji Cooper 159*44096ebdSEnji Cooper static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a, 160*44096ebdSEnji Cooper BN_ULONG b) 161*44096ebdSEnji Cooper { 162*44096ebdSEnji Cooper return constant_time_is_zero_bn(a ^ b); 163*44096ebdSEnji Cooper } 164*44096ebdSEnji Cooper #endif 165*44096ebdSEnji Cooper 16617f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_ge(unsigned int a, 16717f01e99SJung-uk Kim unsigned int b) 16817f01e99SJung-uk Kim { 16917f01e99SJung-uk Kim return ~constant_time_lt(a, b); 17017f01e99SJung-uk Kim } 17117f01e99SJung-uk Kim 17217f01e99SJung-uk Kim static ossl_inline size_t constant_time_ge_s(size_t a, size_t b) 17317f01e99SJung-uk Kim { 17417f01e99SJung-uk Kim return ~constant_time_lt_s(a, b); 17517f01e99SJung-uk Kim } 17617f01e99SJung-uk Kim 17717f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8(unsigned int a, 17817f01e99SJung-uk Kim unsigned int b) 17917f01e99SJung-uk Kim { 18017f01e99SJung-uk Kim return (unsigned char)constant_time_ge(a, b); 18117f01e99SJung-uk Kim } 18217f01e99SJung-uk Kim 18317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b) 18417f01e99SJung-uk Kim { 18517f01e99SJung-uk Kim return (unsigned char)constant_time_ge_s(a, b); 18617f01e99SJung-uk Kim } 18717f01e99SJung-uk Kim 18817f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_is_zero(unsigned int a) 18917f01e99SJung-uk Kim { 19017f01e99SJung-uk Kim return constant_time_msb(~a & (a - 1)); 19117f01e99SJung-uk Kim } 19217f01e99SJung-uk Kim 19317f01e99SJung-uk Kim static ossl_inline size_t constant_time_is_zero_s(size_t a) 19417f01e99SJung-uk Kim { 19517f01e99SJung-uk Kim return constant_time_msb_s(~a & (a - 1)); 19617f01e99SJung-uk Kim } 19717f01e99SJung-uk Kim 19817f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a) 19917f01e99SJung-uk Kim { 20017f01e99SJung-uk Kim return (unsigned char)constant_time_is_zero(a); 20117f01e99SJung-uk Kim } 20217f01e99SJung-uk Kim 20317f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a) 20417f01e99SJung-uk Kim { 20517f01e99SJung-uk Kim return constant_time_msb_32(~a & (a - 1)); 20617f01e99SJung-uk Kim } 20717f01e99SJung-uk Kim 208b077aed3SPierre Pronchery static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a) 209b077aed3SPierre Pronchery { 210b077aed3SPierre Pronchery return constant_time_msb_64(~a & (a - 1)); 211b077aed3SPierre Pronchery } 212b077aed3SPierre Pronchery 21317f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq(unsigned int a, 21417f01e99SJung-uk Kim unsigned int b) 21517f01e99SJung-uk Kim { 21617f01e99SJung-uk Kim return constant_time_is_zero(a ^ b); 21717f01e99SJung-uk Kim } 21817f01e99SJung-uk Kim 21917f01e99SJung-uk Kim static ossl_inline size_t constant_time_eq_s(size_t a, size_t b) 22017f01e99SJung-uk Kim { 22117f01e99SJung-uk Kim return constant_time_is_zero_s(a ^ b); 22217f01e99SJung-uk Kim } 22317f01e99SJung-uk Kim 22417f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8(unsigned int a, 22517f01e99SJung-uk Kim unsigned int b) 22617f01e99SJung-uk Kim { 22717f01e99SJung-uk Kim return (unsigned char)constant_time_eq(a, b); 22817f01e99SJung-uk Kim } 22917f01e99SJung-uk Kim 23017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b) 23117f01e99SJung-uk Kim { 23217f01e99SJung-uk Kim return (unsigned char)constant_time_eq_s(a, b); 23317f01e99SJung-uk Kim } 23417f01e99SJung-uk Kim 23517f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_eq_int(int a, int b) 23617f01e99SJung-uk Kim { 23717f01e99SJung-uk Kim return constant_time_eq((unsigned)(a), (unsigned)(b)); 23817f01e99SJung-uk Kim } 23917f01e99SJung-uk Kim 24017f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_eq_int_8(int a, int b) 24117f01e99SJung-uk Kim { 24217f01e99SJung-uk Kim return constant_time_eq_8((unsigned)(a), (unsigned)(b)); 24317f01e99SJung-uk Kim } 24417f01e99SJung-uk Kim 24517f01e99SJung-uk Kim /* 24617f01e99SJung-uk Kim * Returns the value unmodified, but avoids optimizations. 24717f01e99SJung-uk Kim * The barriers prevent the compiler from narrowing down the 24817f01e99SJung-uk Kim * possible value range of the mask and ~mask in the select 24917f01e99SJung-uk Kim * statements, which avoids the recognition of the select 25017f01e99SJung-uk Kim * and turning it into a conditional load or branch. 25117f01e99SJung-uk Kim */ 25217f01e99SJung-uk Kim static ossl_inline unsigned int value_barrier(unsigned int a) 25317f01e99SJung-uk Kim { 25417f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 25517f01e99SJung-uk Kim unsigned int r; 25617f01e99SJung-uk Kim __asm__("" : "=r"(r) : "0"(a)); 25717f01e99SJung-uk Kim #else 25817f01e99SJung-uk Kim volatile unsigned int r = a; 25917f01e99SJung-uk Kim #endif 26017f01e99SJung-uk Kim return r; 26117f01e99SJung-uk Kim } 26217f01e99SJung-uk Kim 26317f01e99SJung-uk Kim /* Convenience method for uint32_t. */ 26417f01e99SJung-uk Kim static ossl_inline uint32_t value_barrier_32(uint32_t a) 26517f01e99SJung-uk Kim { 26617f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 26717f01e99SJung-uk Kim uint32_t r; 26817f01e99SJung-uk Kim __asm__("" : "=r"(r) : "0"(a)); 26917f01e99SJung-uk Kim #else 27017f01e99SJung-uk Kim volatile uint32_t r = a; 27117f01e99SJung-uk Kim #endif 27217f01e99SJung-uk Kim return r; 27317f01e99SJung-uk Kim } 27417f01e99SJung-uk Kim 27517f01e99SJung-uk Kim /* Convenience method for uint64_t. */ 27617f01e99SJung-uk Kim static ossl_inline uint64_t value_barrier_64(uint64_t a) 27717f01e99SJung-uk Kim { 27817f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 27917f01e99SJung-uk Kim uint64_t r; 28017f01e99SJung-uk Kim __asm__("" : "=r"(r) : "0"(a)); 28117f01e99SJung-uk Kim #else 28217f01e99SJung-uk Kim volatile uint64_t r = a; 28317f01e99SJung-uk Kim #endif 28417f01e99SJung-uk Kim return r; 28517f01e99SJung-uk Kim } 28617f01e99SJung-uk Kim 28717f01e99SJung-uk Kim /* Convenience method for size_t. */ 28817f01e99SJung-uk Kim static ossl_inline size_t value_barrier_s(size_t a) 28917f01e99SJung-uk Kim { 29017f01e99SJung-uk Kim #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 29117f01e99SJung-uk Kim size_t r; 29217f01e99SJung-uk Kim __asm__("" : "=r"(r) : "0"(a)); 29317f01e99SJung-uk Kim #else 29417f01e99SJung-uk Kim volatile size_t r = a; 29517f01e99SJung-uk Kim #endif 29617f01e99SJung-uk Kim return r; 29717f01e99SJung-uk Kim } 29817f01e99SJung-uk Kim 29917f01e99SJung-uk Kim static ossl_inline unsigned int constant_time_select(unsigned int mask, 30017f01e99SJung-uk Kim unsigned int a, 30117f01e99SJung-uk Kim unsigned int b) 30217f01e99SJung-uk Kim { 30317f01e99SJung-uk Kim return (value_barrier(mask) & a) | (value_barrier(~mask) & b); 30417f01e99SJung-uk Kim } 30517f01e99SJung-uk Kim 30617f01e99SJung-uk Kim static ossl_inline size_t constant_time_select_s(size_t mask, 30717f01e99SJung-uk Kim size_t a, 30817f01e99SJung-uk Kim size_t b) 30917f01e99SJung-uk Kim { 31017f01e99SJung-uk Kim return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b); 31117f01e99SJung-uk Kim } 31217f01e99SJung-uk Kim 31317f01e99SJung-uk Kim static ossl_inline unsigned char constant_time_select_8(unsigned char mask, 31417f01e99SJung-uk Kim unsigned char a, 31517f01e99SJung-uk Kim unsigned char b) 31617f01e99SJung-uk Kim { 31717f01e99SJung-uk Kim return (unsigned char)constant_time_select(mask, a, b); 31817f01e99SJung-uk Kim } 31917f01e99SJung-uk Kim 32017f01e99SJung-uk Kim static ossl_inline int constant_time_select_int(unsigned int mask, int a, 32117f01e99SJung-uk Kim int b) 32217f01e99SJung-uk Kim { 32317f01e99SJung-uk Kim return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b)); 32417f01e99SJung-uk Kim } 32517f01e99SJung-uk Kim 32617f01e99SJung-uk Kim static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b) 32717f01e99SJung-uk Kim { 32817f01e99SJung-uk Kim return (int)constant_time_select((unsigned)mask, (unsigned)(a), 32917f01e99SJung-uk Kim (unsigned)(b)); 33017f01e99SJung-uk Kim } 33117f01e99SJung-uk Kim 33217f01e99SJung-uk Kim static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, 33317f01e99SJung-uk Kim uint32_t b) 33417f01e99SJung-uk Kim { 33517f01e99SJung-uk Kim return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b); 33617f01e99SJung-uk Kim } 33717f01e99SJung-uk Kim 33817f01e99SJung-uk Kim static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, 33917f01e99SJung-uk Kim uint64_t b) 34017f01e99SJung-uk Kim { 34117f01e99SJung-uk Kim return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b); 34217f01e99SJung-uk Kim } 34317f01e99SJung-uk Kim 34417f01e99SJung-uk Kim /* 34517f01e99SJung-uk Kim * mask must be 0xFFFFFFFF or 0x00000000. 34617f01e99SJung-uk Kim * 34717f01e99SJung-uk Kim * if (mask) { 34817f01e99SJung-uk Kim * uint32_t tmp = *a; 34917f01e99SJung-uk Kim * 35017f01e99SJung-uk Kim * *a = *b; 35117f01e99SJung-uk Kim * *b = tmp; 35217f01e99SJung-uk Kim * } 35317f01e99SJung-uk Kim */ 35417f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a, 35517f01e99SJung-uk Kim uint32_t *b) 35617f01e99SJung-uk Kim { 35717f01e99SJung-uk Kim uint32_t xor = *a ^ *b; 35817f01e99SJung-uk Kim 35917f01e99SJung-uk Kim xor &= mask; 36017f01e99SJung-uk Kim *a ^= xor; 36117f01e99SJung-uk Kim *b ^= xor; 36217f01e99SJung-uk Kim } 36317f01e99SJung-uk Kim 36417f01e99SJung-uk Kim /* 36517f01e99SJung-uk Kim * mask must be 0xFFFFFFFF or 0x00000000. 36617f01e99SJung-uk Kim * 36717f01e99SJung-uk Kim * if (mask) { 36817f01e99SJung-uk Kim * uint64_t tmp = *a; 36917f01e99SJung-uk Kim * 37017f01e99SJung-uk Kim * *a = *b; 37117f01e99SJung-uk Kim * *b = tmp; 37217f01e99SJung-uk Kim * } 37317f01e99SJung-uk Kim */ 37417f01e99SJung-uk Kim static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a, 37517f01e99SJung-uk Kim uint64_t *b) 37617f01e99SJung-uk Kim { 37717f01e99SJung-uk Kim uint64_t xor = *a ^ *b; 37817f01e99SJung-uk Kim 37917f01e99SJung-uk Kim xor &= mask; 38017f01e99SJung-uk Kim *a ^= xor; 38117f01e99SJung-uk Kim *b ^= xor; 38217f01e99SJung-uk Kim } 38317f01e99SJung-uk Kim 38417f01e99SJung-uk Kim /* 385b077aed3SPierre Pronchery * mask must be 0xFF or 0x00. 386b077aed3SPierre Pronchery * "constant time" is per len. 387b077aed3SPierre Pronchery * 388b077aed3SPierre Pronchery * if (mask) { 389b077aed3SPierre Pronchery * unsigned char tmp[len]; 390b077aed3SPierre Pronchery * 391b077aed3SPierre Pronchery * memcpy(tmp, a, len); 392b077aed3SPierre Pronchery * memcpy(a, b); 393b077aed3SPierre Pronchery * memcpy(b, tmp); 394b077aed3SPierre Pronchery * } 395b077aed3SPierre Pronchery */ 396b077aed3SPierre Pronchery static ossl_inline void constant_time_cond_swap_buff(unsigned char mask, 397b077aed3SPierre Pronchery unsigned char *a, 398b077aed3SPierre Pronchery unsigned char *b, 399b077aed3SPierre Pronchery size_t len) 400b077aed3SPierre Pronchery { 401b077aed3SPierre Pronchery size_t i; 402b077aed3SPierre Pronchery unsigned char tmp; 403b077aed3SPierre Pronchery 404b077aed3SPierre Pronchery for (i = 0; i < len; i++) { 405b077aed3SPierre Pronchery tmp = a[i] ^ b[i]; 406b077aed3SPierre Pronchery tmp &= mask; 407b077aed3SPierre Pronchery a[i] ^= tmp; 408b077aed3SPierre Pronchery b[i] ^= tmp; 409b077aed3SPierre Pronchery } 410b077aed3SPierre Pronchery } 411b077aed3SPierre Pronchery 412b077aed3SPierre Pronchery /* 41317f01e99SJung-uk Kim * table is a two dimensional array of bytes. Each row has rowsize elements. 41417f01e99SJung-uk Kim * Copies row number idx into out. rowsize and numrows are not considered 41517f01e99SJung-uk Kim * private. 41617f01e99SJung-uk Kim */ 41717f01e99SJung-uk Kim static ossl_inline void constant_time_lookup(void *out, 41817f01e99SJung-uk Kim const void *table, 41917f01e99SJung-uk Kim size_t rowsize, 42017f01e99SJung-uk Kim size_t numrows, 42117f01e99SJung-uk Kim size_t idx) 42217f01e99SJung-uk Kim { 42317f01e99SJung-uk Kim size_t i, j; 42417f01e99SJung-uk Kim const unsigned char *tablec = (const unsigned char *)table; 42517f01e99SJung-uk Kim unsigned char *outc = (unsigned char *)out; 42617f01e99SJung-uk Kim unsigned char mask; 42717f01e99SJung-uk Kim 42817f01e99SJung-uk Kim memset(out, 0, rowsize); 42917f01e99SJung-uk Kim 43017f01e99SJung-uk Kim /* Note idx may underflow - but that is well defined */ 43117f01e99SJung-uk Kim for (i = 0; i < numrows; i++, idx--) { 43217f01e99SJung-uk Kim mask = (unsigned char)constant_time_is_zero_s(idx); 43317f01e99SJung-uk Kim for (j = 0; j < rowsize; j++) 43417f01e99SJung-uk Kim *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0); 43517f01e99SJung-uk Kim } 43617f01e99SJung-uk Kim } 43717f01e99SJung-uk Kim 43817f01e99SJung-uk Kim /* 43917f01e99SJung-uk Kim * Expected usage pattern is to unconditionally set error and then 44017f01e99SJung-uk Kim * wipe it if there was no actual error. |clear| is 1 or 0. 44117f01e99SJung-uk Kim */ 44217f01e99SJung-uk Kim void err_clear_last_constant_time(int clear); 44317f01e99SJung-uk Kim 44417f01e99SJung-uk Kim #endif /* OSSL_INTERNAL_CONSTANT_TIME_H */ 445