1279265Sdelphij/* crypto/constant_time_test.c */
2296465Sdelphij/*-
3279265Sdelphij * Utilities for constant-time cryptography.
4279265Sdelphij *
5279265Sdelphij * Author: Emilia Kasper (emilia@openssl.org)
6279265Sdelphij * Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
7279265Sdelphij * (Google).
8279265Sdelphij * ====================================================================
9279265Sdelphij * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
10279265Sdelphij *
11279265Sdelphij * Redistribution and use in source and binary forms, with or without
12279265Sdelphij * modification, are permitted provided that the following conditions
13279265Sdelphij * are met:
14279265Sdelphij * 1. Redistributions of source code must retain the copyright
15279265Sdelphij *    notice, this list of conditions and the following disclaimer.
16279265Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
17279265Sdelphij *    notice, this list of conditions and the following disclaimer in the
18279265Sdelphij *    documentation and/or other materials provided with the distribution.
19279265Sdelphij * 3. All advertising materials mentioning features or use of this software
20279265Sdelphij *    must display the following acknowledgement:
21279265Sdelphij *    "This product includes cryptographic software written by
22279265Sdelphij *     Eric Young (eay@cryptsoft.com)"
23279265Sdelphij *    The word 'cryptographic' can be left out if the rouines from the library
24279265Sdelphij *    being used are not cryptographic related :-).
25279265Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
26279265Sdelphij *    the apps directory (application code) you must include an acknowledgement:
27279265Sdelphij *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
28279265Sdelphij *
29279265Sdelphij * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
30279265Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31279265Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32279265Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33279265Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34279265Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35279265Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36279265Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37279265Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38279265Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39279265Sdelphij * SUCH DAMAGE.
40279265Sdelphij *
41279265Sdelphij * The licence and distribution terms for any publically available version or
42279265Sdelphij * derivative of this code cannot be changed.  i.e. this code cannot simply be
43279265Sdelphij * copied and put under another distribution licence
44279265Sdelphij * [including the GNU Public Licence.]
45279265Sdelphij */
46279265Sdelphij
47279265Sdelphij#include "../crypto/constant_time_locl.h"
48279265Sdelphij
49279265Sdelphij#include <limits.h>
50279265Sdelphij#include <stdio.h>
51279265Sdelphij#include <stdlib.h>
52279265Sdelphij
53279265Sdelphijstatic const unsigned int CONSTTIME_TRUE = (unsigned)(~0);
54279265Sdelphijstatic const unsigned int CONSTTIME_FALSE = 0;
55279265Sdelphijstatic const unsigned char CONSTTIME_TRUE_8 = 0xff;
56279265Sdelphijstatic const unsigned char CONSTTIME_FALSE_8 = 0;
57279265Sdelphij
58296465Sdelphijstatic int test_binary_op(unsigned int (*op) (unsigned int a, unsigned int b),
59296465Sdelphij                          const char *op_name, unsigned int a, unsigned int b,
60296465Sdelphij                          int is_true)
61296465Sdelphij{
62296465Sdelphij    unsigned c = op(a, b);
63296465Sdelphij    if (is_true && c != CONSTTIME_TRUE) {
64296465Sdelphij        fprintf(stderr, "Test failed for %s(%du, %du): expected %du "
65296465Sdelphij                "(TRUE), got %du\n", op_name, a, b, CONSTTIME_TRUE, c);
66296465Sdelphij        return 1;
67296465Sdelphij    } else if (!is_true && c != CONSTTIME_FALSE) {
68296465Sdelphij        fprintf(stderr, "Test failed for  %s(%du, %du): expected %du "
69296465Sdelphij                "(FALSE), got %du\n", op_name, a, b, CONSTTIME_FALSE, c);
70296465Sdelphij        return 1;
71296465Sdelphij    }
72296465Sdelphij    return 0;
73296465Sdelphij}
74279265Sdelphij
75296465Sdelphijstatic int test_binary_op_8(unsigned
76296465Sdelphij                            char (*op) (unsigned int a, unsigned int b),
77296465Sdelphij                            const char *op_name, unsigned int a,
78296465Sdelphij                            unsigned int b, int is_true)
79296465Sdelphij{
80296465Sdelphij    unsigned char c = op(a, b);
81296465Sdelphij    if (is_true && c != CONSTTIME_TRUE_8) {
82296465Sdelphij        fprintf(stderr, "Test failed for %s(%du, %du): expected %u "
83296465Sdelphij                "(TRUE), got %u\n", op_name, a, b, CONSTTIME_TRUE_8, c);
84296465Sdelphij        return 1;
85296465Sdelphij    } else if (!is_true && c != CONSTTIME_FALSE_8) {
86296465Sdelphij        fprintf(stderr, "Test failed for  %s(%du, %du): expected %u "
87296465Sdelphij                "(FALSE), got %u\n", op_name, a, b, CONSTTIME_FALSE_8, c);
88296465Sdelphij        return 1;
89296465Sdelphij    }
90296465Sdelphij    return 0;
91296465Sdelphij}
92279265Sdelphij
93279265Sdelphijstatic int test_is_zero(unsigned int a)
94296465Sdelphij{
95296465Sdelphij    unsigned int c = constant_time_is_zero(a);
96296465Sdelphij    if (a == 0 && c != CONSTTIME_TRUE) {
97296465Sdelphij        fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
98296465Sdelphij                "expected %du (TRUE), got %du\n", a, CONSTTIME_TRUE, c);
99296465Sdelphij        return 1;
100296465Sdelphij    } else if (a != 0 && c != CONSTTIME_FALSE) {
101296465Sdelphij        fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
102296465Sdelphij                "expected %du (FALSE), got %du\n", a, CONSTTIME_FALSE, c);
103296465Sdelphij        return 1;
104296465Sdelphij    }
105296465Sdelphij    return 0;
106296465Sdelphij}
107279265Sdelphij
108279265Sdelphijstatic int test_is_zero_8(unsigned int a)
109296465Sdelphij{
110296465Sdelphij    unsigned char c = constant_time_is_zero_8(a);
111296465Sdelphij    if (a == 0 && c != CONSTTIME_TRUE_8) {
112296465Sdelphij        fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
113296465Sdelphij                "expected %u (TRUE), got %u\n", a, CONSTTIME_TRUE_8, c);
114296465Sdelphij        return 1;
115296465Sdelphij    } else if (a != 0 && c != CONSTTIME_FALSE) {
116296465Sdelphij        fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
117296465Sdelphij                "expected %u (FALSE), got %u\n", a, CONSTTIME_FALSE_8, c);
118296465Sdelphij        return 1;
119296465Sdelphij    }
120296465Sdelphij    return 0;
121296465Sdelphij}
122279265Sdelphij
123279265Sdelphijstatic int test_select(unsigned int a, unsigned int b)
124296465Sdelphij{
125296465Sdelphij    unsigned int selected = constant_time_select(CONSTTIME_TRUE, a, b);
126296465Sdelphij    if (selected != a) {
127296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%du, %du,"
128296465Sdelphij                "%du): expected %du(first value), got %du\n",
129296465Sdelphij                CONSTTIME_TRUE, a, b, a, selected);
130296465Sdelphij        return 1;
131296465Sdelphij    }
132296465Sdelphij    selected = constant_time_select(CONSTTIME_FALSE, a, b);
133296465Sdelphij    if (selected != b) {
134296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%du, %du,"
135296465Sdelphij                "%du): expected %du(second value), got %du\n",
136296465Sdelphij                CONSTTIME_FALSE, a, b, b, selected);
137296465Sdelphij        return 1;
138296465Sdelphij    }
139296465Sdelphij    return 0;
140296465Sdelphij}
141279265Sdelphij
142279265Sdelphijstatic int test_select_8(unsigned char a, unsigned char b)
143296465Sdelphij{
144296465Sdelphij    unsigned char selected = constant_time_select_8(CONSTTIME_TRUE_8, a, b);
145296465Sdelphij    if (selected != a) {
146296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%u, %u,"
147296465Sdelphij                "%u): expected %u(first value), got %u\n",
148296465Sdelphij                CONSTTIME_TRUE, a, b, a, selected);
149296465Sdelphij        return 1;
150296465Sdelphij    }
151296465Sdelphij    selected = constant_time_select_8(CONSTTIME_FALSE_8, a, b);
152296465Sdelphij    if (selected != b) {
153296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%u, %u,"
154296465Sdelphij                "%u): expected %u(second value), got %u\n",
155296465Sdelphij                CONSTTIME_FALSE, a, b, b, selected);
156296465Sdelphij        return 1;
157296465Sdelphij    }
158296465Sdelphij    return 0;
159296465Sdelphij}
160279265Sdelphij
161279265Sdelphijstatic int test_select_int(int a, int b)
162296465Sdelphij{
163296465Sdelphij    int selected = constant_time_select_int(CONSTTIME_TRUE, a, b);
164296465Sdelphij    if (selected != a) {
165296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%du, %d,"
166296465Sdelphij                "%d): expected %d(first value), got %d\n",
167296465Sdelphij                CONSTTIME_TRUE, a, b, a, selected);
168296465Sdelphij        return 1;
169296465Sdelphij    }
170296465Sdelphij    selected = constant_time_select_int(CONSTTIME_FALSE, a, b);
171296465Sdelphij    if (selected != b) {
172296465Sdelphij        fprintf(stderr, "Test failed for constant_time_select(%du, %d,"
173296465Sdelphij                "%d): expected %d(second value), got %d\n",
174296465Sdelphij                CONSTTIME_FALSE, a, b, b, selected);
175296465Sdelphij        return 1;
176296465Sdelphij    }
177296465Sdelphij    return 0;
178296465Sdelphij}
179279265Sdelphij
180279265Sdelphijstatic int test_eq_int(int a, int b)
181296465Sdelphij{
182296465Sdelphij    unsigned int equal = constant_time_eq_int(a, b);
183296465Sdelphij    if (a == b && equal != CONSTTIME_TRUE) {
184296465Sdelphij        fprintf(stderr, "Test failed for constant_time_eq_int(%d, %d): "
185296465Sdelphij                "expected %du(TRUE), got %du\n", a, b, CONSTTIME_TRUE, equal);
186296465Sdelphij        return 1;
187296465Sdelphij    } else if (a != b && equal != CONSTTIME_FALSE) {
188296465Sdelphij        fprintf(stderr, "Test failed for constant_time_eq_int(%d, %d): "
189296465Sdelphij                "expected %du(FALSE), got %du\n",
190296465Sdelphij                a, b, CONSTTIME_FALSE, equal);
191296465Sdelphij        return 1;
192296465Sdelphij    }
193296465Sdelphij    return 0;
194296465Sdelphij}
195279265Sdelphij
196279265Sdelphijstatic int test_eq_int_8(int a, int b)
197296465Sdelphij{
198296465Sdelphij    unsigned char equal = constant_time_eq_int_8(a, b);
199296465Sdelphij    if (a == b && equal != CONSTTIME_TRUE_8) {
200296465Sdelphij        fprintf(stderr, "Test failed for constant_time_eq_int_8(%d, %d): "
201296465Sdelphij                "expected %u(TRUE), got %u\n", a, b, CONSTTIME_TRUE_8, equal);
202296465Sdelphij        return 1;
203296465Sdelphij    } else if (a != b && equal != CONSTTIME_FALSE_8) {
204296465Sdelphij        fprintf(stderr, "Test failed for constant_time_eq_int_8(%d, %d): "
205296465Sdelphij                "expected %u(FALSE), got %u\n",
206296465Sdelphij                a, b, CONSTTIME_FALSE_8, equal);
207296465Sdelphij        return 1;
208296465Sdelphij    }
209296465Sdelphij    return 0;
210296465Sdelphij}
211279265Sdelphij
212296465Sdelphijstatic unsigned int test_values[] =
213296465Sdelphij    { 0, 1, 1024, 12345, 32000, UINT_MAX / 2 - 1,
214296465Sdelphij    UINT_MAX / 2, UINT_MAX / 2 + 1, UINT_MAX - 1,
215296465Sdelphij    UINT_MAX
216296465Sdelphij};
217279265Sdelphij
218296465Sdelphijstatic unsigned char test_values_8[] =
219296465Sdelphij    { 0, 1, 2, 20, 32, 127, 128, 129, 255 };
220279265Sdelphij
221296465Sdelphijstatic int signed_test_values[] = { 0, 1, -1, 1024, -1024, 12345, -12345,
222296465Sdelphij    32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1,
223296465Sdelphij    INT_MIN + 1
224296465Sdelphij};
225279265Sdelphij
226279265Sdelphijint main(int argc, char *argv[])
227296465Sdelphij{
228296465Sdelphij    unsigned int a, b, i, j;
229296465Sdelphij    int c, d;
230296465Sdelphij    unsigned char e, f;
231296465Sdelphij    int num_failed = 0, num_all = 0;
232296465Sdelphij    fprintf(stdout, "Testing constant time operations...\n");
233279265Sdelphij
234296465Sdelphij    for (i = 0; i < sizeof(test_values) / sizeof(int); ++i) {
235296465Sdelphij        a = test_values[i];
236296465Sdelphij        num_failed += test_is_zero(a);
237296465Sdelphij        num_failed += test_is_zero_8(a);
238296465Sdelphij        num_all += 2;
239296465Sdelphij        for (j = 0; j < sizeof(test_values) / sizeof(int); ++j) {
240296465Sdelphij            b = test_values[j];
241296465Sdelphij            num_failed += test_binary_op(&constant_time_lt,
242296465Sdelphij                                         "constant_time_lt", a, b, a < b);
243296465Sdelphij            num_failed += test_binary_op_8(&constant_time_lt_8,
244296465Sdelphij                                           "constant_time_lt_8", a, b, a < b);
245296465Sdelphij            num_failed += test_binary_op(&constant_time_lt,
246296465Sdelphij                                         "constant_time_lt_8", b, a, b < a);
247296465Sdelphij            num_failed += test_binary_op_8(&constant_time_lt_8,
248296465Sdelphij                                           "constant_time_lt_8", b, a, b < a);
249296465Sdelphij            num_failed += test_binary_op(&constant_time_ge,
250296465Sdelphij                                         "constant_time_ge", a, b, a >= b);
251296465Sdelphij            num_failed += test_binary_op_8(&constant_time_ge_8,
252296465Sdelphij                                           "constant_time_ge_8", a, b,
253296465Sdelphij                                           a >= b);
254296465Sdelphij            num_failed +=
255296465Sdelphij                test_binary_op(&constant_time_ge, "constant_time_ge", b, a,
256296465Sdelphij                               b >= a);
257296465Sdelphij            num_failed +=
258296465Sdelphij                test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8", b,
259296465Sdelphij                                 a, b >= a);
260296465Sdelphij            num_failed +=
261296465Sdelphij                test_binary_op(&constant_time_eq, "constant_time_eq", a, b,
262296465Sdelphij                               a == b);
263296465Sdelphij            num_failed +=
264296465Sdelphij                test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8", a,
265296465Sdelphij                                 b, a == b);
266296465Sdelphij            num_failed +=
267296465Sdelphij                test_binary_op(&constant_time_eq, "constant_time_eq", b, a,
268296465Sdelphij                               b == a);
269296465Sdelphij            num_failed +=
270296465Sdelphij                test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8", b,
271296465Sdelphij                                 a, b == a);
272296465Sdelphij            num_failed += test_select(a, b);
273296465Sdelphij            num_all += 13;
274296465Sdelphij        }
275296465Sdelphij    }
276279265Sdelphij
277296465Sdelphij    for (i = 0; i < sizeof(signed_test_values) / sizeof(int); ++i) {
278296465Sdelphij        c = signed_test_values[i];
279296465Sdelphij        for (j = 0; j < sizeof(signed_test_values) / sizeof(int); ++j) {
280296465Sdelphij            d = signed_test_values[j];
281296465Sdelphij            num_failed += test_select_int(c, d);
282296465Sdelphij            num_failed += test_eq_int(c, d);
283296465Sdelphij            num_failed += test_eq_int_8(c, d);
284296465Sdelphij            num_all += 3;
285296465Sdelphij        }
286296465Sdelphij    }
287279265Sdelphij
288296465Sdelphij    for (i = 0; i < sizeof(test_values_8); ++i) {
289296465Sdelphij        e = test_values_8[i];
290296465Sdelphij        for (j = 0; j < sizeof(test_values_8); ++j) {
291296465Sdelphij            f = test_values_8[j];
292296465Sdelphij            num_failed += test_select_8(e, f);
293296465Sdelphij            num_all += 1;
294296465Sdelphij        }
295296465Sdelphij    }
296279265Sdelphij
297296465Sdelphij    if (!num_failed) {
298296465Sdelphij        fprintf(stdout, "ok (ran %d tests)\n", num_all);
299296465Sdelphij        return EXIT_SUCCESS;
300296465Sdelphij    } else {
301296465Sdelphij        fprintf(stdout, "%d of %d tests failed!\n", num_failed, num_all);
302296465Sdelphij        return EXIT_FAILURE;
303296465Sdelphij    }
304296465Sdelphij}
305