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