blob: aa291d75c6bfaa1863a1d10808b2481ef4647ff3 [file] [log] [blame]
gabor-mezei-arm90559722021-07-12 16:31:22 +02001/**
2 * Constant-time functions
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#include "common.h"
gabor-mezei-arm944c1072021-09-27 11:28:54 +020021#include "constant_time.h"
gabor-mezei-armcb4317b2021-09-27 14:28:31 +020022#include "mbedtls/error.h"
gabor-mezei-arm944c1072021-09-27 11:28:54 +020023
gabor-mezei-arm097d4f52021-09-27 12:55:33 +020024#if defined(MBEDTLS_BIGNUM_C)
25#include "mbedtls/bignum.h"
26#endif
27
gabor-mezei-armcb4317b2021-09-27 14:28:31 +020028#if defined(MBEDTLS_SSL_TLS_C)
29#include "mbedtls/ssl_internal.h"
30#endif
31
gabor-mezei-arm097d4f52021-09-27 12:55:33 +020032
gabor-mezei-arm944c1072021-09-27 11:28:54 +020033/* constant-time buffer comparison */
34int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
35{
36 size_t i;
37 volatile const unsigned char *A = (volatile const unsigned char *) a;
38 volatile const unsigned char *B = (volatile const unsigned char *) b;
39 volatile unsigned char diff = 0;
40
41 for( i = 0; i < n; i++ )
42 {
43 /* Read volatile data in order before computing diff.
44 * This avoids IAR compiler warning:
45 * 'the order of volatile accesses is undefined ..' */
46 unsigned char x = A[i], y = B[i];
47 diff |= x ^ y;
48 }
49
50 return( diff );
51}
52
53/* Compare the contents of two buffers in constant time.
54 * Returns 0 if the contents are bitwise identical, otherwise returns
55 * a non-zero value.
56 * This is currently only used by GCM and ChaCha20+Poly1305.
57 */
58int mbedtls_constant_time_memcmp( const void *v1, const void *v2,
59 size_t len )
60{
61 const unsigned char *p1 = (const unsigned char*) v1;
62 const unsigned char *p2 = (const unsigned char*) v2;
63 size_t i;
64 unsigned char diff;
65
66 for( diff = 0, i = 0; i < len; i++ )
67 diff |= p1[i] ^ p2[i];
68
69 return( (int)diff );
70}
71
72/* constant-time buffer comparison */
73unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
74{
75 size_t i;
76 volatile const unsigned char *A = (volatile const unsigned char *) a;
77 volatile const unsigned char *B = (volatile const unsigned char *) b;
78 volatile unsigned char diff = 0;
79
80 for( i = 0; i < n; i++ )
81 {
82 /* Read volatile data in order before computing diff.
83 * This avoids IAR compiler warning:
84 * 'the order of volatile accesses is undefined ..' */
85 unsigned char x = A[i], y = B[i];
86 diff |= x ^ y;
87 }
88
89 return( diff );
90}
91
92/* constant-time buffer comparison */
93int mbedtls_safer_memcmp( const void *a, const void *b, size_t n )
94{
95 size_t i;
96 const unsigned char *A = (const unsigned char *) a;
97 const unsigned char *B = (const unsigned char *) b;
98 unsigned char diff = 0;
99
100 for( i = 0; i < n; i++ )
101 diff |= A[i] ^ B[i];
102
103 return( diff );
104}
gabor-mezei-armc11cac92021-09-27 11:40:03 +0200105
106/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
107 *
108 * \param value The value to analyze.
109 * \return Zero if \p value is zero, otherwise all-bits-one.
110 */
111unsigned mbedtls_cf_uint_mask( unsigned value )
112{
113 /* MSVC has a warning about unary minus on unsigned, but this is
114 * well-defined and precisely what we want to do here */
115#if defined(_MSC_VER)
116#pragma warning( push )
117#pragma warning( disable : 4146 )
118#endif
119 return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) );
120#if defined(_MSC_VER)
121#pragma warning( pop )
122#endif
123}
gabor-mezei-armd361ccd2021-09-27 11:49:42 +0200124
125/*
126 * Turn a bit into a mask:
127 * - if bit == 1, return the all-bits 1 mask, aka (size_t) -1
128 * - if bit == 0, return the all-bits 0 mask, aka 0
129 *
130 * This function can be used to write constant-time code by replacing branches
131 * with bit operations using masks.
132 *
133 * This function is implemented without using comparison operators, as those
134 * might be translated to branches by some compilers on some platforms.
135 */
136size_t mbedtls_cf_size_mask( size_t bit )
137{
138 /* MSVC has a warning about unary minus on unsigned integer types,
139 * but this is well-defined and precisely what we want to do here. */
140#if defined(_MSC_VER)
141#pragma warning( push )
142#pragma warning( disable : 4146 )
143#endif
144 return -bit;
145#if defined(_MSC_VER)
146#pragma warning( pop )
147#endif
148}
gabor-mezei-arm4d6b1462021-09-27 11:53:54 +0200149
150/*
151 * Constant-flow mask generation for "less than" comparison:
152 * - if x < y, return all bits 1, that is (size_t) -1
153 * - otherwise, return all bits 0, that is 0
154 *
155 * This function can be used to write constant-time code by replacing branches
156 * with bit operations using masks.
157 *
158 * This function is implemented without using comparison operators, as those
159 * might be translated to branches by some compilers on some platforms.
160 */
161size_t mbedtls_cf_size_mask_lt( size_t x, size_t y )
162{
163 /* This has the most significant bit set if and only if x < y */
164 const size_t sub = x - y;
165
166 /* sub1 = (x < y) ? 1 : 0 */
167 const size_t sub1 = sub >> ( sizeof( sub ) * 8 - 1 );
168
169 /* mask = (x < y) ? 0xff... : 0x00... */
170 const size_t mask = mbedtls_cf_size_mask( sub1 );
171
172 return( mask );
173}
gabor-mezei-arma2bcabc2021-09-27 11:58:31 +0200174
175/*
176 * Constant-flow mask generation for "greater or equal" comparison:
177 * - if x >= y, return all bits 1, that is (size_t) -1
178 * - otherwise, return all bits 0, that is 0
179 *
180 * This function can be used to write constant-time code by replacing branches
181 * with bit operations using masks.
182 *
183 * This function is implemented without using comparison operators, as those
184 * might be translated to branches by some compilers on some platforms.
185 */
186size_t mbedtls_cf_size_mask_ge( size_t x, size_t y )
187{
188 return( ~mbedtls_cf_size_mask_lt( x, y ) );
189}
gabor-mezei-arm96584dd2021-09-27 12:15:19 +0200190
191/*
192 * Constant-flow boolean "equal" comparison:
193 * return x == y
194 *
195 * This function can be used to write constant-time code by replacing branches
196 * with bit operations - it can be used in conjunction with
197 * mbedtls_ssl_cf_mask_from_bit().
198 *
199 * This function is implemented without using comparison operators, as those
200 * might be translated to branches by some compilers on some platforms.
201 */
202size_t mbedtls_cf_size_bool_eq( size_t x, size_t y )
203{
204 /* diff = 0 if x == y, non-zero otherwise */
205 const size_t diff = x ^ y;
206
207 /* MSVC has a warning about unary minus on unsigned integer types,
208 * but this is well-defined and precisely what we want to do here. */
209#if defined(_MSC_VER)
210#pragma warning( push )
211#pragma warning( disable : 4146 )
212#endif
213
214 /* diff_msb's most significant bit is equal to x != y */
215 const size_t diff_msb = ( diff | (size_t) -diff );
216
217#if defined(_MSC_VER)
218#pragma warning( pop )
219#endif
220
221 /* diff1 = (x != y) ? 1 : 0 */
222 const size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 );
223
224 return( 1 ^ diff1 );
225}
gabor-mezei-arm9d7bf092021-09-27 12:25:07 +0200226
227/** Check whether a size is out of bounds, without branches.
228 *
229 * This is equivalent to `size > max`, but is likely to be compiled to
230 * to code using bitwise operation rather than a branch.
231 *
232 * \param size Size to check.
233 * \param max Maximum desired value for \p size.
234 * \return \c 0 if `size <= max`.
235 * \return \c 1 if `size > max`.
236 */
237unsigned mbedtls_cf_size_gt( size_t size, size_t max )
238{
239 /* Return the sign bit (1 for negative) of (max - size). */
240 return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) );
241}
gabor-mezei-arm097d4f52021-09-27 12:55:33 +0200242
243#if defined(MBEDTLS_BIGNUM_C)
244
245/** Decide if an integer is less than the other, without branches.
246 *
247 * \param x First integer.
248 * \param y Second integer.
249 *
250 * \return 1 if \p x is less than \p y, 0 otherwise
251 */
252unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x,
253 const mbedtls_mpi_uint y )
254{
255 mbedtls_mpi_uint ret;
256 mbedtls_mpi_uint cond;
257
258 /*
259 * Check if the most significant bits (MSB) of the operands are different.
260 */
261 cond = ( x ^ y );
262 /*
263 * If the MSB are the same then the difference x-y will be negative (and
264 * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
265 */
266 ret = ( x - y ) & ~cond;
267 /*
268 * If the MSB are different, then the operand with the MSB of 1 is the
269 * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
270 * the MSB of y is 0.)
271 */
272 ret |= y & cond;
273
274
275 ret = ret >> ( sizeof( mbedtls_mpi_uint ) * 8 - 1 );
276
277 return (unsigned) ret;
278}
279
280#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-arm75332532021-09-27 12:59:30 +0200281
282/** Choose between two integer values, without branches.
283 *
284 * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled
285 * to code using bitwise operation rather than a branch.
286 *
287 * \param cond Condition to test.
288 * \param if1 Value to use if \p cond is nonzero.
289 * \param if0 Value to use if \p cond is zero.
290 * \return \c if1 if \p cond is nonzero, otherwise \c if0.
291 */
292unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 )
293{
294 unsigned mask = mbedtls_cf_uint_mask( cond );
295 return( ( mask & if1 ) | (~mask & if0 ) );
296}
gabor-mezei-arm5cec8b42021-09-27 13:03:57 +0200297
gabor-mezei-armbc3a2882021-09-27 15:47:00 +0200298size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 )
299{
300 size_t mask = mbedtls_cf_size_mask( cond );
301 return( ( mask & if1 ) | (~mask & if0 ) );
302}
303
gabor-mezei-arm5cec8b42021-09-27 13:03:57 +0200304/**
305 * Select between two sign values in constant-time.
306 *
307 * This is functionally equivalent to second ? a : b but uses only bit
308 * operations in order to avoid branches.
309 *
310 * \param[in] a The first sign; must be either +1 or -1.
311 * \param[in] b The second sign; must be either +1 or -1.
312 * \param[in] second Must be either 1 (return b) or 0 (return a).
313 *
314 * \return The selected sign value.
315 */
316int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second )
317{
318 /* In order to avoid questions about what we can reasonnably assume about
319 * the representations of signed integers, move everything to unsigned
320 * by taking advantage of the fact that a and b are either +1 or -1. */
321 unsigned ua = a + 1;
322 unsigned ub = b + 1;
323
324 /* second was 0 or 1, mask is 0 or 2 as are ua and ub */
325 const unsigned mask = second << 1;
326
327 /* select ua or ub */
328 unsigned ur = ( ua & ~mask ) | ( ub & mask );
329
330 /* ur is now 0 or 2, convert back to -1 or +1 */
331 return( (int) ur - 1 );
332}
gabor-mezei-arm043192d2021-09-27 13:17:15 +0200333
334#if defined(MBEDTLS_BIGNUM_C)
335
336/*
337 * Conditionally assign dest = src, without leaking information
338 * about whether the assignment was made or not.
339 * dest and src must be arrays of limbs of size n.
340 * assign must be 0 or 1.
341 */
342void mbedtls_cf_mpi_uint_cond_assign( size_t n,
343 mbedtls_mpi_uint *dest,
344 const mbedtls_mpi_uint *src,
345 unsigned char assign )
346{
347 size_t i;
348
349 /* MSVC has a warning about unary minus on unsigned integer types,
350 * but this is well-defined and precisely what we want to do here. */
351#if defined(_MSC_VER)
352#pragma warning( push )
353#pragma warning( disable : 4146 )
354#endif
355
356 /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
357 const mbedtls_mpi_uint mask = -assign;
358
359#if defined(_MSC_VER)
360#pragma warning( pop )
361#endif
362
363 for( i = 0; i < n; i++ )
364 dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask );
365}
366
367#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-arm7b23c0b2021-09-27 13:31:06 +0200368
369/** Shift some data towards the left inside a buffer without leaking
370 * the length of the data through side channels.
371 *
372 * `mbedtls_cf_mem_move_to_left(start, total, offset)` is functionally
373 * equivalent to
374 * ```
375 * memmove(start, start + offset, total - offset);
376 * memset(start + offset, 0, total - offset);
377 * ```
378 * but it strives to use a memory access pattern (and thus total timing)
379 * that does not depend on \p offset. This timing independence comes at
380 * the expense of performance.
381 *
382 * \param start Pointer to the start of the buffer.
383 * \param total Total size of the buffer.
384 * \param offset Offset from which to copy \p total - \p offset bytes.
385 */
386void mbedtls_cf_mem_move_to_left( void *start,
387 size_t total,
388 size_t offset )
389{
390 volatile unsigned char *buf = start;
391 size_t i, n;
392 if( total == 0 )
393 return;
394 for( i = 0; i < total; i++ )
395 {
396 unsigned no_op = mbedtls_cf_size_gt( total - offset, i );
397 /* The first `total - offset` passes are a no-op. The last
398 * `offset` passes shift the data one byte to the left and
399 * zero out the last byte. */
400 for( n = 0; n < total - 1; n++ )
401 {
402 unsigned char current = buf[n];
403 unsigned char next = buf[n+1];
404 buf[n] = mbedtls_cf_uint_if( no_op, current, next );
405 }
406 buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 );
407 }
408}
gabor-mezei-armee06feb2021-09-27 13:34:25 +0200409
410/*
411 * Constant-flow conditional memcpy:
412 * - if c1 == c2, equivalent to memcpy(dst, src, len),
413 * - otherwise, a no-op,
414 * but with execution flow independent of the values of c1 and c2.
415 *
416 * This function is implemented without using comparison operators, as those
417 * might be translated to branches by some compilers on some platforms.
418 */
419void mbedtls_cf_memcpy_if_eq( unsigned char *dst,
420 const unsigned char *src,
421 size_t len,
422 size_t c1, size_t c2 )
423{
424 /* mask = c1 == c2 ? 0xff : 0x00 */
425 const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 );
426 const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal );
427
428 /* dst[i] = c1 == c2 ? src[i] : dst[i] */
429 for( size_t i = 0; i < len; i++ )
430 dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask );
431}
gabor-mezei-arm0f7b9e42021-09-27 13:57:45 +0200432
433/*
434 * Constant-flow memcpy from variable position in buffer.
435 * - functionally equivalent to memcpy(dst, src + offset_secret, len)
436 * - but with execution flow independent from the value of offset_secret.
437 */
438void mbedtls_cf_memcpy_offset(
439 unsigned char *dst,
440 const unsigned char *src_base,
441 size_t offset_secret,
442 size_t offset_min, size_t offset_max,
443 size_t len )
444{
445 size_t offset;
446
447 for( offset = offset_min; offset <= offset_max; offset++ )
448 {
449 mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len,
450 offset, offset_secret );
451 }
452}
gabor-mezei-armcb4317b2021-09-27 14:28:31 +0200453
454#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
455
456/*
457 * Compute HMAC of variable-length data with constant flow.
458 *
459 * Only works with MD-5, SHA-1, SHA-256 and SHA-384.
460 * (Otherwise, computation of block_size needs to be adapted.)
461 */
462int mbedtls_cf_hmac(
463 mbedtls_md_context_t *ctx,
464 const unsigned char *add_data, size_t add_data_len,
465 const unsigned char *data, size_t data_len_secret,
466 size_t min_data_len, size_t max_data_len,
467 unsigned char *output )
468{
469 /*
470 * This function breaks the HMAC abstraction and uses the md_clone()
471 * extension to the MD API in order to get constant-flow behaviour.
472 *
473 * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
474 * concatenation, and okey/ikey are the XOR of the key with some fixed bit
475 * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
476 *
477 * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
478 * minlen, then cloning the context, and for each byte up to maxlen
479 * finishing up the hash computation, keeping only the correct result.
480 *
481 * Then we only need to compute HASH(okey + inner_hash) and we're done.
482 */
483 const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info );
484 /* TLS 1.0-1.2 only support SHA-384, SHA-256, SHA-1, MD-5,
485 * all of which have the same block size except SHA-384. */
486 const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
487 const unsigned char * const ikey = ctx->hmac_ctx;
488 const unsigned char * const okey = ikey + block_size;
489 const size_t hash_size = mbedtls_md_get_size( ctx->md_info );
490
491 unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
492 mbedtls_md_context_t aux;
493 size_t offset;
494 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
495
496 mbedtls_md_init( &aux );
497
498#define MD_CHK( func_call ) \
499 do { \
500 ret = (func_call); \
501 if( ret != 0 ) \
502 goto cleanup; \
503 } while( 0 )
504
505 MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
506
507 /* After hmac_start() of hmac_reset(), ikey has already been hashed,
508 * so we can start directly with the message */
509 MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) );
510 MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) );
511
512 /* For each possible length, compute the hash up to that point */
513 for( offset = min_data_len; offset <= max_data_len; offset++ )
514 {
515 MD_CHK( mbedtls_md_clone( &aux, ctx ) );
516 MD_CHK( mbedtls_md_finish( &aux, aux_out ) );
517 /* Keep only the correct inner_hash in the output buffer */
518 mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size,
519 offset, data_len_secret );
520
521 if( offset < max_data_len )
522 MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) );
523 }
524
525 /* The context needs to finish() before it starts() again */
526 MD_CHK( mbedtls_md_finish( ctx, aux_out ) );
527
528 /* Now compute HASH(okey + inner_hash) */
529 MD_CHK( mbedtls_md_starts( ctx ) );
530 MD_CHK( mbedtls_md_update( ctx, okey, block_size ) );
531 MD_CHK( mbedtls_md_update( ctx, output, hash_size ) );
532 MD_CHK( mbedtls_md_finish( ctx, output ) );
533
534 /* Done, get ready for next time */
535 MD_CHK( mbedtls_md_hmac_reset( ctx ) );
536
537#undef MD_CHK
538
539cleanup:
540 mbedtls_md_free( &aux );
541 return( ret );
542}
543
544#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
gabor-mezei-armb8caeee2021-09-27 15:33:35 +0200545
546#if defined(MBEDTLS_BIGNUM_C)
547
548#define MPI_VALIDATE_RET( cond ) \
549 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA )
550
551/*
552 * Conditionally assign X = Y, without leaking information
553 * about whether the assignment was made or not.
554 * (Leaking information about the respective sizes of X and Y is ok however.)
555 */
556int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
557{
558 int ret = 0;
559 size_t i;
560 mbedtls_mpi_uint limb_mask;
561 MPI_VALIDATE_RET( X != NULL );
562 MPI_VALIDATE_RET( Y != NULL );
563
564 /* MSVC has a warning about unary minus on unsigned integer types,
565 * but this is well-defined and precisely what we want to do here. */
566#if defined(_MSC_VER)
567#pragma warning( push )
568#pragma warning( disable : 4146 )
569#endif
570
571 /* make sure assign is 0 or 1 in a time-constant manner */
572 assign = (assign | (unsigned char)-assign) >> (sizeof( assign ) * 8 - 1);
573 /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
574 limb_mask = -assign;
575
576#if defined(_MSC_VER)
577#pragma warning( pop )
578#endif
579
580 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
581
582 X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign );
583
584 mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign );
585
586 for( i = Y->n; i < X->n; i++ )
587 X->p[i] &= ~limb_mask;
588
589cleanup:
590 return( ret );
591}
592
gabor-mezei-arm58fc8a62021-09-27 15:37:50 +0200593/*
594 * Conditionally swap X and Y, without leaking information
595 * about whether the swap was made or not.
596 * Here it is not ok to simply swap the pointers, which whould lead to
597 * different memory access patterns when X and Y are used afterwards.
598 */
599int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
600{
601 int ret, s;
602 size_t i;
603 mbedtls_mpi_uint limb_mask;
604 mbedtls_mpi_uint tmp;
605 MPI_VALIDATE_RET( X != NULL );
606 MPI_VALIDATE_RET( Y != NULL );
607
608 if( X == Y )
609 return( 0 );
610
611 /* MSVC has a warning about unary minus on unsigned integer types,
612 * but this is well-defined and precisely what we want to do here. */
613#if defined(_MSC_VER)
614#pragma warning( push )
615#pragma warning( disable : 4146 )
616#endif
617
618 /* make sure swap is 0 or 1 in a time-constant manner */
619 swap = (swap | (unsigned char)-swap) >> (sizeof( swap ) * 8 - 1);
620 /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */
621 limb_mask = -swap;
622
623#if defined(_MSC_VER)
624#pragma warning( pop )
625#endif
626
627 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
628 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
629
630 s = X->s;
631 X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap );
632 Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap );
633
634
635 for( i = 0; i < X->n; i++ )
636 {
637 tmp = X->p[i];
638 X->p[i] = ( X->p[i] & ~limb_mask ) | ( Y->p[i] & limb_mask );
639 Y->p[i] = ( Y->p[i] & ~limb_mask ) | ( tmp & limb_mask );
640 }
641
642cleanup:
643 return( ret );
644}
645
gabor-mezei-armb10301d2021-09-27 15:41:30 +0200646/*
647 * Compare signed values in constant time
648 */
649int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
650 unsigned *ret )
651{
652 size_t i;
653 /* The value of any of these variables is either 0 or 1 at all times. */
654 unsigned cond, done, X_is_negative, Y_is_negative;
655
656 MPI_VALIDATE_RET( X != NULL );
657 MPI_VALIDATE_RET( Y != NULL );
658 MPI_VALIDATE_RET( ret != NULL );
659
660 if( X->n != Y->n )
661 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
662
663 /*
664 * Set sign_N to 1 if N >= 0, 0 if N < 0.
665 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
666 */
667 X_is_negative = ( X->s & 2 ) >> 1;
668 Y_is_negative = ( Y->s & 2 ) >> 1;
669
670 /*
671 * If the signs are different, then the positive operand is the bigger.
672 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
673 * is false if X is positive (X_is_negative == 0).
674 */
675 cond = ( X_is_negative ^ Y_is_negative );
676 *ret = cond & X_is_negative;
677
678 /*
679 * This is a constant-time function. We might have the result, but we still
680 * need to go through the loop. Record if we have the result already.
681 */
682 done = cond;
683
684 for( i = X->n; i > 0; i-- )
685 {
686 /*
687 * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
688 * X and Y are negative.
689 *
690 * Again even if we can make a decision, we just mark the result and
691 * the fact that we are done and continue looping.
692 */
693 cond = mbedtls_cf_mpi_uint_lt( Y->p[i - 1], X->p[i - 1] );
694 *ret |= cond & ( 1 - done ) & X_is_negative;
695 done |= cond;
696
697 /*
698 * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
699 * X and Y are positive.
700 *
701 * Again even if we can make a decision, we just mark the result and
702 * the fact that we are done and continue looping.
703 */
704 cond = mbedtls_cf_mpi_uint_lt( X->p[i - 1], Y->p[i - 1] );
705 *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative );
706 done |= cond;
707 }
708
709 return( 0 );
710}
711
gabor-mezei-armb8caeee2021-09-27 15:33:35 +0200712#endif /* MBEDTLS_BIGNUM_C */