1 /**********************************************************************
2 Copyright(c) 2011-2016 Intel Corporation All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in
11 the documentation and/or other materials provided with the
12 distribution.
13 * Neither the name of Intel Corporation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 **********************************************************************/
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include "md5_mb.h"
33
34 #ifndef FIPS_MODE
35 #define TEST_LEN (1024 * 1024)
36 #define TEST_BUFS 100
37 #ifndef RANDOMS
38 #define RANDOMS 10
39 #endif
40 #ifndef TEST_SEED
41 #define TEST_SEED 0x1234
42 #endif
43
44 #define UPDATE_SIZE 13 * ISAL_MD5_BLOCK_SIZE
45 #define MAX_RAND_UPDATE_BLOCKS (TEST_LEN / (16 * ISAL_MD5_BLOCK_SIZE))
46
47 #ifdef DEBUG
48 #define debug_char(x) putchar(x)
49 #else
50 #define debug_char(x) \
51 do { \
52 } while (0)
53 #endif
54
55 /* Reference digest global to reduce stack usage */
56 static uint32_t digest_ref[TEST_BUFS][ISAL_MD5_DIGEST_NWORDS];
57
58 extern void
59 md5_ref(uint8_t *input_data, uint32_t *digest, uint32_t len);
60
61 // Generates pseudo-random data
62
63 void
rand_buffer(unsigned char * buf,const long buffer_size)64 rand_buffer(unsigned char *buf, const long buffer_size)
65 {
66 long i;
67 for (i = 0; i < buffer_size; i++)
68 buf[i] = rand();
69 }
70 #endif
71
72 int
main(void)73 main(void)
74 {
75 #ifndef FIPS_MODE
76 ISAL_MD5_HASH_CTX_MGR *mgr = NULL;
77 ISAL_MD5_HASH_CTX ctxpool[TEST_BUFS], *ctx = NULL;
78 uint32_t i, j, fail = 0;
79 uint32_t len_done, len_rem, len_rand;
80 unsigned char *bufs[TEST_BUFS] = { 0 };
81 unsigned char *buf_ptr[TEST_BUFS];
82 uint32_t lens[TEST_BUFS];
83 unsigned int joblen, jobs, t;
84 int ret;
85
86 printf("multibinary_md5_update test, %d sets of %dx%d max: ", RANDOMS, TEST_BUFS, TEST_LEN);
87
88 srand(TEST_SEED);
89
90 ret = posix_memalign((void *) &mgr, 16, sizeof(ISAL_MD5_HASH_CTX_MGR));
91 if ((ret != 0) || (mgr == NULL)) {
92 printf("posix_memalign failed test aborted\n");
93 return 1;
94 }
95
96 ret = isal_md5_ctx_mgr_init(mgr);
97 if (ret)
98 return 1;
99
100 for (i = 0; i < TEST_BUFS; i++) {
101 // Allocate and fill buffer
102 bufs[i] = (unsigned char *) malloc(TEST_LEN);
103 buf_ptr[i] = bufs[i];
104 if (bufs[i] == NULL) {
105 printf("malloc failed test aborted\n");
106 fail++;
107 goto end;
108 }
109 rand_buffer(bufs[i], TEST_LEN);
110
111 // Init ctx contents
112 isal_hash_ctx_init(&ctxpool[i]);
113 ctxpool[i].user_data = (void *) ((uint64_t) i);
114
115 // Run reference test
116 md5_ref(bufs[i], digest_ref[i], TEST_LEN);
117 }
118
119 // Run sb_md5 tests
120 for (i = 0; i < TEST_BUFS;) {
121 len_done = (int) ((uintptr_t) buf_ptr[i] - (uintptr_t) bufs[i]);
122 len_rem = TEST_LEN - len_done;
123
124 if (len_done == 0)
125 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
126 UPDATE_SIZE, ISAL_HASH_FIRST);
127 else if (len_rem <= UPDATE_SIZE)
128 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i], len_rem,
129 ISAL_HASH_LAST);
130 else
131 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
132 UPDATE_SIZE, ISAL_HASH_UPDATE);
133 if (ret)
134 return 1;
135
136 // Add jobs while available or finished
137 if ((ctx == NULL) || isal_hash_ctx_complete(ctx)) {
138 i++;
139 continue;
140 }
141 // Resubmit unfinished job
142 i = (uint32_t) (uintptr_t) (ctx->user_data);
143 buf_ptr[i] += UPDATE_SIZE;
144 }
145
146 // Start flushing finished jobs, end on last flushed
147 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
148 if (ret)
149 return 1;
150 while (ctx) {
151 if (isal_hash_ctx_complete(ctx)) {
152 debug_char('-');
153 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
154 if (ret)
155 return 1;
156 continue;
157 }
158 // Resubmit unfinished job
159 i = (uint32_t) (uintptr_t) (ctx->user_data);
160 buf_ptr[i] += UPDATE_SIZE;
161
162 len_done = (uint32_t) ((uintptr_t) buf_ptr[i] - (uintptr_t) bufs[i]);
163 len_rem = TEST_LEN - len_done;
164
165 if (len_rem <= UPDATE_SIZE)
166 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i], len_rem,
167 ISAL_HASH_LAST);
168 else
169 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
170 UPDATE_SIZE, ISAL_HASH_UPDATE);
171 if (ret)
172 return 1;
173
174 if (ctx == NULL) {
175 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
176 if (ret)
177 return 1;
178 }
179 }
180
181 // Check digests
182 for (i = 0; i < TEST_BUFS; i++) {
183 for (j = 0; j < ISAL_MD5_DIGEST_NWORDS; j++) {
184 if (ctxpool[i].job.result_digest[j] != digest_ref[i][j]) {
185 fail++;
186 printf("Test%d fixed size, digest%d fail %8X <=> %8X", i, j,
187 ctxpool[i].job.result_digest[j], digest_ref[i][j]);
188 }
189 }
190 }
191 putchar('.');
192
193 // Run tests with random size and number of jobs
194 for (t = 0; t < RANDOMS; t++) {
195 jobs = rand() % (TEST_BUFS);
196
197 for (i = 0; i < jobs; i++) {
198 joblen = rand() % (TEST_LEN);
199 rand_buffer(bufs[i], joblen);
200 lens[i] = joblen;
201 buf_ptr[i] = bufs[i];
202 md5_ref(bufs[i], digest_ref[i], lens[i]);
203 }
204
205 ret = isal_md5_ctx_mgr_init(mgr);
206 if (ret)
207 return 1;
208
209 // Run md5_sb jobs
210 i = 0;
211 while (i < jobs) {
212 // Submit a new job
213 len_rand = ISAL_MD5_BLOCK_SIZE +
214 ISAL_MD5_BLOCK_SIZE * (rand() % MAX_RAND_UPDATE_BLOCKS);
215
216 if (lens[i] > len_rand)
217 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
218 len_rand, ISAL_HASH_FIRST);
219 else
220 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
221 lens[i], ISAL_HASH_ENTIRE);
222 if (ret)
223 return 1;
224
225 // Returned ctx could be:
226 // - null context (we are just getting started and lanes aren't full yet),
227 // or
228 // - finished already (an ENTIRE we submitted or a previous LAST is
229 // returned), or
230 // - an unfinished ctx, we will resubmit
231
232 if ((ctx == NULL) || isal_hash_ctx_complete(ctx)) {
233 i++;
234 continue;
235 } else {
236 // unfinished ctx returned, choose another random update length and
237 // submit either UPDATE or LAST depending on the amount of buffer
238 // remaining
239 while ((ctx != NULL) && !(isal_hash_ctx_complete(ctx))) {
240 j = (uint32_t) (uintptr_t) (ctx->user_data); // Get index of
241 // the returned
242 // ctx
243 buf_ptr[j] = bufs[j] + ctx->total_length;
244 len_rand = (rand() % ISAL_MD5_BLOCK_SIZE) *
245 (rand() % MAX_RAND_UPDATE_BLOCKS);
246 len_rem = lens[j] - (uint32_t) ctx->total_length;
247
248 if (len_rem <=
249 len_rand) // submit the rest of the job as LAST
250 ret = isal_md5_ctx_mgr_submit(
251 mgr, &ctxpool[j], &ctx, buf_ptr[j], len_rem,
252 ISAL_HASH_LAST);
253 else // submit the random update length as UPDATE
254 ret = isal_md5_ctx_mgr_submit(
255 mgr, &ctxpool[j], &ctx, buf_ptr[j],
256 len_rand, ISAL_HASH_UPDATE);
257 if (ret)
258 return 1;
259 } // Either continue submitting any contexts returned here as
260 // UPDATE/LAST, or
261 // go back to submitting new jobs using the index i.
262
263 i++;
264 }
265 }
266
267 // Start flushing finished jobs, end on last flushed
268 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
269 if (ret)
270 return 1;
271 while (ctx) {
272 if (isal_hash_ctx_complete(ctx)) {
273 debug_char('-');
274 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
275 if (ret)
276 return 1;
277 continue;
278 }
279 // Resubmit unfinished job
280 i = (uint32_t) (uintptr_t) (ctx->user_data);
281 buf_ptr[i] = bufs[i] + ctx->total_length; // update buffer pointer
282 len_rem = lens[i] - (uint32_t) ctx->total_length;
283 len_rand =
284 (rand() % ISAL_MD5_BLOCK_SIZE) * (rand() % MAX_RAND_UPDATE_BLOCKS);
285 debug_char('+');
286 if (len_rem <= len_rand)
287 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
288 len_rem, ISAL_HASH_LAST);
289 else
290 ret = isal_md5_ctx_mgr_submit(mgr, &ctxpool[i], &ctx, buf_ptr[i],
291 len_rand, ISAL_HASH_UPDATE);
292 if (ret)
293 return 1;
294
295 if (ctx == NULL) {
296 ret = isal_md5_ctx_mgr_flush(mgr, &ctx);
297 if (ret)
298 return 1;
299 }
300 }
301
302 // Check result digest
303 for (i = 0; i < jobs; i++) {
304 for (j = 0; j < ISAL_MD5_DIGEST_NWORDS; j++) {
305 if (ctxpool[i].job.result_digest[j] != digest_ref[i][j]) {
306 fail++;
307 printf("Test%d, digest%d fail %8X <=> %8X\n", i, j,
308 ctxpool[i].job.result_digest[j], digest_ref[i][j]);
309 }
310 }
311 }
312 if (fail) {
313 printf("Test failed function check %d\n", fail);
314 goto end;
315 }
316
317 putchar('.');
318 fflush(0);
319 } // random test t
320
321 end:
322 for (i = 0; i < TEST_BUFS; i++)
323 free(bufs[i]);
324 aligned_free(mgr);
325
326 if (fail) {
327 printf("Test failed function check %d\n", fail);
328 } else
329 printf(" multibinary_md5_update rand: Pass\n");
330
331 return fail;
332 #else
333 printf("Not Executed\n");
334
335 return 0;
336 #endif /* FIPS_MODE */
337 }
338