1 /*
2 * Utilities for constant-time cryptography.
3 *
4 * Author: Emilia Kasper (emilia@openssl.org)
5 * Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
6 * (Google).
7 * ====================================================================
8 * Copyright (c) 2014 The OpenSSL Project. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * "This product includes cryptographic software written by
21 * Eric Young (eay@cryptsoft.com)"
22 * The word 'cryptographic' can be left out if the rouines from the library
23 * being used are not cryptographic related :-).
24 * 4. If you include any Windows specific code (or a derivative thereof) from
25 * the apps directory (application code) you must include an acknowledgement:
26 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
27 *
28 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * The licence and distribution terms for any publically available version or
41 * derivative of this code cannot be changed. i.e. this code cannot simply be
42 * copied and put under another distribution licence
43 * [including the GNU Public Licence.]
44 */
45
46 #include "internal.h"
47
48 #include <limits.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51
52
53 static const unsigned int CONSTTIME_TRUE = (unsigned)(~0);
54 static const unsigned int CONSTTIME_FALSE = 0;
55 static const uint8_t CONSTTIME_TRUE_8 = 0xff;
56 static const uint8_t CONSTTIME_FALSE_8 = 0;
57
test_binary_op(unsigned int (* op)(unsigned int a,unsigned int b),const char * op_name,unsigned int a,unsigned int b,int is_true)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,
60 int is_true) {
61 unsigned c = op(a, b);
62 if (is_true && c != CONSTTIME_TRUE) {
63 fprintf(stderr,
64 "Test failed for %s(%du, %du): expected %du (TRUE), got %du\n",
65 op_name, a, b, CONSTTIME_TRUE, c);
66 return 1;
67 } else if (!is_true && c != CONSTTIME_FALSE) {
68 fprintf(stderr,
69 "Test failed for %s(%du, %du): expected %du (FALSE), got %du\n",
70 op_name, a, b, CONSTTIME_FALSE, c);
71 return 1;
72 }
73 return 0;
74 }
75
test_binary_op_8(uint8_t (* op)(unsigned int a,unsigned int b),const char * op_name,unsigned int a,unsigned int b,int is_true)76 static int test_binary_op_8(uint8_t (*op)(unsigned int a, unsigned int b),
77 const char* op_name, unsigned int a, unsigned int b,
78 int is_true) {
79 uint8_t c = op(a, b);
80 if (is_true && c != CONSTTIME_TRUE_8) {
81 fprintf(stderr,
82 "Test failed for %s(%du, %du): expected %u (TRUE), got %u\n",
83 op_name, a, b, CONSTTIME_TRUE_8, c);
84 return 1;
85 } else if (!is_true && c != CONSTTIME_FALSE_8) {
86 fprintf(stderr,
87 "Test failed for %s(%du, %du): expected %u (FALSE), got %u\n",
88 op_name, a, b, CONSTTIME_FALSE_8, c);
89 return 1;
90 }
91 return 0;
92 }
93
test_is_zero(unsigned int a)94 static int test_is_zero(unsigned int a) {
95 unsigned int c = constant_time_is_zero(a);
96 if (a == 0 && c != CONSTTIME_TRUE) {
97 fprintf(stderr,
98 "Test failed for constant_time_is_zero(%du): expected %du (TRUE), "
99 "got %du\n",
100 a, CONSTTIME_TRUE, c);
101 return 1;
102 } else if (a != 0 && c != CONSTTIME_FALSE) {
103 fprintf(stderr,
104 "Test failed for constant_time_is_zero(%du): expected %du (FALSE), "
105 "got %du\n",
106 a, CONSTTIME_FALSE, c);
107 return 1;
108 }
109 return 0;
110 }
111
test_is_zero_8(unsigned int a)112 static int test_is_zero_8(unsigned int a) {
113 uint8_t c = constant_time_is_zero_8(a);
114 if (a == 0 && c != CONSTTIME_TRUE_8) {
115 fprintf(stderr,
116 "Test failed for constant_time_is_zero(%du): expected %u (TRUE), "
117 "got %u\n",
118 a, CONSTTIME_TRUE_8, c);
119 return 1;
120 } else if (a != 0 && c != CONSTTIME_FALSE) {
121 fprintf(stderr,
122 "Test failed for constant_time_is_zero(%du): expected %u (FALSE), "
123 "got %u\n",
124 a, CONSTTIME_FALSE_8, c);
125 return 1;
126 }
127 return 0;
128 }
129
test_select(unsigned int a,unsigned int b)130 static int test_select(unsigned int a, unsigned int b) {
131 unsigned int selected = constant_time_select(CONSTTIME_TRUE, a, b);
132 if (selected != a) {
133 fprintf(stderr,
134 "Test failed for constant_time_select(%du, %du,"
135 "%du): expected %du(first value), got %du\n",
136 CONSTTIME_TRUE, a, b, a, selected);
137 return 1;
138 }
139 selected = constant_time_select(CONSTTIME_FALSE, a, b);
140 if (selected != b) {
141 fprintf(stderr,
142 "Test failed for constant_time_select(%du, %du,"
143 "%du): expected %du(second value), got %du\n",
144 CONSTTIME_FALSE, a, b, b, selected);
145 return 1;
146 }
147 return 0;
148 }
149
test_select_8(uint8_t a,uint8_t b)150 static int test_select_8(uint8_t a, uint8_t b) {
151 uint8_t selected = constant_time_select_8(CONSTTIME_TRUE_8, a, b);
152 if (selected != a) {
153 fprintf(stderr,
154 "Test failed for constant_time_select(%u, %u,"
155 "%u): expected %u(first value), got %u\n",
156 CONSTTIME_TRUE, a, b, a, selected);
157 return 1;
158 }
159 selected = constant_time_select_8(CONSTTIME_FALSE_8, a, b);
160 if (selected != b) {
161 fprintf(stderr,
162 "Test failed for constant_time_select(%u, %u,"
163 "%u): expected %u(second value), got %u\n",
164 CONSTTIME_FALSE, a, b, b, selected);
165 return 1;
166 }
167 return 0;
168 }
169
test_select_int(int a,int b)170 static int test_select_int(int a, int b) {
171 int selected = constant_time_select_int(CONSTTIME_TRUE, a, b);
172 if (selected != a) {
173 fprintf(stderr,
174 "Test failed for constant_time_select(%du, %d,"
175 "%d): expected %d(first value), got %d\n",
176 CONSTTIME_TRUE, a, b, a, selected);
177 return 1;
178 }
179 selected = constant_time_select_int(CONSTTIME_FALSE, a, b);
180 if (selected != b) {
181 fprintf(stderr,
182 "Test failed for constant_time_select(%du, %d,"
183 "%d): expected %d(second value), got %d\n",
184 CONSTTIME_FALSE, a, b, b, selected);
185 return 1;
186 }
187 return 0;
188 }
189
test_eq_int(int a,int b)190 static int test_eq_int(int a, int b) {
191 unsigned int equal = constant_time_eq_int(a, b);
192 if (a == b && equal != CONSTTIME_TRUE) {
193 fprintf(stderr,
194 "Test failed for constant_time_eq_int(%d, %d): expected %du(TRUE), "
195 "got %du\n",
196 a, b, CONSTTIME_TRUE, equal);
197 return 1;
198 } else if (a != b && equal != CONSTTIME_FALSE) {
199 fprintf(stderr,
200 "Test failed for constant_time_eq_int(%d, %d): expected "
201 "%du(FALSE), got %du\n",
202 a, b, CONSTTIME_FALSE, equal);
203 return 1;
204 }
205 return 0;
206 }
207
test_eq_int_8(int a,int b)208 static int test_eq_int_8(int a, int b) {
209 uint8_t equal = constant_time_eq_int_8(a, b);
210 if (a == b && equal != CONSTTIME_TRUE_8) {
211 fprintf(stderr,
212 "Test failed for constant_time_eq_int_8(%d, %d): expected "
213 "%u(TRUE), got %u\n",
214 a, b, CONSTTIME_TRUE_8, equal);
215 return 1;
216 } else if (a != b && equal != CONSTTIME_FALSE_8) {
217 fprintf(stderr,
218 "Test failed for constant_time_eq_int_8(%d, %d): expected "
219 "%u(FALSE), got %u\n",
220 a, b, CONSTTIME_FALSE_8, equal);
221 return 1;
222 }
223 return 0;
224 }
225
226 static unsigned int test_values[] = {0, 1, 1024, 12345, 32000, UINT_MAX / 2 - 1,
227 UINT_MAX / 2, UINT_MAX / 2 + 1,
228 UINT_MAX - 1, UINT_MAX};
229
230 static uint8_t test_values_8[] = {0, 1, 2, 20, 32, 127, 128, 129, 255};
231
232 static int signed_test_values[] = {
233 0, 1, -1, 1024, -1024, 12345, -12345,
234 32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1, INT_MIN + 1};
235
main(int argc,char * argv[])236 int main(int argc, char* argv[]) {
237 unsigned int a, b, i, j;
238 int c, d;
239 uint8_t e, f;
240 int num_failed = 0, num_all = 0;
241 fprintf(stdout, "Testing constant time operations...\n");
242
243 for (i = 0; i < sizeof(test_values) / sizeof(int); ++i) {
244 a = test_values[i];
245 num_failed += test_is_zero(a);
246 num_failed += test_is_zero_8(a);
247 num_all += 2;
248 for (j = 0; j < sizeof(test_values) / sizeof(int); ++j) {
249 b = test_values[j];
250 num_failed +=
251 test_binary_op(&constant_time_lt, "constant_time_lt", a, b, a < b);
252 num_failed += test_binary_op_8(&constant_time_lt_8, "constant_time_lt_8",
253 a, b, a < b);
254 num_failed +=
255 test_binary_op(&constant_time_lt, "constant_time_lt_8", b, a, b < a);
256 num_failed += test_binary_op_8(&constant_time_lt_8, "constant_time_lt_8",
257 b, a, b < a);
258 num_failed +=
259 test_binary_op(&constant_time_ge, "constant_time_ge", a, b, a >= b);
260 num_failed += test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8",
261 a, b, a >= b);
262 num_failed +=
263 test_binary_op(&constant_time_ge, "constant_time_ge", b, a, b >= a);
264 num_failed += test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8",
265 b, a, b >= a);
266 num_failed +=
267 test_binary_op(&constant_time_eq, "constant_time_eq", a, b, a == b);
268 num_failed += test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8",
269 a, b, a == b);
270 num_failed +=
271 test_binary_op(&constant_time_eq, "constant_time_eq", b, a, b == a);
272 num_failed += test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8",
273 b, a, b == a);
274 num_failed += test_select(a, b);
275 num_all += 13;
276 }
277 }
278
279 for (i = 0; i < sizeof(signed_test_values) / sizeof(int); ++i) {
280 c = signed_test_values[i];
281 for (j = 0; j < sizeof(signed_test_values) / sizeof(int); ++j) {
282 d = signed_test_values[j];
283 num_failed += test_select_int(c, d);
284 num_failed += test_eq_int(c, d);
285 num_failed += test_eq_int_8(c, d);
286 num_all += 3;
287 }
288 }
289
290 for (i = 0; i < sizeof(test_values_8); ++i) {
291 e = test_values_8[i];
292 for (j = 0; j < sizeof(test_values_8); ++j) {
293 f = test_values_8[j];
294 num_failed += test_select_8(e, f);
295 num_all += 1;
296 }
297 }
298
299 if (!num_failed) {
300 fprintf(stdout, "ok (ran %d tests)\n", num_all);
301 fprintf(stdout, "PASS\n");
302 return EXIT_SUCCESS;
303 } else {
304 fprintf(stdout, "%d of %d tests failed!\n", num_failed, num_all);
305 return EXIT_FAILURE;
306 }
307 }
308