|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @brief Source file for the implementation of the MD4 Message-Digest Algorithm - RFC 1320. |
|
19 @internalComponent |
|
20 */ |
|
21 |
|
22 #include "MD4.H" |
|
23 |
|
24 // This implementation is fully derived (copied) from the former MD4 |
|
25 // implementation provided by Symbian PPP in the release 7.0s of |
|
26 // Symbian OS. This is a provisional solution until the Symbian |
|
27 // Security subsystem components will provide a MD4 implementation. |
|
28 |
|
29 #define MD4_S11 3 |
|
30 #define MD4_S12 7 |
|
31 #define MD4_S13 11 |
|
32 #define MD4_S14 19 |
|
33 #define MD4_S21 3 |
|
34 #define MD4_S22 5 |
|
35 #define MD4_S23 9 |
|
36 #define MD4_S24 13 |
|
37 #define MD4_S31 3 |
|
38 #define MD4_S32 9 |
|
39 #define MD4_S33 11 |
|
40 #define MD4_S34 15 |
|
41 |
|
42 static const TUint8 Padding[64] = |
|
43 { |
|
44 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
47 }; |
|
48 |
|
49 // F, G, H and I are basic MD4 functions. |
|
50 #define MD4_F(x, y, z) ((x & y) | ((~x) & z)) |
|
51 #define MD4_G(x, y, z) ((x & y) | (x & z) | (y & z)) |
|
52 #define MD4_H(x, y, z) (x ^ y ^ z) |
|
53 |
|
54 // _ROL rotates x left n bits. |
|
55 #define _ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) |
|
56 |
|
57 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. |
|
58 // Rotation is separate from addition to prevent recomputation. |
|
59 #define MD4_FF(a, b, c, d, x, s ) { \ |
|
60 a += MD4_F(b, c, d) + x; \ |
|
61 a = _ROL (a, s); \ |
|
62 } |
|
63 #define MD4_GG(a, b, c, d, x, s) { \ |
|
64 a += MD4_G(b, c, d) + x + 0x5a827999; \ |
|
65 a = _ROL (a, s); \ |
|
66 } |
|
67 #define MD4_HH(a, b, c, d, x, s) { \ |
|
68 a += MD4_H(b, c, d) + x + 0x6ed9eba1; \ |
|
69 a = _ROL (a, s); \ |
|
70 } |
|
71 |
|
72 const TInt KMdOutputSize = 16; |
|
73 |
|
74 CMd4::CMd4() |
|
75 { |
|
76 iCount[0] = 0; |
|
77 iCount[1] = 0; |
|
78 // Load magic initialization constants. |
|
79 iState[0] = 0x67452301; |
|
80 iState[1] = 0xefcdab89; |
|
81 iState[2] = 0x98badcfe; |
|
82 iState[3] = 0x10325476; |
|
83 } |
|
84 |
|
85 CMd4* CMd4::NewL() |
|
86 { |
|
87 return new(ELeave) CMd4; |
|
88 } |
|
89 |
|
90 // moved from the former CDigestBase |
|
91 TInt CMd4::Input(const TDesC8& aDes) |
|
92 { |
|
93 Update(aDes.Ptr(), aDes.Length()); |
|
94 return KErrNone; |
|
95 } |
|
96 |
|
97 // moved from the former CDigestBase |
|
98 TInt CMd4::Output(TDes8& aDes) |
|
99 { |
|
100 TUint8* digest = (TUint8*)aDes.Ptr(); |
|
101 if (aDes.MaxLength()<16) |
|
102 return KErrOverflow; |
|
103 |
|
104 Final(digest); |
|
105 |
|
106 aDes.SetLength(16); |
|
107 return KErrNone; |
|
108 } |
|
109 |
|
110 // moved from the former CDigestBase |
|
111 TInt CMd4::OutputSize() const |
|
112 // |
|
113 // Return size of output |
|
114 // |
|
115 { |
|
116 return KMdOutputSize; |
|
117 } |
|
118 |
|
119 // moved from the former CDigestBase |
|
120 void CMd4::Update(const TUint8* aInput, TInt aLen) |
|
121 // |
|
122 // MD5 block update operation. Continues an MD5 message-digest |
|
123 // operation, processing another message block, and updating the |
|
124 // context. |
|
125 // |
|
126 { |
|
127 TInt i; |
|
128 TInt index; |
|
129 TInt partlen; |
|
130 |
|
131 /* Compute number of bytes mod 64 */ |
|
132 index = (TUint)((iCount[0] >> 3) & 0x3F); |
|
133 |
|
134 /* Update number of bits */ |
|
135 iCount[0] += (aLen<<3); |
|
136 |
|
137 if (iCount[0] < (TUint)(aLen<<3)) |
|
138 iCount[1]++; |
|
139 iCount[1] += (aLen>>29); |
|
140 partlen = 64 - index; |
|
141 |
|
142 // Transform as many times as possible. |
|
143 if (aLen >= partlen) |
|
144 { |
|
145 Mem::Copy(&iBuffer[index], aInput, partlen); |
|
146 Transform(iBuffer); |
|
147 for (i = partlen; i+63 < aLen; i += 64) |
|
148 Transform (&aInput[i]); |
|
149 index = 0; |
|
150 } |
|
151 else |
|
152 i = 0; |
|
153 |
|
154 /* Buffer remaining input */ |
|
155 Mem::Copy(&iBuffer[index], &aInput[i], aLen-i); |
|
156 } |
|
157 |
|
158 // moved from the former CDigestBase |
|
159 void CMd4::Final(TUint8* aDigest /*[16]*/) |
|
160 // |
|
161 // MD5 finalization. Ends an MD5 message-digest operation, writing the |
|
162 // the message digest and zeroizing the context. |
|
163 // |
|
164 { |
|
165 TUint8 bits[8]; |
|
166 TInt index, padlen; |
|
167 |
|
168 /* Save number of bits */ |
|
169 Encode(bits, (TUint32*)&iCount[0], 8); |
|
170 |
|
171 // Pad out to 56 mod 64. |
|
172 index = (TUint)((iCount[0] >> 3) & 0x3f); |
|
173 padlen = (index < 56) ? (56 - index) : (120 - index); |
|
174 Update(Padding, padlen); |
|
175 |
|
176 // Append length (before padding) */ |
|
177 Update(bits, 8); |
|
178 // Store state in digest */ |
|
179 Encode(aDigest, iState, 16); |
|
180 |
|
181 // Zero sensitive information. |
|
182 Mem::FillZ(iCount, sizeof(iCount)); |
|
183 Mem::FillZ(iState, sizeof(iState)); |
|
184 Mem::FillZ(iBuffer, sizeof(iBuffer)); |
|
185 } |
|
186 |
|
187 // moved from the former CDigestBase |
|
188 void CMd4::Encode(TUint8* aOutput, const TUint32* aInput, TInt aLen) |
|
189 // |
|
190 // Encodes input (UINT4) into output (unsigned char). |
|
191 // Assumes len is a multiple of 4. |
|
192 // |
|
193 { |
|
194 TInt i; |
|
195 TInt j; |
|
196 |
|
197 for (i=0, j=0; j<aLen; i++, j+=4) |
|
198 { |
|
199 aOutput[j] = (TUint8)(aInput[i] & 0xff); |
|
200 aOutput[j+1] = (TUint8)((aInput[i] >> 8) & 0xff); |
|
201 aOutput[j+2] = (TUint8)((aInput[i] >> 16) & 0xff); |
|
202 aOutput[j+3] = (TUint8)((aInput[i] >> 24) & 0xff); |
|
203 } |
|
204 } |
|
205 |
|
206 // moved from the former CDigestBase |
|
207 void CMd4::Decode(TUint32* aOutput, const TUint8* aInput, TInt aLen) |
|
208 // |
|
209 // Decodes input (unsigned char) into output (UINT4). |
|
210 // Assumes len is a multiple of 4. |
|
211 // |
|
212 { |
|
213 TInt i; |
|
214 TInt j; |
|
215 |
|
216 for (i=0, j=0; j<aLen; i++, j+=4) |
|
217 { |
|
218 aOutput[i] = ((TUint)aInput[j]) |
|
219 | (((TUint)aInput[j+1]) << 8) |
|
220 | (((TUint)aInput[j+2]) << 16) |
|
221 | (((TUint)aInput[j+3]) << 24); |
|
222 } |
|
223 } |
|
224 |
|
225 void CMd4::Transform (const TUint8* aBlock /*[64]*/) |
|
226 // |
|
227 // MD4 basic transformation. |
|
228 // Transforms state based on block. |
|
229 // |
|
230 { |
|
231 TUint a = iState[0]; |
|
232 TUint b = iState[1]; |
|
233 TUint c = iState[2]; |
|
234 TUint d = iState[3]; |
|
235 TUint x[16] = {0,}; |
|
236 |
|
237 Decode((TUint32*)&x[0], aBlock, 64); |
|
238 |
|
239 /* Round 1 */ |
|
240 MD4_FF (a, b, c, d, x[ 0], MD4_S11); /* 1 */ |
|
241 MD4_FF (d, a, b, c, x[ 1], MD4_S12); /* 2 */ |
|
242 MD4_FF (c, d, a, b, x[ 2], MD4_S13); /* 3 */ |
|
243 MD4_FF (b, c, d, a, x[ 3], MD4_S14); /* 4 */ |
|
244 MD4_FF (a, b, c, d, x[ 4], MD4_S11); /* 5 */ |
|
245 MD4_FF (d, a, b, c, x[ 5], MD4_S12); /* 6 */ |
|
246 MD4_FF (c, d, a, b, x[ 6], MD4_S13); /* 7 */ |
|
247 MD4_FF (b, c, d, a, x[ 7], MD4_S14); /* 8 */ |
|
248 MD4_FF (a, b, c, d, x[ 8], MD4_S11); /* 9 */ |
|
249 MD4_FF (d, a, b, c, x[ 9], MD4_S12); /* 10 */ |
|
250 MD4_FF (c, d, a, b, x[10], MD4_S13); /* 11 */ |
|
251 MD4_FF (b, c, d, a, x[11], MD4_S14); /* 12 */ |
|
252 MD4_FF (a, b, c, d, x[12], MD4_S11); /* 13 */ |
|
253 MD4_FF (d, a, b, c, x[13], MD4_S12); /* 14 */ |
|
254 MD4_FF (c, d, a, b, x[14], MD4_S13); /* 15 */ |
|
255 MD4_FF (b, c, d, a, x[15], MD4_S14); /* 16 */ |
|
256 |
|
257 /* Round 2 */ |
|
258 MD4_GG (a, b, c, d, x[ 0], MD4_S21); /* 17 */ |
|
259 MD4_GG (d, a, b, c, x[ 4], MD4_S22); /* 18 */ |
|
260 MD4_GG (c, d, a, b, x[ 8], MD4_S23); /* 19 */ |
|
261 MD4_GG (b, c, d, a, x[12], MD4_S24); /* 20 */ |
|
262 MD4_GG (a, b, c, d, x[ 1], MD4_S21); /* 21 */ |
|
263 MD4_GG (d, a, b, c, x[ 5], MD4_S22); /* 22 */ |
|
264 MD4_GG (c, d, a, b, x[ 9], MD4_S23); /* 23 */ |
|
265 MD4_GG (b, c, d, a, x[13], MD4_S24); /* 24 */ |
|
266 MD4_GG (a, b, c, d, x[ 2], MD4_S21); /* 25 */ |
|
267 MD4_GG (d, a, b, c, x[ 6], MD4_S22); /* 26 */ |
|
268 MD4_GG (c, d, a, b, x[10], MD4_S23); /* 27 */ |
|
269 MD4_GG (b, c, d, a, x[14], MD4_S24); /* 28 */ |
|
270 MD4_GG (a, b, c, d, x[ 3], MD4_S21); /* 29 */ |
|
271 MD4_GG (d, a, b, c, x[ 7], MD4_S22); /* 30 */ |
|
272 MD4_GG (c, d, a, b, x[11], MD4_S23); /* 31 */ |
|
273 MD4_GG (b, c, d, a, x[15], MD4_S24); /* 32 */ |
|
274 |
|
275 /* Round 3 */ |
|
276 MD4_HH (a, b, c, d, x[ 0], MD4_S31); /* 33 */ |
|
277 MD4_HH (d, a, b, c, x[ 8], MD4_S32); /* 34 */ |
|
278 MD4_HH (c, d, a, b, x[ 4], MD4_S33); /* 35 */ |
|
279 MD4_HH (b, c, d, a, x[12], MD4_S34); /* 36 */ |
|
280 MD4_HH (a, b, c, d, x[ 2], MD4_S31); /* 37 */ |
|
281 MD4_HH (d, a, b, c, x[10], MD4_S32); /* 38 */ |
|
282 MD4_HH (c, d, a, b, x[ 6], MD4_S33); /* 39 */ |
|
283 MD4_HH (b, c, d, a, x[14], MD4_S34); /* 40 */ |
|
284 MD4_HH (a, b, c, d, x[ 1], MD4_S31); /* 41 */ |
|
285 MD4_HH (d, a, b, c, x[ 9], MD4_S32); /* 42 */ |
|
286 MD4_HH (c, d, a, b, x[ 5], MD4_S33); /* 43 */ |
|
287 MD4_HH (b, c, d, a, x[13], MD4_S34); /* 44 */ |
|
288 MD4_HH (a, b, c, d, x[ 3], MD4_S31); /* 45 */ |
|
289 MD4_HH (d, a, b, c, x[11], MD4_S32); /* 46 */ |
|
290 MD4_HH (c, d, a, b, x[ 7], MD4_S33); /* 47 */ |
|
291 MD4_HH (b, c, d, a, x[15], MD4_S34); /* 48 */ |
|
292 |
|
293 |
|
294 iState[0] += a; |
|
295 iState[1] += b; |
|
296 iState[2] += c; |
|
297 iState[3] += d; |
|
298 |
|
299 // Zeroize sensitive information. |
|
300 Mem::FillZ(x, sizeof(x)); |
|
301 } |