1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "hwrng_unittest"
18
19 #include <math.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <lib/rng/trusty_rng.h>
26 #include <trusty_unittest.h>
27 #include <uapi/err.h>
28
29 static uint32_t _hist[256];
30 static uint8_t _rng_buf[1024];
31
hwrng_update_hist(uint8_t * data,unsigned int cnt)32 static void hwrng_update_hist(uint8_t* data, unsigned int cnt) {
33 for (unsigned int i = 0; i < cnt; i++) {
34 _hist[data[i]]++;
35 }
36 }
37
hwrng_show_data(const void * ptr,size_t len)38 static void hwrng_show_data(const void* ptr, size_t len) {
39 uintptr_t address = (uintptr_t)ptr;
40 size_t count;
41 size_t i;
42 fprintf(stderr, "Dumping first hwrng request:\n");
43 for (count = 0; count < len; count += 16) {
44 for (i = 0; i < MIN(len - count, 16); i++) {
45 fprintf(stderr, "0x%02hhx ", *(const uint8_t*)(address + i));
46 }
47 fprintf(stderr, "\n");
48 address += 16;
49 }
50 }
51
TEST(hwrng,show_data_test)52 TEST(hwrng, show_data_test) {
53 int rc;
54 rc = trusty_rng_hw_rand(_rng_buf, 32);
55 EXPECT_EQ(NO_ERROR, rc, "hwrng test");
56 if (rc == NO_ERROR) {
57 hwrng_show_data(_rng_buf, 32);
58 }
59 }
60
TEST(hwrng,var_rng_req_test)61 TEST(hwrng, var_rng_req_test) {
62 int rc;
63 unsigned int i;
64 size_t req_cnt;
65 /* Issue 100 hwrng requests of variable sizes */
66 for (i = 0; i < 100; i++) {
67 req_cnt = ((size_t)rand() % sizeof(_rng_buf)) + 1;
68 rc = trusty_rng_hw_rand(_rng_buf, req_cnt);
69 EXPECT_EQ(NO_ERROR, rc, "hwrng test");
70 if (rc != NO_ERROR) {
71 TLOGI("trusty_rng_hw_rand returned %d\n", rc);
72 continue;
73 }
74 }
75 }
76
77 /*
78 * This Test is NOT intended as a replacement for a proper NIST SP 800-22
79 * certification suites. It only attempts to detect detect gross misbehaviors of
80 * rng early on, at low computational costs while not being flaky. It is
81 * adapted from Section 2.13
82 */
83
84 #define NB_RNG_QUERIES 1000
85 #define LEN_BYTES_RNG_QUERIES 1024
86 #define CUM_SUM_ERR_MSG_SZ 256
87 /*
88 * Standard Normal Cumulative Probability Distribution Function as defined in
89 * Section 5.5.3
90 */
phi(double z)91 static double phi(double z) {
92 return 0.5 * (1.0 + erf(z / sqrt(2.0)));
93 }
94
95 /*
96 * This is the actual NIST Test as defined in NIST 800-22 Section 2.13. It
97 * will return NO_ERROR if and only if it succeeds, otherwise an error code.
98 */
cumulative_sums_forward_test_helper(void)99 static int cumulative_sums_forward_test_helper(void) {
100 /* n is as defined in NIST 800-22 Section 2.13.7 recommends >=100 */
101 const int64_t n = (NB_RNG_QUERIES * LEN_BYTES_RNG_QUERIES * 8);
102 _Static_assert(
103 n >= 100,
104 "n as defined in NIST 800-22 Section 2.13.7 recommends >=100");
105
106 int rc;
107 int S = 0;
108 size_t i, j, k;
109
110 /* largest absolute value of the partial sums */
111 int64_t z = 0;
112
113 for (i = 0; i < NB_RNG_QUERIES; i++) {
114 rc = trusty_rng_hw_rand(_rng_buf, LEN_BYTES_RNG_QUERIES);
115 if (rc != NO_ERROR) {
116 TLOGE("trusty_rng_hw_rand returned %d", rc);
117 return rc;
118 }
119 for (j = 0; j < LEN_BYTES_RNG_QUERIES; j++) {
120 for (k = 0; k < 8; k++) {
121 S += (_rng_buf[j] >> k) & 1 ? 1 : -1;
122 z = MAX(abs(S), z);
123 }
124 }
125 }
126
127 int64_t start = ((-(double)n / (double)z) + 1.0) / 4.0;
128 int64_t end = (((double)n / (double)z) + 1.0) / 4.0;
129 int64_t start2 = ((-(double)n / (double)z) - 3.0) / 4.0;
130 double p = 1.0;
131 for (int64_t k = start; k <= end; k++) {
132 p -= phi(((4.0 * k + 1.0) * z) / sqrt(n));
133 p += phi(((4.0 * k - 1.0) * z) / sqrt(n));
134 }
135 for (int64_t k = start2; k <= end; k++) {
136 p += phi(((4.0 * k + 3.0) * z) / sqrt(n));
137 p -= phi(((4.0 * k + 1.0) * z) / sqrt(n));
138 }
139
140 if (p <= 0.01) {
141 trusty_unittest_printf(
142 "[ WARN ] NIST 800-22 - Section 2.13.5 Decision Rule (at the 1 Percent Level)\n");
143 return ERR_GENERIC;
144 }
145
146 return NO_ERROR;
147 }
148
149 /*
150 * To avoid flakiness on real devices the actual NIST test is attempted 3 times.
151 * The helper which implements the Test as-is has ~1% failure rate.
152 */
TEST(hwrng,cumulative_sums_forward_test)153 TEST(hwrng, cumulative_sums_forward_test) {
154 int ret = NO_ERROR;
155 int counter = 3;
156 do {
157 ret = cumulative_sums_forward_test_helper();
158 } while (ret && counter--);
159
160 EXPECT_EQ(
161 ret, NO_ERROR,
162 "NIST 800-22 - Section 2.13.5 criteria not met after 3 attempts.");
163 }
164
TEST(hwrng,stats_test)165 TEST(hwrng, stats_test) {
166 int rc;
167 unsigned int i;
168 size_t req_cnt;
169 uint32_t exp_cnt;
170 uint32_t cnt = 0;
171 uint32_t ave = 0;
172 uint32_t dev = 0;
173 /* issue 100x256 bytes requests */
174 req_cnt = 256;
175 exp_cnt = 1000 * req_cnt;
176 memset(_hist, 0, sizeof(_hist));
177 for (i = 0; i < 1000; i++) {
178 rc = trusty_rng_hw_rand(_rng_buf, req_cnt);
179 EXPECT_EQ(NO_ERROR, rc, "hwrng test");
180 if (rc != NO_ERROR) {
181 TLOGI("trusty_rng_hw_rand returned %d\n", rc);
182 continue;
183 }
184 hwrng_update_hist(_rng_buf, req_cnt);
185 }
186
187 /* check hwrng stats */
188 for (i = 0; i < 256; i++)
189 cnt += _hist[i];
190 ave = cnt / 256;
191 EXPECT_EQ(exp_cnt, cnt, "hwrng ttl sample cnt");
192 EXPECT_EQ(1000, ave, "hwrng eve sample cnt");
193
194 /*
195 * Ideally data should be uniformly distributed
196 * Calculate average deviation from ideal model
197 */
198 for (i = 0; i < 256; i++) {
199 uint32_t val = (_hist[i] > ave) ? _hist[i] - ave : ave - _hist[i];
200 dev += val;
201 }
202 dev /= 256;
203 /*
204 * Check if average deviation is within 5% of ideal model
205 * which is fairly arbitrary requirement. It could be useful
206 * to alert is something terribly wrong with rng source.
207 */
208 EXPECT_GT(50, dev, "average dev");
209 }
210
211 PORT_TEST(hwrng, "com.android.trusty.hwrng.test")
212