Skip to content

Commit 18b642b

Browse files
ekasperandi34
authored andcommitted
Constant-time utilities
Pull constant-time methods out to a separate header, add tests. Reviewed-by: Bodo Moeller <bodo@openssl.org> (cherry picked from commit 5a3d21c0585064292bde5cd34089e120487ab687) Bug: 28550804 Change-Id: I73567e98e148740a92751c6f6ab59268129a5cab
1 parent 86fbed9 commit 18b642b

File tree

3 files changed

+384
-45
lines changed

3 files changed

+384
-45
lines changed

crypto/constant_time_locl.h

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/* crypto/constant_time_locl.h */
2+
/*
3+
* Utilities for constant-time cryptography.
4+
*
5+
* Author: Emilia Kasper (emilia@openssl.org)
6+
* Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
7+
* (Google).
8+
* ====================================================================
9+
* Copyright (c) 2014 The OpenSSL Project. All rights reserved.
10+
*
11+
* Redistribution and use in source and binary forms, with or without
12+
* modification, are permitted provided that the following conditions
13+
* are met:
14+
* 1. Redistributions of source code must retain the copyright
15+
* notice, this list of conditions and the following disclaimer.
16+
* 2. Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
* 3. All advertising materials mentioning features or use of this software
20+
* must display the following acknowledgement:
21+
* "This product includes cryptographic software written by
22+
* Eric Young (eay@cryptsoft.com)"
23+
* The word 'cryptographic' can be left out if the rouines from the library
24+
* being used are not cryptographic related :-).
25+
* 4. If you include any Windows specific code (or a derivative thereof) from
26+
* the apps directory (application code) you must include an acknowledgement:
27+
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
28+
*
29+
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
30+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39+
* SUCH DAMAGE.
40+
*
41+
* The licence and distribution terms for any publically available version or
42+
* derivative of this code cannot be changed. i.e. this code cannot simply be
43+
* copied and put under another distribution licence
44+
* [including the GNU Public Licence.]
45+
*/
46+
47+
#ifndef HEADER_CONSTANT_TIME_LOCL_H
48+
#define HEADER_CONSTANT_TIME_LOCL_H
49+
50+
#include "e_os.h" /* For 'inline' */
51+
52+
#ifdef __cplusplus
53+
extern "C" {
54+
#endif
55+
56+
/*
57+
* The following methods return a bitmask of all ones (0xff...f) for true
58+
* and 0 for false. This is useful for choosing a value based on the result
59+
* of a conditional in constant time. For example,
60+
*
61+
* if (a < b) {
62+
* c = a;
63+
* } else {
64+
* c = b;
65+
* }
66+
*
67+
* can be written as
68+
*
69+
* unsigned int lt = constant_time_lt(a, b);
70+
* c = a & lt | b & ~lt;
71+
*/
72+
73+
/*
74+
* Returns the given value with the MSB copied to all the other
75+
* bits. Uses the fact that arithmetic shift shifts-in the sign bit.
76+
* However, this is not ensured by the C standard so you may need to
77+
* replace this with something else on odd CPUs.
78+
*/
79+
static inline unsigned int constant_time_msb(unsigned int a);
80+
81+
/*
82+
* Returns 0xff..f if a < b and 0 otherwise.
83+
*/
84+
inline unsigned int constant_time_lt(unsigned int a, unsigned int b);
85+
/* Convenience method for getting an 8-bit mask. */
86+
inline unsigned char constant_time_lt_8(unsigned int a, unsigned int b);
87+
88+
/*
89+
* Returns 0xff..f if a >= b and 0 otherwise.
90+
*/
91+
inline unsigned int constant_time_ge(unsigned int a, unsigned int b);
92+
/* Convenience method for getting an 8-bit mask. */
93+
inline unsigned char constant_time_ge_8(unsigned int a, unsigned int b);
94+
95+
/*
96+
* Returns 0xff..f if a == 0 and 0 otherwise.
97+
*/
98+
inline unsigned int constant_time_is_zero(unsigned int a);
99+
/* Convenience method for getting an 8-bit mask. */
100+
inline unsigned char constant_time_is_zero_8(unsigned int a);
101+
102+
103+
/*
104+
* Returns 0xff..f if a == b and 0 otherwise.
105+
*/
106+
inline unsigned int constant_time_eq(unsigned int a, unsigned int b);
107+
/* Convenience method for getting an 8-bit mask. */
108+
inline unsigned char constant_time_eq_8(unsigned int a, unsigned int b);
109+
110+
static inline unsigned int constant_time_msb(unsigned int a)
111+
{
112+
return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1));
113+
}
114+
115+
inline unsigned int constant_time_lt(unsigned int a, unsigned int b)
116+
{
117+
unsigned int lt;
118+
/* Case 1: msb(a) == msb(b). a < b iff the MSB of a - b is set.*/
119+
lt = ~(a ^ b) & (a - b);
120+
/* Case 2: msb(a) != msb(b). a < b iff the MSB of b is set. */
121+
lt |= ~a & b;
122+
return constant_time_msb(lt);
123+
}
124+
125+
inline unsigned char constant_time_lt_8(unsigned int a, unsigned int b)
126+
{
127+
return (unsigned char)(constant_time_lt(a, b));
128+
}
129+
130+
inline unsigned int constant_time_ge(unsigned int a, unsigned int b)
131+
{
132+
unsigned int ge;
133+
/* Case 1: msb(a) == msb(b). a >= b iff the MSB of a - b is not set.*/
134+
ge = ~((a ^ b) | (a - b));
135+
/* Case 2: msb(a) != msb(b). a >= b iff the MSB of a is set. */
136+
ge |= a & ~b;
137+
return constant_time_msb(ge);
138+
}
139+
140+
inline unsigned char constant_time_ge_8(unsigned int a, unsigned int b)
141+
{
142+
return (unsigned char)(constant_time_ge(a, b));
143+
}
144+
145+
inline unsigned int constant_time_is_zero(unsigned int a)
146+
{
147+
return constant_time_msb(~a & (a - 1));
148+
}
149+
150+
inline unsigned char constant_time_is_zero_8(unsigned int a)
151+
{
152+
return (unsigned char)(constant_time_is_zero(a));
153+
}
154+
155+
inline unsigned int constant_time_eq(unsigned int a, unsigned int b)
156+
{
157+
return constant_time_is_zero(a ^ b);
158+
}
159+
160+
inline unsigned char constant_time_eq_8(unsigned int a, unsigned int b)
161+
{
162+
return (unsigned char)(constant_time_eq(a, b));
163+
}
164+
165+
#ifdef __cplusplus
166+
}
167+
#endif
168+
169+
#endif /* HEADER_CONSTANT_TIME_LOCL_H */

