Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/include/internal/constant_time.h
34879 views
1
/*
2
* Copyright 2014-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
#ifndef OSSL_INTERNAL_CONSTANT_TIME_H
11
# define OSSL_INTERNAL_CONSTANT_TIME_H
12
# pragma once
13
14
# include <stdlib.h>
15
# include <string.h>
16
# include <openssl/e_os2.h> /* For 'ossl_inline' */
17
18
/*-
19
* The boolean methods return a bitmask of all ones (0xff...f) for true
20
* and 0 for false. This is useful for choosing a value based on the result
21
* of a conditional in constant time. For example,
22
* if (a < b) {
23
* c = a;
24
* } else {
25
* c = b;
26
* }
27
* can be written as
28
* unsigned int lt = constant_time_lt(a, b);
29
* c = constant_time_select(lt, a, b);
30
*/
31
32
/* Returns the given value with the MSB copied to all the other bits. */
33
static ossl_inline unsigned int constant_time_msb(unsigned int a);
34
/* Convenience method for uint32_t. */
35
static ossl_inline uint32_t constant_time_msb_32(uint32_t a);
36
/* Convenience method for uint64_t. */
37
static ossl_inline uint64_t constant_time_msb_64(uint64_t a);
38
39
/* Returns 0xff..f if a < b and 0 otherwise. */
40
static ossl_inline unsigned int constant_time_lt(unsigned int a,
41
unsigned int b);
42
/* Convenience method for getting an 8-bit mask. */
43
static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
44
unsigned int b);
45
/* Convenience method for uint32_t. */
46
static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b);
47
48
/* Convenience method for uint64_t. */
49
static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b);
50
51
/* Returns 0xff..f if a >= b and 0 otherwise. */
52
static ossl_inline unsigned int constant_time_ge(unsigned int a,
53
unsigned int b);
54
/* Convenience method for getting an 8-bit mask. */
55
static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
56
unsigned int b);
57
58
/* Returns 0xff..f if a == 0 and 0 otherwise. */
59
static ossl_inline unsigned int constant_time_is_zero(unsigned int a);
60
/* Convenience method for getting an 8-bit mask. */
61
static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a);
62
/* Convenience method for getting a 32-bit mask. */
63
static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a);
64
65
/* Returns 0xff..f if a == b and 0 otherwise. */
66
static ossl_inline unsigned int constant_time_eq(unsigned int a,
67
unsigned int b);
68
/* Convenience method for getting an 8-bit mask. */
69
static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
70
unsigned int b);
71
/* Signed integers. */
72
static ossl_inline unsigned int constant_time_eq_int(int a, int b);
73
/* Convenience method for getting an 8-bit mask. */
74
static ossl_inline unsigned char constant_time_eq_int_8(int a, int b);
75
76
/*-
77
* Returns (mask & a) | (~mask & b).
78
*
79
* When |mask| is all 1s or all 0s (as returned by the methods above),
80
* the select methods return either |a| (if |mask| is nonzero) or |b|
81
* (if |mask| is zero).
82
*/
83
static ossl_inline unsigned int constant_time_select(unsigned int mask,
84
unsigned int a,
85
unsigned int b);
86
/* Convenience method for unsigned chars. */
87
static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
88
unsigned char a,
89
unsigned char b);
90
91
/* Convenience method for uint32_t. */
92
static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
93
uint32_t b);
94
95
/* Convenience method for uint64_t. */
96
static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
97
uint64_t b);
98
/* Convenience method for signed integers. */
99
static ossl_inline int constant_time_select_int(unsigned int mask, int a,
100
int b);
101
102
103
static ossl_inline unsigned int constant_time_msb(unsigned int a)
104
{
105
return 0 - (a >> (sizeof(a) * 8 - 1));
106
}
107
108
109
static ossl_inline uint32_t constant_time_msb_32(uint32_t a)
110
{
111
return 0 - (a >> 31);
112
}
113
114
static ossl_inline uint64_t constant_time_msb_64(uint64_t a)
115
{
116
return 0 - (a >> 63);
117
}
118
119
static ossl_inline size_t constant_time_msb_s(size_t a)
120
{
121
return 0 - (a >> (sizeof(a) * 8 - 1));
122
}
123
124
static ossl_inline unsigned int constant_time_lt(unsigned int a,
125
unsigned int b)
126
{
127
return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
128
}
129
130
static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)
131
{
132
return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
133
}
134
135
static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
136
unsigned int b)
137
{
138
return (unsigned char)constant_time_lt(a, b);
139
}
140
141
static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b)
142
{
143
return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b)));
144
}
145
146
static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
147
{
148
return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));
149
}
150
151
#ifdef BN_ULONG
152
static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)
153
{
154
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
155
BN_ULONG r;
156
__asm__("" : "=r"(r) : "0"(a));
157
#else
158
volatile BN_ULONG r = a;
159
#endif
160
return r;
161
}
162
163
static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)
164
{
165
return 0 - (a >> (sizeof(a) * 8 - 1));
166
}
167
168
static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)
169
{
170
return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));
171
}
172
173
static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)
174
{
175
return constant_time_msb_bn(~a & (a - 1));
176
}
177
178
static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,
179
BN_ULONG b)
180
{
181
return constant_time_is_zero_bn(a ^ b);
182
}
183
184
static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,
185
BN_ULONG a,
186
BN_ULONG b)
187
{
188
return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);
189
}
190
#endif
191
192
static ossl_inline unsigned int constant_time_ge(unsigned int a,
193
unsigned int b)
194
{
195
return ~constant_time_lt(a, b);
196
}
197
198
static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
199
{
200
return ~constant_time_lt_s(a, b);
201
}
202
203
static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
204
unsigned int b)
205
{
206
return (unsigned char)constant_time_ge(a, b);
207
}
208
209
static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
210
{
211
return (unsigned char)constant_time_ge_s(a, b);
212
}
213
214
static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
215
{
216
return constant_time_msb(~a & (a - 1));
217
}
218
219
static ossl_inline size_t constant_time_is_zero_s(size_t a)
220
{
221
return constant_time_msb_s(~a & (a - 1));
222
}
223
224
static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
225
{
226
return (unsigned char)constant_time_is_zero(a);
227
}
228
229
static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)
230
{
231
return constant_time_msb_32(~a & (a - 1));
232
}
233
234
static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)
235
{
236
return constant_time_msb_64(~a & (a - 1));
237
}
238
239
static ossl_inline unsigned int constant_time_eq(unsigned int a,
240
unsigned int b)
241
{
242
return constant_time_is_zero(a ^ b);
243
}
244
245
static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
246
{
247
return constant_time_is_zero_s(a ^ b);
248
}
249
250
static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
251
unsigned int b)
252
{
253
return (unsigned char)constant_time_eq(a, b);
254
}
255
256
static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
257
{
258
return (unsigned char)constant_time_eq_s(a, b);
259
}
260
261
static ossl_inline unsigned int constant_time_eq_int(int a, int b)
262
{
263
return constant_time_eq((unsigned)(a), (unsigned)(b));
264
}
265
266
static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)
267
{
268
return constant_time_eq_8((unsigned)(a), (unsigned)(b));
269
}
270
271
/*
272
* Returns the value unmodified, but avoids optimizations.
273
* The barriers prevent the compiler from narrowing down the
274
* possible value range of the mask and ~mask in the select
275
* statements, which avoids the recognition of the select
276
* and turning it into a conditional load or branch.
277
*/
278
static ossl_inline unsigned int value_barrier(unsigned int a)
279
{
280
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
281
unsigned int r;
282
__asm__("" : "=r"(r) : "0"(a));
283
#else
284
volatile unsigned int r = a;
285
#endif
286
return r;
287
}
288
289
/* Convenience method for uint32_t. */
290
static ossl_inline uint32_t value_barrier_32(uint32_t a)
291
{
292
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
293
uint32_t r;
294
__asm__("" : "=r"(r) : "0"(a));
295
#else
296
volatile uint32_t r = a;
297
#endif
298
return r;
299
}
300
301
/* Convenience method for uint64_t. */
302
static ossl_inline uint64_t value_barrier_64(uint64_t a)
303
{
304
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
305
uint64_t r;
306
__asm__("" : "=r"(r) : "0"(a));
307
#else
308
volatile uint64_t r = a;
309
#endif
310
return r;
311
}
312
313
/* Convenience method for size_t. */
314
static ossl_inline size_t value_barrier_s(size_t a)
315
{
316
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
317
size_t r;
318
__asm__("" : "=r"(r) : "0"(a));
319
#else
320
volatile size_t r = a;
321
#endif
322
return r;
323
}
324
325
/* Convenience method for unsigned char. */
326
static ossl_inline unsigned char value_barrier_8(unsigned char a)
327
{
328
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
329
unsigned char r;
330
__asm__("" : "=r"(r) : "0"(a));
331
#else
332
volatile unsigned char r = a;
333
#endif
334
return r;
335
}
336
337
static ossl_inline unsigned int constant_time_select(unsigned int mask,
338
unsigned int a,
339
unsigned int b)
340
{
341
return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
342
}
343
344
static ossl_inline size_t constant_time_select_s(size_t mask,
345
size_t a,
346
size_t b)
347
{
348
return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
349
}
350
351
static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
352
unsigned char a,
353
unsigned char b)
354
{
355
return (unsigned char)constant_time_select(mask, a, b);
356
}
357
358
static ossl_inline int constant_time_select_int(unsigned int mask, int a,
359
int b)
360
{
361
return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));
362
}
363
364
static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
365
{
366
return (int)constant_time_select((unsigned)mask, (unsigned)(a),
367
(unsigned)(b));
368
}
369
370
static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
371
uint32_t b)
372
{
373
return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);
374
}
375
376
static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
377
uint64_t b)
378
{
379
return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);
380
}
381
382
/*
383
* mask must be 0xFFFFFFFF or 0x00000000.
384
*
385
* if (mask) {
386
* uint32_t tmp = *a;
387
*
388
* *a = *b;
389
* *b = tmp;
390
* }
391
*/
392
static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,
393
uint32_t *b)
394
{
395
uint32_t xor = *a ^ *b;
396
397
xor &= value_barrier_32(mask);
398
*a ^= xor;
399
*b ^= xor;
400
}
401
402
/*
403
* mask must be 0xFFFFFFFF or 0x00000000.
404
*
405
* if (mask) {
406
* uint64_t tmp = *a;
407
*
408
* *a = *b;
409
* *b = tmp;
410
* }
411
*/
412
static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,
413
uint64_t *b)
414
{
415
uint64_t xor = *a ^ *b;
416
417
xor &= value_barrier_64(mask);
418
*a ^= xor;
419
*b ^= xor;
420
}
421
422
/*
423
* mask must be 0xFF or 0x00.
424
* "constant time" is per len.
425
*
426
* if (mask) {
427
* unsigned char tmp[len];
428
*
429
* memcpy(tmp, a, len);
430
* memcpy(a, b);
431
* memcpy(b, tmp);
432
* }
433
*/
434
static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,
435
unsigned char *a,
436
unsigned char *b,
437
size_t len)
438
{
439
size_t i;
440
unsigned char tmp;
441
442
for (i = 0; i < len; i++) {
443
tmp = a[i] ^ b[i];
444
tmp &= value_barrier_8(mask);
445
a[i] ^= tmp;
446
b[i] ^= tmp;
447
}
448
}
449
450
/*
451
* table is a two dimensional array of bytes. Each row has rowsize elements.
452
* Copies row number idx into out. rowsize and numrows are not considered
453
* private.
454
*/
455
static ossl_inline void constant_time_lookup(void *out,
456
const void *table,
457
size_t rowsize,
458
size_t numrows,
459
size_t idx)
460
{
461
size_t i, j;
462
const unsigned char *tablec = (const unsigned char *)table;
463
unsigned char *outc = (unsigned char *)out;
464
unsigned char mask;
465
466
memset(out, 0, rowsize);
467
468
/* Note idx may underflow - but that is well defined */
469
for (i = 0; i < numrows; i++, idx--) {
470
mask = (unsigned char)constant_time_is_zero_s(idx);
471
for (j = 0; j < rowsize; j++)
472
*(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);
473
}
474
}
475
476
/*
477
* Expected usage pattern is to unconditionally set error and then
478
* wipe it if there was no actual error. |clear| is 1 or 0.
479
*/
480
void err_clear_last_constant_time(int clear);
481
482
#endif /* OSSL_INTERNAL_CONSTANT_TIME_H */
483
484