]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/Md5.c
b1aa888e24c3aaac044c4074aa7cbc8f1cfa6fdb
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / Md5.c
1 /** @file
2 Implementation of MD5 algorithm
3
4 Copyright (c) 2004 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name:
14
15 Md5.c
16
17 Abstract:
18
19 Implementation of MD5 algorithm
20
21 **/
22
23 #include "Md5.h"
24
25 STATIC CONST UINT32 MD5_K[][2] = {
26 { 0, 1 },
27 { 1, 5 },
28 { 5, 3 },
29 { 0, 7 }
30 };
31
32 STATIC CONST UINT32 MD5_S[][4] = {
33 { 7, 22, 17, 12 },
34 { 5, 20, 14, 9 },
35 { 4, 23, 16 ,11 },
36 { 6, 21, 15, 10 },
37 };
38
39 STATIC CONST UINT32 MD5_T[] = {
40 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
41 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
42 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
43 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
44 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
45 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
46 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
47 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
48 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
49 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
50 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
51 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
52 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
53 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
54 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
55 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
56 };
57
58 STATIC CONST UINT8 Md5HashPadding[] =
59 {
60 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
76 };
77
78 //
79 // ROTATE_LEFT rotates x left n bits.
80 //
81 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
82
83 #define SA S[j & 3]
84 #define SB S[(j + 1) & 3]
85 #define SC S[(j + 2) & 3]
86 #define SD S[(j + 3) & 3]
87
88 //
89 // TF1, TF2, TF3, TF4 are basic MD5 transform functions
90 //
91 UINT32 TF1 (UINT32 A, UINT32 B, UINT32 C)
92 {
93 return (A & B) | (~A & C);
94 }
95
96 UINT32 TF2 (UINT32 A, UINT32 B, UINT32 C)
97 {
98 return (A & C) | (B & ~C);
99 }
100
101 UINT32 TF3 (UINT32 A, UINT32 B, UINT32 C)
102 {
103 return A ^ B ^ C;
104 }
105
106 UINT32 TF4 (UINT32 A, UINT32 B, UINT32 C)
107 {
108 return B ^ (A | ~C);
109 }
110
111 typedef
112 UINT32
113 (*MD5_TRANSFORM_FUNC) (
114 IN UINT32 A,
115 IN UINT32 B,
116 IN UINT32 C
117 );
118
119 STATIC CONST MD5_TRANSFORM_FUNC MD5_F[] = {
120 TF1,
121 TF2,
122 TF3,
123 TF4
124 };
125
126 /**
127 Perform the MD5 transform on 64 bytes data segment
128
129 @param Md5Ctx[in] it includes the data segment for Md5 transform
130
131 @retval NONE.
132
133 **/
134 STATIC
135 VOID
136 MD5Transform (
137 IN MD5_CTX *Md5Ctx
138 )
139 {
140 UINT32 i;
141 UINT32 j;
142 UINT32 S[MD5_HASHSIZE >> 2];
143 UINT32 *X;
144 UINT32 k;
145 UINT32 t;
146
147 X = (UINT32 *) Md5Ctx->M;
148
149 //
150 // Copy MD5 states to S
151 //
152 CopyMem (S, Md5Ctx->States, MD5_HASHSIZE);
153
154 t = 0;
155 for (i = 0; i < 4; i++) {
156 k = MD5_K[i][0];
157 for (j = 16; j > 0; j--) {
158 SA += (*MD5_F[i]) (SB, SC, SD) + X[k] + MD5_T[t];
159 SA = ROTATE_LEFT (SA, MD5_S[i][j & 3]);
160 SA += SB;
161
162 k += MD5_K[i][1];
163 k &= 15;
164
165 t++;
166 }
167 }
168
169 for (i = 0; i < 4; i++) {
170 Md5Ctx->States[i] += S[i];
171 }
172 }
173
174 /**
175 Copy data segment into the M field of MD5_CTX structure for later transform.
176 If the length of data segment is larger than 64 bytes, then does the transform
177 immediately and the generated Md5 code is stored in the States field of MD5_CTX
178 data struct for later accumulation.
179 All of Md5 code generated for the sequential 64-bytes data segaments are be
180 accumulated in MD5Final() function.
181
182 @param Md5Ctx[in] the data structure of storing the original data
183 segment and the final result.
184
185 @param Data[in] the data wanted to be transformed
186
187 @param DataLen[in] the length of data
188
189 @retval NONE.
190 **/
191 STATIC
192 VOID
193 MD5UpdateBlock (
194 IN MD5_CTX *Md5Ctx,
195 IN CONST UINT8 *Data,
196 IN UINTN DataLen
197 )
198 {
199 UINTN Limit;
200
201 for (Limit = 64 - Md5Ctx->Count; DataLen >= 64 - Md5Ctx->Count; Limit = 64) {
202 CopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, Limit);
203 MD5Transform (Md5Ctx);
204
205 Md5Ctx->Count = 0;
206 Data += Limit;
207 DataLen -= Limit;
208 }
209
210 CopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, DataLen);
211 Md5Ctx->Count += DataLen;
212 }
213
214 /**
215 Initialize four 32-bits chaining variables and use them to do the Md5 transform.
216
217 @param Md5Ctx[in] the data structure of Md5
218
219 @retval EFI_SUCCESS initialization is ok
220
221 **/
222 EFI_STATUS
223 MD5Init (
224 IN MD5_CTX *Md5Ctx
225 )
226 {
227 ZeroMem (Md5Ctx, sizeof (*Md5Ctx));
228
229 //
230 // Set magic initialization constants.
231 //
232 Md5Ctx->States[0] = 0x67452301;
233 Md5Ctx->States[1] = 0xefcdab89;
234 Md5Ctx->States[2] = 0x98badcfe;
235 Md5Ctx->States[3] = 0x10325476;
236
237 return EFI_SUCCESS;
238 }
239
240 /**
241 the external interface of Md5 algorithm
242
243 @param Md5Ctx[in] the data structure of storing the original data
244 segment and the final result.
245
246 @param Data[in] the data wanted to be transformed.
247
248 @param DataLen[in] the length of data.
249
250 @retval EFI_SUCCESS the transform is ok.
251
252 **/
253 EFI_STATUS
254 MD5Update (
255 IN MD5_CTX *Md5Ctx,
256 IN VOID *Data,
257 IN UINTN DataLen
258 )
259 {
260 if (EFI_ERROR (Md5Ctx->Status)) {
261 return Md5Ctx->Status;
262 }
263
264 MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) Data, DataLen);
265 Md5Ctx->Length += DataLen;
266 return EFI_SUCCESS;
267 }
268
269 /**
270 accumulate the MD5 value of every data segment and generate the finial
271 result according to MD5 algorithm
272
273 @param Md5Ctx[in] the data structure of storing the original data
274 segment and the final result.
275
276 @param HashVal[out] the final 128-bits output.
277
278 @retval EFI_SUCCESS the transform is ok.
279
280 **/
281 EFI_STATUS
282 MD5Final (
283 IN MD5_CTX *Md5Ctx,
284 OUT UINT8 *HashVal
285 )
286 {
287 UINTN PadLength;
288
289 if (Md5Ctx->Status == EFI_ALREADY_STARTED) {
290 //
291 // Store Hashed value & Zeroize sensitive context information.
292 //
293 CopyMem (HashVal, (UINT8 *) Md5Ctx->States, MD5_HASHSIZE);
294 ZeroMem ((UINT8 *)Md5Ctx, sizeof (*Md5Ctx));
295
296 return EFI_SUCCESS;
297 }
298
299 if (EFI_ERROR (Md5Ctx->Status)) {
300 return Md5Ctx->Status;
301 }
302
303 PadLength = Md5Ctx->Count >= 56 ? 120 : 56;
304 PadLength -= Md5Ctx->Count;
305 MD5UpdateBlock (Md5Ctx, Md5HashPadding, PadLength);
306 Md5Ctx->Length = LShiftU64 (Md5Ctx->Length, 3);
307 MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) &Md5Ctx->Length, 8);
308
309 ZeroMem (Md5Ctx->M, sizeof (Md5Ctx->M));
310 Md5Ctx->Length = 0;
311 Md5Ctx->Status = EFI_ALREADY_STARTED;
312 return MD5Final (Md5Ctx, HashVal);
313 }
314