crypto/constant_time_test.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/* crypto/constant_time_test.c */
2+
/*
3+
* Utilities for constant-time cryptography.
4+
*
5+
* Author: Emilia Kasper (emilia@openssl.org)
6+
* Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
7+
* (Google).
8+
* ====================================================================
9+
* Copyright (c) 2014 The OpenSSL Project. All rights reserved.
10+
*
11+
* Redistribution and use in source and binary forms, with or without
12+
* modification, are permitted provided that the following conditions
13+
* are met:
14+
* 1. Redistributions of source code must retain the copyright
15+
* notice, this list of conditions and the following disclaimer.
16+
* 2. Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
* 3. All advertising materials mentioning features or use of this software
20+
* must display the following acknowledgement:
21+
* "This product includes cryptographic software written by
22+
* Eric Young (eay@cryptsoft.com)"
23+
* The word 'cryptographic' can be left out if the rouines from the library
24+
* being used are not cryptographic related :-).
25+
* 4. If you include any Windows specific code (or a derivative thereof) from
26+
* the apps directory (application code) you must include an acknowledgement:
27+
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
28+
*
29+
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
30+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39+
* SUCH DAMAGE.
40+
*
41+
* The licence and distribution terms for any publically available version or
42+
* derivative of this code cannot be changed. i.e. this code cannot simply be
43+
* copied and put under another distribution licence
44+
* [including the GNU Public Licence.]
45+
*/
46+
47+
#include "../crypto/constant_time_locl.h"
48+
49+
#include <limits.h>
50+
#include <stdio.h>
51+
#include <stdlib.h>
52+
53+
static const unsigned int CONSTTIME_TRUE = ~0;
54+
static const unsigned int CONSTTIME_FALSE = 0;
55+
static const unsigned char CONSTTIME_TRUE_8 = ~0;
56+
static const unsigned char CONSTTIME_FALSE_8 = 0;
57+
58+
static int test_binary_op(unsigned int (*op)(unsigned int a, unsigned int b),
59+
const char* op_name, unsigned int a, unsigned int b, int is_true)
60+
{
61+
unsigned c = op(a, b);
62+
if (is_true && c != CONSTTIME_TRUE)
63+
{
64+
fprintf(stderr, "Test failed for %s(%du, %du): expected %du "
65+
"(TRUE), got %du\n", op_name, a, b, CONSTTIME_TRUE, c);
66+
return 1;
67+
}
68+
else if (!is_true && c != CONSTTIME_FALSE)
69+
{
70+
fprintf(stderr, "Test failed for %s(%du, %du): expected %du "
71+
"(FALSE), got %du\n", op_name, a, b, CONSTTIME_FALSE,
72+
c);
73+
return 1;
74+
}
75+
return 0;
76+
}
77+
78+
static int test_binary_op_8(unsigned char (*op)(unsigned int a, unsigned int b),
79+
const char* op_name, unsigned int a, unsigned int b, int is_true)
80+
{
81+
unsigned char c = op(a, b);
82+
if (is_true && c != CONSTTIME_TRUE_8)
83+
{
84+
fprintf(stderr, "Test failed for %s(%du, %du): expected %u "
85+
"(TRUE), got %u\n", op_name, a, b, CONSTTIME_TRUE_8, c);
86+
return 1;
87+
}
88+
else if (!is_true && c != CONSTTIME_FALSE_8)
89+
{
90+
fprintf(stderr, "Test failed for %s(%du, %du): expected %u "
91+
"(FALSE), got %u\n", op_name, a, b, CONSTTIME_FALSE_8,
92+
c);
93+
return 1;
94+
}
95+
return 0;
96+
}
97+
98+
static int test_is_zero(unsigned int a)
99+
{
100+
unsigned int c = constant_time_is_zero(a);
101+
if (a == 0 && c != CONSTTIME_TRUE)
102+
{
103+
fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
104+
"expected %du (TRUE), got %du\n", a, CONSTTIME_TRUE, c);
105+
return 1;
106+
}
107+
else if (a != 0 && c != CONSTTIME_FALSE)
108+
{
109+
fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
110+
"expected %du (FALSE), got %du\n", a, CONSTTIME_FALSE,
111+
c);
112+
return 1;
113+
}
114+
return 0;
115+
}
116+
117+
static int test_is_zero_8(unsigned int a)
118+
{
119+
unsigned char c = constant_time_is_zero_8(a);
120+
if (a == 0 && c != CONSTTIME_TRUE_8)
121+
{
122+
fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
123+
"expected %u (TRUE), got %u\n", a, CONSTTIME_TRUE_8, c);
124+
return 1;
125+
}
126+
else if (a != 0 && c != CONSTTIME_FALSE)
127+
{
128+
fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
129+
"expected %u (FALSE), got %u\n", a, CONSTTIME_FALSE_8,
130+
c);
131+
return 1;
132+
}
133+
return 0;
134+
}
135+
136+
static unsigned int test_values[] = {0, 1, 1024, 12345, 32000, UINT_MAX/2-1,
137+
UINT_MAX/2, UINT_MAX/2+1, UINT_MAX-1,
138+
UINT_MAX};
139+
140+
int main(int argc, char *argv[])
141+
{
142+
unsigned int a, b, i, j;
143+
int num_failed = 0, num_all = 0;
144+
fprintf(stdout, "Testing constant time operations...\n");
145+
146+
for (i = 0; i < sizeof(test_values)/sizeof(int); ++i)
147+
{
148+
a = test_values[i];
149+
num_failed += test_is_zero(a);
150+
num_failed += test_is_zero_8(a);
151+
num_failed += test_binary_op(&constant_time_lt,
152+
"constant_time_lt", a, a, 0);
153+
num_failed += test_binary_op_8(&constant_time_lt_8,
154+
"constant_time_lt_8", a, a, 0);
155+
num_failed += test_binary_op(&constant_time_ge,
156+
"constant_time_ge", a, a, 1);
157+
num_failed += test_binary_op_8(&constant_time_ge_8,
158+
"constant_time_ge_8", a, a, 1);
159+
num_failed += test_binary_op(&constant_time_eq,
160+
"constant_time_eq", a, a, 1);
161+
num_failed += test_binary_op_8(&constant_time_eq_8,
162+
"constant_time_eq_8", a, a, 1);
163+
num_all += 8;
164+
for (j = i + 1; j < sizeof(test_values)/sizeof(int); ++j)
165+
{
166+
b = test_values[j];
167+
num_failed += test_binary_op(&constant_time_lt,
168+
"constant_time_lt", a, b, a < b);
169+
num_failed += test_binary_op_8(&constant_time_lt_8,
170+
"constant_time_lt_8", a, b, a < b);
171+
num_failed += test_binary_op(&constant_time_lt,
172+
"constant_time_lt_8", b, a, b < a);
173+
num_failed += test_binary_op_8(&constant_time_lt_8,
174+
"constant_time_lt_8", b, a, b < a);
175+
num_failed += test_binary_op(&constant_time_ge,
176+
"constant_time_ge", a, b, a >= b);
177+
num_failed += test_binary_op_8(&constant_time_ge_8,
178+
"constant_time_ge_8", a, b, a >= b);
179+
num_failed += test_binary_op(&constant_time_ge,
180+
"constant_time_ge", b, a, b >= a);
181+
num_failed += test_binary_op_8(&constant_time_ge_8,
182+
"constant_time_ge_8", b, a, b >= a);
183+
num_failed += test_binary_op(&constant_time_eq,
184+
"constant_time_eq", a, b, a == b);
185+
num_failed += test_binary_op_8(&constant_time_eq_8,
186+
"constant_time_eq_8", a, b, a == b);
187+
num_failed += test_binary_op(&constant_time_eq,
188+
"constant_time_eq", b, a, b == a);
189+
num_failed += test_binary_op_8(&constant_time_eq_8,
190+
"constant_time_eq_8", b, a, b == a);
191+
num_all += 12;
192+
}
193+
}
194+
195+
if (!num_failed)
196+
{
197+
fprintf(stdout, "ok (ran %d tests)\n", num_all);
198+
return EXIT_SUCCESS;
199+
}
200+
else
201+
{
202+
fprintf(stdout, "%d of %d tests failed!\n", num_failed, num_all);
203+
return EXIT_FAILURE;
204+
}
205+
}

0 commit comments

Comments
 (0)