VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

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