VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/checksum/alt-md4.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/* $Id: alt-md4.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Message-Digest Algorithm 4, Alternative Implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2023 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* Defined Constants And Macros *
40*********************************************************************************************************************************/
41/** The MD4 block size in bytes. */
42#define RTMD4_BLOCK_SIZE 64
43/** The MD4 block size in bits. */
44#define RTMD4_BLOCK_SIZE_IN_BITS (RTMD4_BLOCK_SIZE * 8)
45
46
47/*********************************************************************************************************************************
48* Header Files *
49*********************************************************************************************************************************/
50#include "internal/iprt.h"
51#include <iprt/types.h>
52
53
54/** Our private context structure. */
55typedef struct RTMD4ALTPRIVATECTX
56{
57 uint32_t uA;
58 uint32_t uB;
59 uint32_t uC;
60 uint32_t uD;
61 /** Message length in bits. */
62 uint64_t cTotalBits;
63 /** Input buffer. cTotalBits indicates how much is present. */
64 union
65 {
66 uint8_t abBuffer[RTMD4_BLOCK_SIZE];
67 uint32_t aX[RTMD4_BLOCK_SIZE / 4];
68 } u;
69} RTMD4ALTPRIVATECTX;
70
71
72#define RT_MD4_PRIVATE_ALT_CONTEXT
73#include <iprt/md4.h>
74
75#include <iprt/asm.h>
76#include <iprt/assert.h>
77#include <iprt/string.h>
78
79AssertCompile(RT_SIZEOFMEMB(RTMD4CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTMD4CONTEXT, AltPrivate));
80
81
82/*********************************************************************************************************************************
83* Global Variables *
84*********************************************************************************************************************************/
85/** MD4 padding. */
86static const uint8_t g_abMd4Padding[RTMD4_BLOCK_SIZE] =
87{
88 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92};
93
94
95
96
97RTDECL(void) RTMd4Init(PRTMD4CONTEXT pCtx)
98{
99 pCtx->AltPrivate.uA = UINT32_C(0x67452301);
100 pCtx->AltPrivate.uB = UINT32_C(0xefcdab89);
101 pCtx->AltPrivate.uC = UINT32_C(0x98badcfe);
102 pCtx->AltPrivate.uD = UINT32_C(0x10325476);
103 pCtx->AltPrivate.cTotalBits = 0;
104 RT_ZERO(pCtx->AltPrivate.u);
105}
106RT_EXPORT_SYMBOL(RTMd4Init);
107
108
109DECLINLINE(uint32_t) rtMd4FuncF(uint32_t uX, uint32_t uY, uint32_t uZ)
110{
111 return (uX & uY) | (~uX & uZ);
112}
113
114DECLINLINE(uint32_t) rtMd4FuncG(uint32_t uX, uint32_t uY, uint32_t uZ)
115{
116 return (uX & (uY | uZ)) | (uY & uZ);
117}
118
119DECLINLINE(uint32_t) rtMd4FuncH(uint32_t uX, uint32_t uY, uint32_t uZ)
120{
121 return uX ^ uY ^ uZ;
122}
123
124
125/**
126 * Process the current block.
127 *
128 * Requires one of the rtMD4BlockInit functions to be called first.
129 *
130 * @param pCtx The MD4 context.
131 */
132DECLINLINE(void) rtMD4BlockProcess(PRTMD4CONTEXT pCtx)
133{
134#ifdef RT_BIG_ENDIAN
135 /* Convert the X array to little endian. */
136 for (uint32_t i = 0; i < RT_ELEMENTS(pCtx->AltPrivate.u.aX); i++)
137 pCtx->AltPrivate.u.aX[i] = RT_BSWAP_U32(pCtx->AltPrivate.u.aX[i]);
138#endif
139
140 /* Instead of saving A, B, C, D we copy them into variables and work on those. */
141 uint32_t A = pCtx->AltPrivate.uA;
142 uint32_t B = pCtx->AltPrivate.uB;
143 uint32_t C = pCtx->AltPrivate.uC;
144 uint32_t D = pCtx->AltPrivate.uD;
145
146 /* Round #1: */
147#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncF(b, c, d) + pCtx->AltPrivate.u.aX[k], s)
148 A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 1, 7); C = ABCD_K_S(C,D,A,B, 2, 11); B = ABCD_K_S(B,C,D,A, 3, 19);
149 A = ABCD_K_S(A,B,C,D, 4, 3); D = ABCD_K_S(D,A,B,C, 5, 7); C = ABCD_K_S(C,D,A,B, 6, 11); B = ABCD_K_S(B,C,D,A, 7, 19);
150 A = ABCD_K_S(A,B,C,D, 8, 3); D = ABCD_K_S(D,A,B,C, 9, 7); C = ABCD_K_S(C,D,A,B, 10, 11); B = ABCD_K_S(B,C,D,A, 11, 19);
151 A = ABCD_K_S(A,B,C,D, 12, 3); D = ABCD_K_S(D,A,B,C, 13, 7); C = ABCD_K_S(C,D,A,B, 14, 11); B = ABCD_K_S(B,C,D,A, 15, 19);
152#undef ABCD_K_S
153
154 /* Round #2: */
155#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncG(b, c, d) + pCtx->AltPrivate.u.aX[k] + UINT32_C(0x5a827999), s)
156 A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 4, 5); C = ABCD_K_S(C,D,A,B, 8, 9); B = ABCD_K_S(B,C,D,A, 12, 13);
157 A = ABCD_K_S(A,B,C,D, 1, 3); D = ABCD_K_S(D,A,B,C, 5, 5); C = ABCD_K_S(C,D,A,B, 9, 9); B = ABCD_K_S(B,C,D,A, 13, 13);
158 A = ABCD_K_S(A,B,C,D, 2, 3); D = ABCD_K_S(D,A,B,C, 6, 5); C = ABCD_K_S(C,D,A,B, 10, 9); B = ABCD_K_S(B,C,D,A, 14, 13);
159 A = ABCD_K_S(A,B,C,D, 3, 3); D = ABCD_K_S(D,A,B,C, 7, 5); C = ABCD_K_S(C,D,A,B, 11, 9); B = ABCD_K_S(B,C,D,A, 15, 13);
160#undef ABCD_K_S
161
162 /* Round #3: */
163#define ABCD_K_S(a,b,c,d, k, s) ASMRotateLeftU32(a + rtMd4FuncH(b, c, d) + pCtx->AltPrivate.u.aX[k] + UINT32_C(0x6ed9eba1), s)
164 A = ABCD_K_S(A,B,C,D, 0, 3); D = ABCD_K_S(D,A,B,C, 8, 9); C = ABCD_K_S(C,D,A,B, 4, 11); B = ABCD_K_S(B,C,D,A, 12, 15);
165 A = ABCD_K_S(A,B,C,D, 2, 3); D = ABCD_K_S(D,A,B,C, 10, 9); C = ABCD_K_S(C,D,A,B, 6, 11); B = ABCD_K_S(B,C,D,A, 14, 15);
166 A = ABCD_K_S(A,B,C,D, 1, 3); D = ABCD_K_S(D,A,B,C, 9, 9); C = ABCD_K_S(C,D,A,B, 5, 11); B = ABCD_K_S(B,C,D,A, 13, 15);
167 A = ABCD_K_S(A,B,C,D, 3, 3); D = ABCD_K_S(D,A,B,C, 11, 9); C = ABCD_K_S(C,D,A,B, 7, 11); B = ABCD_K_S(B,C,D,A, 15, 15);
168#undef ABCD_K_S
169
170 /* Perform the additions. */
171 pCtx->AltPrivate.uA += A;
172 pCtx->AltPrivate.uB += B;
173 pCtx->AltPrivate.uC += C;
174 pCtx->AltPrivate.uD += D;
175}
176
177
178RTDECL(void) RTMd4Update(PRTMD4CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
179{
180 uint8_t const *pbBuf = (uint8_t const *)pvBuf;
181
182 /*
183 * Deal with buffered bytes first.
184 */
185 if (pCtx->AltPrivate.cTotalBits & (RTMD4_BLOCK_SIZE_IN_BITS - 1))
186 {
187 uint8_t cbBuffered = (pCtx->AltPrivate.cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1);
188 uint8_t cbMissing = RTMD4_BLOCK_SIZE - cbBuffered;
189 if (cbBuf >= cbMissing)
190 {
191 memcpy(&pCtx->AltPrivate.u.abBuffer[cbBuffered], pbBuf, cbMissing);
192 pCtx->AltPrivate.cTotalBits += cbMissing << 3;
193 pbBuf += cbMissing;
194 cbBuf -= cbMissing;
195
196 rtMD4BlockProcess(pCtx);
197 }
198 else
199 {
200 memcpy(&pCtx->AltPrivate.u.abBuffer[cbBuffered], pbBuf, cbBuf);
201 pCtx->AltPrivate.cTotalBits += cbBuf << 3;
202 return;
203 }
204 }
205
206 /*
207 * Process full blocks directly from the input buffer.
208 */
209 while (cbBuf >= RTMD4_BLOCK_SIZE)
210 {
211 memcpy(&pCtx->AltPrivate.u.abBuffer[0], pbBuf, RTMD4_BLOCK_SIZE);
212 rtMD4BlockProcess(pCtx);
213
214 pbBuf += RTMD4_BLOCK_SIZE;
215 cbBuf -= RTMD4_BLOCK_SIZE;
216 pCtx->AltPrivate.cTotalBits += RTMD4_BLOCK_SIZE_IN_BITS;
217 }
218
219 /*
220 * Stash any remaining bytes into the context buffer.
221 */
222 if (cbBuf > 0)
223 {
224 memcpy(&pCtx->AltPrivate.u.abBuffer[0], pbBuf, cbBuf);
225 pCtx->AltPrivate.cTotalBits += cbBuf << 3;
226 }
227}
228RT_EXPORT_SYMBOL(RTMd4Update);
229
230
231RTDECL(void) RTMd4Final(PRTMD4CONTEXT pCtx, uint8_t pabDigest[RTMD4_HASH_SIZE])
232{
233 uint64_t const cTotalBits = pCtx->AltPrivate.cTotalBits;
234
235 /*
236 * Pad input to block size minus sizeof(cTotalBits).
237 */
238 uint8_t cbMissing = RTMD4_BLOCK_SIZE - ((cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1));
239 uint8_t cbPadding = cbMissing + (cbMissing > 8 ? 0 : RTMD4_BLOCK_SIZE) - 8;
240 Assert(cbPadding > 0 && cbPadding <= sizeof(g_abMd4Padding));
241 RTMd4Update(pCtx, g_abMd4Padding, cbPadding);
242 Assert(((pCtx->AltPrivate.cTotalBits >> 3) & (RTMD4_BLOCK_SIZE - 1)) == RTMD4_BLOCK_SIZE - 8);
243
244 /*
245 * Encode the total bitcount at the end of the buffer and do the final round.
246 */
247 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 8] = (uint8_t)(cTotalBits );
248 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 7] = (uint8_t)(cTotalBits >> 8);
249 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 6] = (uint8_t)(cTotalBits >> 16);
250 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 5] = (uint8_t)(cTotalBits >> 24);
251 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 4] = (uint8_t)(cTotalBits >> 32);
252 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 3] = (uint8_t)(cTotalBits >> 40);
253 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 2] = (uint8_t)(cTotalBits >> 48);
254 pCtx->AltPrivate.u.abBuffer[RTMD4_BLOCK_SIZE - 1] = (uint8_t)(cTotalBits >> 56);
255 rtMD4BlockProcess(pCtx);
256
257 /*
258 * Done. Just encode the digest.
259 */
260 pabDigest[ 0] = (uint8_t)(pCtx->AltPrivate.uA );
261 pabDigest[ 1] = (uint8_t)(pCtx->AltPrivate.uA >> 8);
262 pabDigest[ 2] = (uint8_t)(pCtx->AltPrivate.uA >> 16);
263 pabDigest[ 3] = (uint8_t)(pCtx->AltPrivate.uA >> 24);
264 pabDigest[ 4] = (uint8_t)(pCtx->AltPrivate.uB );
265 pabDigest[ 5] = (uint8_t)(pCtx->AltPrivate.uB >> 8);
266 pabDigest[ 6] = (uint8_t)(pCtx->AltPrivate.uB >> 16);
267 pabDigest[ 7] = (uint8_t)(pCtx->AltPrivate.uB >> 24);
268 pabDigest[ 8] = (uint8_t)(pCtx->AltPrivate.uC );
269 pabDigest[ 9] = (uint8_t)(pCtx->AltPrivate.uC >> 8);
270 pabDigest[10] = (uint8_t)(pCtx->AltPrivate.uC >> 16);
271 pabDigest[11] = (uint8_t)(pCtx->AltPrivate.uC >> 24);
272 pabDigest[12] = (uint8_t)(pCtx->AltPrivate.uD );
273 pabDigest[13] = (uint8_t)(pCtx->AltPrivate.uD >> 8);
274 pabDigest[14] = (uint8_t)(pCtx->AltPrivate.uD >> 16);
275 pabDigest[15] = (uint8_t)(pCtx->AltPrivate.uD >> 24);
276
277 /*
278 * Nuke the state.
279 */
280 RT_ZERO(pCtx->AltPrivate);
281}
282RT_EXPORT_SYMBOL(RTMd4Final);
283
284
285RTDECL(void) RTMd4(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTMD4_HASH_SIZE])
286{
287 RTMD4CONTEXT Ctx;
288 RTMd4Init(&Ctx);
289 RTMd4Update(&Ctx, pvBuf, cbBuf);
290 RTMd4Final(&Ctx, pabDigest);
291}
292RT_EXPORT_SYMBOL(RTMd4);
293
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use