VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTDigest.cpp@ 72140

Last change on this file since 72140 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: tstRTDigest.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTSha*, RTMd5, RTCrc*.
4 */
5
6/*
7 * Copyright (C) 2009-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/sha.h>
32#include <iprt/md2.h>
33#include <iprt/md5.h>
34#include <iprt/crc.h>
35
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/getopt.h>
40#include <iprt/initterm.h>
41#include <iprt/param.h>
42#include <iprt/path.h>
43#include <iprt/process.h>
44#include <iprt/string.h>
45#include <iprt/stream.h>
46#include <iprt/crypto/digest.h>
47
48
49static int Error(const char *pszFormat, ...)
50{
51 char szName[RTPATH_MAX];
52 if (!RTProcGetExecutablePath(szName, sizeof(szName)))
53 strcpy(szName, "tstRTDigest");
54
55 RTStrmPrintf(g_pStdErr, "%s: error: ", RTPathFilename(szName));
56 va_list va;
57 va_start(va, pszFormat);
58 RTStrmPrintfV(g_pStdErr, pszFormat, va);
59 va_end(va);
60
61 return 1;
62}
63
64
65static int MyReadFile(RTFILE hFile, void *pvBuf, size_t cbToRead, size_t *pcbRead, uint64_t *pcbMaxLeft)
66{
67 int rc = VINF_SUCCESS;
68 if (*pcbMaxLeft > 0)
69 {
70 if (cbToRead > *pcbMaxLeft)
71 cbToRead = (size_t)*pcbMaxLeft;
72 rc = RTFileRead(hFile, pvBuf, cbToRead, pcbRead);
73 if (RT_SUCCESS(rc))
74 *pcbMaxLeft -= *pcbRead;
75 }
76 else
77 *pcbRead = 0;
78 return rc;
79}
80
81
82static char *MyGetNextSignificantLine(PRTSTREAM pFile, char *pszBuf, size_t cbBuf, uint32_t *piLine, int *prc)
83{
84 for (;;)
85 {
86 *pszBuf = '\0';
87 int rc = RTStrmGetLine(pFile, pszBuf, cbBuf);
88 if (RT_FAILURE(rc))
89 {
90 if (rc != VERR_EOF)
91 {
92 Error("Read error: %Rrc", rc);
93 *prc = rc;
94 return NULL;
95 }
96 if (!*pszBuf)
97 return NULL;
98 }
99 *piLine += 1;
100
101 /* Significant? */
102 char *pszStart = RTStrStrip(pszBuf);
103 if (*pszStart && *pszStart != '#')
104 return pszStart;
105 }
106}
107
108
109int main(int argc, char **argv)
110{
111 RTR3InitExe(argc, &argv, 0);
112
113 RTDIGESTTYPE enmDigestType = RTDIGESTTYPE_INVALID;
114 const char *pszDigestType = "NotSpecified";
115
116 enum
117 {
118 kMethod_Full,
119 kMethod_Block,
120 kMethod_File,
121 kMethod_CVAS
122 } enmMethod = kMethod_Block;
123
124 uint64_t offStart = 0;
125 uint64_t cbMax = UINT64_MAX;
126 bool fTestcase = false;
127
128 static const RTGETOPTDEF s_aOptions[] =
129 {
130 { "--type", 't', RTGETOPT_REQ_STRING },
131 { "--method", 'm', RTGETOPT_REQ_STRING },
132 { "--help", 'h', RTGETOPT_REQ_NOTHING },
133 { "--length", 'l', RTGETOPT_REQ_UINT64 },
134 { "--offset", 'o', RTGETOPT_REQ_UINT64 },
135 { "--testcase", 'x', RTGETOPT_REQ_NOTHING },
136 };
137
138 int ch;
139 RTGETOPTUNION ValueUnion;
140 RTGETOPTSTATE GetState;
141 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
142 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
143 {
144 switch (ch)
145 {
146 case 't':
147 if (!RTStrICmp(ValueUnion.psz, "crc32"))
148 {
149 pszDigestType = "CRC32";
150 enmDigestType = RTDIGESTTYPE_CRC32;
151 }
152 else if (!RTStrICmp(ValueUnion.psz, "crc64"))
153 {
154 pszDigestType = "CRC64";
155 enmDigestType = RTDIGESTTYPE_CRC64;
156 }
157 else if (!RTStrICmp(ValueUnion.psz, "md2"))
158 {
159 pszDigestType = "MD2";
160 enmDigestType = RTDIGESTTYPE_MD2;
161 }
162 else if (!RTStrICmp(ValueUnion.psz, "md5"))
163 {
164 pszDigestType = "MD5";
165 enmDigestType = RTDIGESTTYPE_MD5;
166 }
167 else if (!RTStrICmp(ValueUnion.psz, "sha1"))
168 {
169 pszDigestType = "SHA-1";
170 enmDigestType = RTDIGESTTYPE_SHA1;
171 }
172 else if (!RTStrICmp(ValueUnion.psz, "sha224"))
173 {
174 pszDigestType = "SHA-224";
175 enmDigestType = RTDIGESTTYPE_SHA224;
176 }
177 else if (!RTStrICmp(ValueUnion.psz, "sha256"))
178 {
179 pszDigestType = "SHA-256";
180 enmDigestType = RTDIGESTTYPE_SHA256;
181 }
182 else if (!RTStrICmp(ValueUnion.psz, "sha384"))
183 {
184 pszDigestType = "SHA-384";
185 enmDigestType = RTDIGESTTYPE_SHA384;
186 }
187 else if (!RTStrICmp(ValueUnion.psz, "sha512"))
188 {
189 pszDigestType = "SHA-512";
190 enmDigestType = RTDIGESTTYPE_SHA512;
191 }
192 else if (!RTStrICmp(ValueUnion.psz, "sha512/224"))
193 {
194 pszDigestType = "SHA-512/224";
195 enmDigestType = RTDIGESTTYPE_SHA512T224;
196 }
197 else if (!RTStrICmp(ValueUnion.psz, "sha512/256"))
198 {
199 pszDigestType = "SHA-512/256";
200 enmDigestType = RTDIGESTTYPE_SHA512T256;
201 }
202 else
203 {
204 Error("Invalid digest type: %s\n", ValueUnion.psz);
205 return 1;
206 }
207 break;
208
209 case 'm':
210 if (!RTStrICmp(ValueUnion.psz, "full"))
211 enmMethod = kMethod_Full;
212 else if (!RTStrICmp(ValueUnion.psz, "block"))
213 enmMethod = kMethod_Block;
214 else if (!RTStrICmp(ValueUnion.psz, "file"))
215 enmMethod = kMethod_File;
216 else if (!RTStrICmp(ValueUnion.psz, "cvas"))
217 enmMethod = kMethod_CVAS;
218 else
219 {
220 Error("Invalid digest method: %s\n", ValueUnion.psz);
221 return 1;
222 }
223 break;
224
225 case 'l':
226 cbMax = ValueUnion.u64;
227 break;
228
229 case 'o':
230 offStart = ValueUnion.u64;
231 break;
232
233 case 'x':
234 fTestcase = true;
235 break;
236
237 case 'h':
238 RTPrintf("usage: tstRTDigest -t <digest-type> [-o <offset>] [-l <length>] [-x] file [file2 [..]]\n");
239 return 1;
240
241 case VINF_GETOPT_NOT_OPTION:
242 {
243 if (enmDigestType == RTDIGESTTYPE_INVALID)
244 return Error("No digest type was specified\n");
245
246 switch (enmMethod)
247 {
248 case kMethod_Full:
249 return Error("Full file method is not implemented\n");
250
251 case kMethod_File:
252 if (offStart != 0 || cbMax != UINT64_MAX)
253 return Error("The -l and -o options do not work with the 'file' method.");
254 switch (enmDigestType)
255 {
256 case RTDIGESTTYPE_SHA1:
257 {
258 char *pszDigest;
259 int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
260 if (RT_FAILURE(rc))
261 return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
262 RTPrintf("%s %s\n", pszDigest, ValueUnion.psz);
263 RTStrFree(pszDigest);
264 break;
265 }
266
267 case RTDIGESTTYPE_SHA256:
268 {
269 char *pszDigest;
270 int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
271 if (RT_FAILURE(rc))
272 return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
273 RTPrintf("%s %s\n", pszDigest, ValueUnion.psz);
274 RTStrFree(pszDigest);
275 break;
276 }
277 default:
278 return Error("The file method isn't implemented for this digest\n");
279 }
280 break;
281
282 case kMethod_Block:
283 {
284 RTFILE hFile;
285 int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
286 if (RT_FAILURE(rc))
287 return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc);
288 if (offStart != 0)
289 {
290 rc = RTFileSeek(hFile, offStart, RTFILE_SEEK_BEGIN, NULL);
291 if (RT_FAILURE(rc))
292 return Error("RTFileSeek(%s,%ull) -> %Rrc\n", ValueUnion.psz, offStart, rc);
293 }
294
295 uint64_t cbMaxLeft = cbMax;
296 size_t cbRead;
297 uint8_t abBuf[_64K];
298 char *pszDigest = (char *)&abBuf[0];
299 switch (enmDigestType)
300 {
301 case RTDIGESTTYPE_CRC32:
302 {
303 uint32_t uCRC32 = RTCrc32Start();
304 for (;;)
305 {
306 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
307 if (RT_FAILURE(rc) || !cbRead)
308 break;
309 uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead);
310 }
311 uCRC32 = RTCrc32Finish(uCRC32);
312 RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32);
313 break;
314 }
315
316 case RTDIGESTTYPE_CRC64:
317 {
318 uint64_t uCRC64 = RTCrc64Start();
319 for (;;)
320 {
321 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
322 if (RT_FAILURE(rc) || !cbRead)
323 break;
324 uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead);
325 }
326 uCRC64 = RTCrc64Finish(uCRC64);
327 RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64);
328 break;
329 }
330
331 case RTDIGESTTYPE_MD2:
332 {
333 RTMD2CONTEXT Ctx;
334 RTMd2Init(&Ctx);
335 for (;;)
336 {
337 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
338 if (RT_FAILURE(rc) || !cbRead)
339 break;
340 RTMd2Update(&Ctx, abBuf, cbRead);
341 }
342 uint8_t abDigest[RTMD2_HASH_SIZE];
343 RTMd2Final(&Ctx, abDigest);
344 RTMd2ToString(abDigest, pszDigest, sizeof(abBuf));
345 break;
346 }
347
348 case RTDIGESTTYPE_MD5:
349 {
350 RTMD5CONTEXT Ctx;
351 RTMd5Init(&Ctx);
352 for (;;)
353 {
354 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
355 if (RT_FAILURE(rc) || !cbRead)
356 break;
357 RTMd5Update(&Ctx, abBuf, cbRead);
358 }
359 uint8_t abDigest[RTMD5HASHSIZE];
360 RTMd5Final(abDigest, &Ctx);
361 RTMd5ToString(abDigest, pszDigest, sizeof(abBuf));
362 break;
363 }
364
365 case RTDIGESTTYPE_SHA1:
366 {
367 RTSHA1CONTEXT Ctx;
368 RTSha1Init(&Ctx);
369 for (;;)
370 {
371 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
372 if (RT_FAILURE(rc) || !cbRead)
373 break;
374 RTSha1Update(&Ctx, abBuf, cbRead);
375 }
376 uint8_t abDigest[RTSHA1_HASH_SIZE];
377 RTSha1Final(&Ctx, abDigest);
378 RTSha1ToString(abDigest, pszDigest, sizeof(abBuf));
379 break;
380 }
381
382 case RTDIGESTTYPE_SHA256:
383 {
384 RTSHA256CONTEXT Ctx;
385 RTSha256Init(&Ctx);
386 for (;;)
387 {
388 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
389 if (RT_FAILURE(rc) || !cbRead)
390 break;
391 RTSha256Update(&Ctx, abBuf, cbRead);
392 }
393 uint8_t abDigest[RTSHA256_HASH_SIZE];
394 RTSha256Final(&Ctx, abDigest);
395 RTSha256ToString(abDigest, pszDigest, sizeof(abBuf));
396 break;
397 }
398
399 case RTDIGESTTYPE_SHA512:
400 {
401 RTSHA512CONTEXT Ctx;
402 RTSha512Init(&Ctx);
403 for (;;)
404 {
405 rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
406 if (RT_FAILURE(rc) || !cbRead)
407 break;
408 RTSha512Update(&Ctx, abBuf, cbRead);
409 }
410 uint8_t abDigest[RTSHA512_HASH_SIZE];
411 RTSha512Final(&Ctx, abDigest);
412 RTSha512ToString(abDigest, pszDigest, sizeof(abBuf));
413 break;
414 }
415
416 default:
417 return Error("Internal error #1\n");
418 }
419 RTFileClose(hFile);
420 if (RT_FAILURE(rc) && rc != VERR_EOF)
421 {
422 RTPrintf("Partial: %s %s\n", pszDigest, ValueUnion.psz);
423 return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc);
424 }
425
426 if (!fTestcase)
427 RTPrintf("%s %s\n", pszDigest, ValueUnion.psz);
428 else if (offStart)
429 RTPrintf(" { &g_abRandom72KB[%#4llx], %5llu, \"%s\", \"%s %llu bytes @%llu\" },\n",
430 offStart, cbMax - cbMaxLeft, pszDigest, pszDigestType, offStart, cbMax - cbMaxLeft);
431 else
432 RTPrintf(" { &g_abRandom72KB[0], %5llu, \"%s\", \"%s %llu bytes\" },\n",
433 cbMax - cbMaxLeft, pszDigest, pszDigestType, cbMax - cbMaxLeft);
434 break;
435 }
436
437
438 /*
439 * Process a SHS response file:
440 * http://csrc.nist.gov/groups/STM/cavp/index.html#03
441 */
442 case kMethod_CVAS:
443 {
444 RTCRDIGEST hDigest;
445 int rc = RTCrDigestCreateByType(&hDigest, enmDigestType);
446 if (RT_FAILURE(rc))
447 return Error("Failed to create digest calculator for %s: %Rrc", pszDigestType, rc);
448
449 uint32_t const cbDigest = RTCrDigestGetHashSize(hDigest);
450 if (!cbDigest || cbDigest >= _1K)
451 return Error("Unexpected hash size: %#x\n", cbDigest);
452
453 PRTSTREAM pFile;
454 rc = RTStrmOpen(ValueUnion.psz, "r", &pFile);
455 if (RT_FAILURE(rc))
456 return Error("Failed to open CVAS file '%s': %Rrc", ValueUnion.psz, rc);
457
458 /*
459 * Parse the input file.
460 * ASSUME order: Len, Msg, MD.
461 */
462 static char s_szLine[_256K];
463 char *psz;
464 uint32_t cPassed = 0;
465 uint32_t cErrors = 0;
466 uint32_t iLine = 1;
467 for (;;)
468 {
469 psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
470 if (!psz)
471 break;
472
473 /* Skip [L = 20] stuff. */
474 if (*psz == '[')
475 continue;
476
477 /* Message length. */
478 uint64_t cMessageBits;
479 if (RTStrNICmp(psz, RT_STR_TUPLE("Len =")))
480 return Error("%s(%d): Expected 'Len =' found '%.10s...'", ValueUnion.psz, iLine, psz);
481 psz = RTStrStripL(psz + 5);
482 rc = RTStrToUInt64Full(psz, 0, &cMessageBits);
483 if (rc != VINF_SUCCESS)
484 return Error("%s(%d): Error parsing length '%s': %Rrc\n", ValueUnion.psz, iLine, psz, rc);
485
486 /* The message text. */
487 psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
488 if (!psz)
489 return Error("%s(%d): Expected message text not EOF.", ValueUnion.psz, iLine);
490 if (RTStrNICmp(psz, RT_STR_TUPLE("Msg =")))
491 return Error("%s(%d): Expected 'Msg =' found '%.10s...'", ValueUnion.psz, iLine, psz);
492 psz = RTStrStripL(psz + 5);
493
494 size_t const cbMessage = (cMessageBits + 7) / 8;
495 static uint8_t s_abMessage[sizeof(s_szLine) / 2];
496 if (cbMessage > 0)
497 {
498 rc = RTStrConvertHexBytes(psz, s_abMessage, cbMessage, 0 /*fFlags*/);
499 if (rc != VINF_SUCCESS)
500 return Error("%s(%d): Error parsing message '%.10s...': %Rrc\n",
501 ValueUnion.psz, iLine, psz, rc);
502 }
503
504 /* The message digest. */
505 psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
506 if (!psz)
507 return Error("%s(%d): Expected message digest not EOF.", ValueUnion.psz, iLine);
508 if (RTStrNICmp(psz, RT_STR_TUPLE("MD =")))
509 return Error("%s(%d): Expected 'MD =' found '%.10s...'", ValueUnion.psz, iLine, psz);
510 psz = RTStrStripL(psz + 4);
511
512 static uint8_t s_abExpectedDigest[_1K];
513 rc = RTStrConvertHexBytes(psz, s_abExpectedDigest, cbDigest, 0 /*fFlags*/);
514 if (rc != VINF_SUCCESS)
515 return Error("%s(%d): Error parsing message digest '%.10s...': %Rrc\n",
516 ValueUnion.psz, iLine, psz, rc);
517
518 /*
519 * Do the testing.
520 */
521 rc = RTCrDigestReset(hDigest);
522 if (rc != VINF_SUCCESS)
523 return Error("RTCrDigestReset failed: %Rrc", rc);
524
525 rc = RTCrDigestUpdate(hDigest, s_abMessage, cbMessage);
526 if (rc != VINF_SUCCESS)
527 return Error("RTCrDigestUpdate failed: %Rrc", rc);
528
529 static uint8_t s_abActualDigest[_1K];
530 rc = RTCrDigestFinal(hDigest, s_abActualDigest, cbDigest);
531 if (rc != VINF_SUCCESS)
532 return Error("RTCrDigestFinal failed: %Rrc", rc);
533
534 if (memcmp(s_abActualDigest, s_abExpectedDigest, cbDigest) == 0)
535 cPassed++;
536 else
537 {
538 Error("%s(%d): Message digest mismatch. Expected %.*RThxs, got %.*RThxs.",
539 ValueUnion.psz, iLine, cbDigest, s_abExpectedDigest, cbDigest, s_abActualDigest);
540 cErrors++;
541 }
542 }
543
544 RTStrmClose(pFile);
545 if (cErrors > 0)
546 return Error("Failed: %u error%s (%u passed)", cErrors, cErrors == 1 ? "" : "s", cPassed);
547 RTPrintf("Passed %u test%s.\n", cPassed, cPassed == 1 ? "" : "s");
548 if (RT_FAILURE(rc))
549 return Error("Failed: %Rrc", rc);
550 break;
551 }
552
553 default:
554 return Error("Internal error #2\n");
555 }
556 break;
557 }
558
559 default:
560 return RTGetOptPrintError(ch, &ValueUnion);
561 }
562 }
563
564 return 0;
565}
566
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette