VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/digest-core.cpp@ 73603

Last change on this file since 73603 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: digest-core.cpp 73097 2018-07-12 21:06:33Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Cryptographic Hash / Message Digest API
4 */
5
6/*
7 * Copyright (C) 2006-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 "internal/iprt.h"
32#include <iprt/crypto/digest.h>
33
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/crypto/x509.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Generic message digest instance.
46 */
47typedef struct RTCRDIGESTINT
48{
49 /** Magic value (RTCRDIGESTINT_MAGIC). */
50 uint32_t u32Magic;
51 /** Reference counter. */
52 uint32_t volatile cRefs;
53 /** Pointer to the message digest descriptor. */
54 PCRTCRDIGESTDESC pDesc;
55 /** The offset into abState of the storage space . At
56 * least RTCRDIGESTDESC::cbHash bytes is available at that location. */
57 uint32_t offHash;
58 /** State. */
59 uint32_t uState;
60 /** The number of bytes consumed. */
61 uint64_t cbConsumed;
62 /** Pointer to the data specific to the message digest algorithm. Points
63 * either to &abState[0] or to memory allocated with pDesc->pfnNew. */
64 void *pvState;
65 /** Opaque data specific to the message digest algorithm, size given by
66 * RTCRDIGESTDESC::cbState. This is followed by space for the final hash
67 * at offHash with size RTCRDIGESTDESC::cbHash. The data specific to the
68 * message digest algorithm can also be 0. In this case, pDesc->pfnNew()
69 * and pDesc->pfnFree() must not be NULL. */
70 uint8_t abState[1];
71} RTCRDIGESTINT;
72/** Pointer to a message digest instance. */
73typedef RTCRDIGESTINT *PRTCRDIGESTINT;
74
75/** Magic value for RTCRDIGESTINT::u32Magic (Ralph C. Merkle). */
76#define RTCRDIGESTINT_MAGIC UINT32_C(0x19520202)
77
78/** @name RTCRDIGESTINT::uState values.
79 * @{ */
80/** Ready for more data. */
81#define RTCRDIGEST_STATE_READY UINT32_C(1)
82/** The hash has been finalized and can be found at offHash. */
83#define RTCRDIGEST_STATE_FINAL UINT32_C(2)
84/** Busted state, can happen after re-init. */
85#define RTCRDIGEST_STATE_BUSTED UINT32_C(3)
86/** @} */
87
88
89
90RTDECL(int) RTCrDigestCreate(PRTCRDIGEST phDigest, PCRTCRDIGESTDESC pDesc, void *pvOpaque)
91{
92 AssertPtrReturn(phDigest, VERR_INVALID_POINTER);
93 AssertPtrReturn(pDesc, VERR_INVALID_POINTER);
94
95 int rc = VINF_SUCCESS;
96 uint32_t const offHash = RT_ALIGN_32(pDesc->cbState, 8);
97 AssertReturn(pDesc->pfnNew || offHash, VERR_INVALID_PARAMETER);
98 AssertReturn(!pDesc->pfnNew || (pDesc->pfnFree && pDesc->pfnInit && pDesc->pfnClone), VERR_INVALID_PARAMETER);
99 PRTCRDIGESTINT pThis = (PRTCRDIGESTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRDIGESTINT, abState[offHash + pDesc->cbHash]));
100 if (pThis)
101 {
102 if (pDesc->pfnNew)
103 pThis->pvState = pDesc->pfnNew();
104 else
105 pThis->pvState = &pThis->abState[0];
106 if (pThis->pvState)
107 {
108 pThis->u32Magic = RTCRDIGESTINT_MAGIC;
109 pThis->cRefs = 1;
110 pThis->offHash = offHash;
111 pThis->pDesc = pDesc;
112 pThis->uState = RTCRDIGEST_STATE_READY;
113 if (pDesc->pfnInit)
114 rc = pDesc->pfnInit(pThis->pvState, pvOpaque, false /*fReInit*/);
115 if (RT_SUCCESS(rc))
116 {
117 *phDigest = pThis;
118 return VINF_SUCCESS;
119 }
120 if (pDesc->pfnFree)
121 pDesc->pfnFree(pThis->pvState);
122 }
123 else
124 rc = VERR_NO_MEMORY;
125 pThis->u32Magic = 0;
126 RTMemFree(pThis);
127 }
128 else
129 rc = VERR_NO_MEMORY;
130 return rc;
131}
132
133
134RTDECL(int) RTCrDigestClone(PRTCRDIGEST phDigest, RTCRDIGEST hSrc)
135{
136 AssertPtrReturn(phDigest, VERR_INVALID_POINTER);
137 AssertPtrReturn(hSrc, VERR_INVALID_HANDLE);
138 AssertReturn(hSrc->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
139
140 int rc = VINF_SUCCESS;
141 uint32_t const offHash = hSrc->offHash;
142 PRTCRDIGESTINT pThis = (PRTCRDIGESTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRDIGESTINT, abState[offHash + hSrc->pDesc->cbHash]));
143 if (pThis)
144 {
145 if (hSrc->pDesc->pfnNew)
146 pThis->pvState = hSrc->pDesc->pfnNew();
147 else
148 pThis->pvState = &pThis->abState[0];
149 if (pThis->pvState)
150 {
151 pThis->u32Magic = RTCRDIGESTINT_MAGIC;
152 pThis->cRefs = 1;
153 pThis->offHash = offHash;
154 pThis->pDesc = hSrc->pDesc;
155 if (hSrc->pDesc->pfnClone)
156 rc = hSrc->pDesc->pfnClone(pThis->pvState, hSrc->pvState);
157 else
158 {
159 Assert(!hSrc->pDesc->pfnNew);
160 memcpy(pThis->pvState, hSrc->pvState, offHash);
161 }
162 memcpy(&pThis->abState[offHash], &hSrc->abState[offHash], hSrc->pDesc->cbHash);
163 pThis->uState = hSrc->uState;
164
165 if (RT_SUCCESS(rc))
166 {
167 *phDigest = pThis;
168 return VINF_SUCCESS;
169 }
170 if (hSrc->pDesc->pfnFree)
171 hSrc->pDesc->pfnFree(pThis->pvState);
172 }
173 else
174 rc = VERR_NO_MEMORY;
175 pThis->u32Magic = 0;
176 RTMemFree(pThis);
177 }
178 else
179 rc = VERR_NO_MEMORY;
180 return rc;
181}
182
183
184RTDECL(int) RTCrDigestReset(RTCRDIGEST hDigest)
185{
186 PRTCRDIGESTINT pThis = hDigest;
187 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
188 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
189
190 pThis->cbConsumed = 0;
191 pThis->uState = RTCRDIGEST_STATE_READY;
192
193 int rc = VINF_SUCCESS;
194 if (pThis->pDesc->pfnInit)
195 {
196 rc = pThis->pDesc->pfnInit(pThis->pvState, NULL, true /*fReInit*/);
197 if (RT_FAILURE(rc))
198 pThis->uState = RTCRDIGEST_STATE_BUSTED;
199 RT_BZERO(&pThis->abState[pThis->offHash], pThis->pDesc->cbHash);
200 }
201 else
202 {
203 Assert(!pThis->pDesc->pfnNew);
204 RT_BZERO(pThis->pvState, pThis->offHash + pThis->pDesc->cbHash);
205 }
206 return rc;
207}
208
209
210RTDECL(uint32_t) RTCrDigestRetain(RTCRDIGEST hDigest)
211{
212 PRTCRDIGESTINT pThis = hDigest;
213 AssertPtrReturn(pThis, UINT32_MAX);
214 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, UINT32_MAX);
215
216 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
217 Assert(cRefs < 64);
218 return cRefs;
219}
220
221
222RTDECL(uint32_t) RTCrDigestRelease(RTCRDIGEST hDigest)
223{
224 PRTCRDIGESTINT pThis = hDigest;
225 if (pThis == NIL_RTCRDIGEST)
226 return 0;
227 AssertPtrReturn(pThis, UINT32_MAX);
228 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, UINT32_MAX);
229
230 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
231 if (!cRefs)
232 {
233 pThis->u32Magic = ~RTCRDIGESTINT_MAGIC;
234 if (pThis->pDesc->pfnDelete)
235 pThis->pDesc->pfnDelete(pThis->pvState);
236 if (pThis->pDesc->pfnFree)
237 pThis->pDesc->pfnFree(pThis->pvState);
238 RTMemFree(pThis);
239 }
240 Assert(cRefs < 64);
241 return cRefs;
242}
243
244
245RTDECL(int) RTCrDigestUpdate(RTCRDIGEST hDigest, void const *pvData, size_t cbData)
246{
247 PRTCRDIGESTINT pThis = hDigest;
248 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
249 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
250 AssertReturn(pThis->uState == RTCRDIGEST_STATE_READY, VERR_INVALID_STATE);
251
252 pThis->pDesc->pfnUpdate(pThis->pvState, pvData, cbData);
253 pThis->cbConsumed += cbData;
254 return VINF_SUCCESS;
255}
256
257
258RTDECL(int) RTCrDigestFinal(RTCRDIGEST hDigest, void *pvHash, size_t cbHash)
259{
260 PRTCRDIGESTINT pThis = hDigest;
261 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
262 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
263 AssertReturn(pThis->uState == RTCRDIGEST_STATE_READY || pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE);
264 AssertPtrNullReturn(pvHash, VERR_INVALID_POINTER);
265
266 /*
267 * Make sure the hash calculation is final.
268 */
269 if (pThis->uState == RTCRDIGEST_STATE_READY)
270 {
271 pThis->pDesc->pfnFinal(pThis->pvState, &pThis->abState[pThis->offHash]);
272 pThis->uState = RTCRDIGEST_STATE_FINAL;
273 }
274 else
275 AssertReturn(pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE);
276
277 /*
278 * Copy out the hash if requested.
279 */
280 if (cbHash > 0)
281 {
282 uint32_t cbNeeded = pThis->pDesc->cbHash;
283 if (pThis->pDesc->pfnGetHashSize)
284 cbNeeded = pThis->pDesc->pfnGetHashSize(pThis->pvState);
285 Assert(cbNeeded > 0);
286
287 if (cbNeeded == cbHash)
288 memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded);
289 else if (cbNeeded > cbHash)
290 {
291 memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded);
292 memset((uint8_t *)pvHash + cbNeeded, 0, cbHash - cbNeeded);
293 return VINF_BUFFER_UNDERFLOW;
294 }
295 else
296 {
297 memcpy(pvHash, &pThis->abState[pThis->offHash], cbHash);
298 return VERR_BUFFER_OVERFLOW;
299 }
300 }
301
302 return VINF_SUCCESS;
303}
304
305
306RTDECL(bool) RTCrDigestMatch(RTCRDIGEST hDigest, void const *pvHash, size_t cbHash)
307{
308 PRTCRDIGESTINT pThis = hDigest;
309
310 int rc = RTCrDigestFinal(pThis, NULL, 0);
311 AssertRCReturn(rc, false);
312
313 AssertPtrReturn(pvHash, false);
314 return pThis->pDesc->cbHash == cbHash
315 && !memcmp(&pThis->abState[pThis->offHash], pvHash, cbHash);
316}
317
318
319RTDECL(uint8_t const *) RTCrDigestGetHash(RTCRDIGEST hDigest)
320{
321 PRTCRDIGESTINT pThis = hDigest;
322 AssertPtrReturn(pThis, NULL);
323 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, NULL);
324
325 int rc = RTCrDigestFinal(pThis, NULL, 0);
326 AssertRCReturn(rc, NULL);
327
328 return &pThis->abState[pThis->offHash];
329}
330
331
332RTDECL(uint32_t) RTCrDigestGetHashSize(RTCRDIGEST hDigest)
333{
334 PRTCRDIGESTINT pThis = hDigest;
335 AssertPtrReturn(pThis, 0);
336 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, 0);
337 if (pThis->pDesc->pfnGetHashSize)
338 {
339 uint32_t cbHash = pThis->pDesc->pfnGetHashSize(pThis->pvState);
340 Assert(cbHash <= pThis->pDesc->cbHash);
341 return cbHash;
342 }
343 return pThis->pDesc->cbHash;
344}
345
346
347RTDECL(uint64_t) RTCrDigestGetConsumedSize(RTCRDIGEST hDigest)
348{
349 PRTCRDIGESTINT pThis = hDigest;
350 AssertPtrReturn(pThis, 0);
351 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, 0);
352 return pThis->cbConsumed;
353}
354
355
356RTDECL(bool) RTCrDigestIsFinalized(RTCRDIGEST hDigest)
357{
358 PRTCRDIGESTINT pThis = hDigest;
359 AssertPtrReturn(pThis, false);
360 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, false);
361 return pThis->uState == RTCRDIGEST_STATE_FINAL;
362}
363
364
365RTDECL(RTDIGESTTYPE) RTCrDigestGetType(RTCRDIGEST hDigest)
366{
367 PRTCRDIGESTINT pThis = hDigest;
368 AssertPtrReturn(pThis, RTDIGESTTYPE_INVALID);
369 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, RTDIGESTTYPE_INVALID);
370
371 RTDIGESTTYPE enmType = pThis->pDesc->enmType;
372 if (pThis->pDesc->pfnGetDigestType)
373 enmType = pThis->pDesc->pfnGetDigestType(pThis->pvState);
374 return enmType;
375}
376
377
378RTDECL(const char *) RTCrDigestGetAlgorithmOid(RTCRDIGEST hDigest)
379{
380 return RTCrDigestTypeToAlgorithmOid(RTCrDigestGetType(hDigest));
381}
382
383
384RTDECL(const char *) RTCrDigestTypeToAlgorithmOid(RTDIGESTTYPE enmDigestType)
385{
386 switch (enmDigestType)
387 {
388 case RTDIGESTTYPE_MD2: return RTCRX509ALGORITHMIDENTIFIERID_MD2;
389 case RTDIGESTTYPE_MD4: return RTCRX509ALGORITHMIDENTIFIERID_MD4;
390 case RTDIGESTTYPE_MD5: return RTCRX509ALGORITHMIDENTIFIERID_MD5;
391 case RTDIGESTTYPE_SHA1: return RTCRX509ALGORITHMIDENTIFIERID_SHA1;
392 case RTDIGESTTYPE_SHA224: return RTCRX509ALGORITHMIDENTIFIERID_SHA224;
393 case RTDIGESTTYPE_SHA256: return RTCRX509ALGORITHMIDENTIFIERID_SHA256;
394 case RTDIGESTTYPE_SHA384: return RTCRX509ALGORITHMIDENTIFIERID_SHA384;
395 case RTDIGESTTYPE_SHA512: return RTCRX509ALGORITHMIDENTIFIERID_SHA512;
396 default: return NULL;
397 }
398}
399
400
401RTDECL(const char *) RTCrDigestTypeToName(RTDIGESTTYPE enmDigestType)
402{
403 switch (enmDigestType)
404 {
405 case RTDIGESTTYPE_CRC32: return "CRC32";
406 case RTDIGESTTYPE_CRC64: return "CRC64";
407 case RTDIGESTTYPE_MD2: return "MD2";
408 case RTDIGESTTYPE_MD4: return "MD4";
409 case RTDIGESTTYPE_MD5: return "MD5";
410 case RTDIGESTTYPE_SHA1: return "SHA-1";
411 case RTDIGESTTYPE_SHA224: return "SHA-224";
412 case RTDIGESTTYPE_SHA256: return "SHA-256";
413 case RTDIGESTTYPE_SHA384: return "SHA-384";
414 case RTDIGESTTYPE_SHA512: return "SHA-512";
415 case RTDIGESTTYPE_SHA512T224: return "SHA-512/224";
416 case RTDIGESTTYPE_SHA512T256: return "SHA-512/256";
417 default: return NULL;
418 }
419}
420
421
422RTDECL(uint32_t) RTCrDigestTypeToHashSize(RTDIGESTTYPE enmDigestType)
423{
424 switch (enmDigestType)
425 {
426 case RTDIGESTTYPE_CRC32: return 32 / 8;
427 case RTDIGESTTYPE_CRC64: return 64 / 8;
428 case RTDIGESTTYPE_MD2: return 128 / 8;
429 case RTDIGESTTYPE_MD4: return 128 / 8;
430 case RTDIGESTTYPE_MD5: return 128 / 8;
431 case RTDIGESTTYPE_SHA1: return 160 / 8;
432 case RTDIGESTTYPE_SHA224: return 224 / 8;
433 case RTDIGESTTYPE_SHA256: return 256 / 8;
434 case RTDIGESTTYPE_SHA384: return 384 / 8;
435 case RTDIGESTTYPE_SHA512: return 512 / 8;
436 case RTDIGESTTYPE_SHA512T224: return 224 / 8;
437 case RTDIGESTTYPE_SHA512T256: return 256 / 8;
438 default:
439 AssertFailed();
440 return 0;
441 }
442}
443
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