root / md5.pas @ 3
Historique | Voir | Annoter | Télécharger (12,451 ko)
1 | 3 | avalancogn | // tabs = 2
|
---|---|---|---|
2 | // -----------------------------------------------------------------------------------------------
|
||
3 | //
|
||
4 | // MD5 Message-Digest for Delphi 4
|
||
5 | //
|
||
6 | // Delphi 4 Unit implementing the
|
||
7 | // RSA Data Security, Inc. MD5 Message-Digest Algorithm
|
||
8 | //
|
||
9 | // Implementation of Ronald L. Rivest's RFC 1321
|
||
10 | //
|
||
11 | // Copyright ? 1997-1999 Medienagentur Fichtner & Meyer
|
||
12 | // Written by Matthias Fichtner
|
||
13 | //
|
||
14 | // -----------------------------------------------------------------------------------------------
|
||
15 | // See RFC 1321 for RSA Data Security's copyright and license notice!
|
||
16 | // -----------------------------------------------------------------------------------------------
|
||
17 | //
|
||
18 | // 14-Jun-97 mf Implemented MD5 according to RFC 1321 RFC 1321
|
||
19 | // 16-Jun-97 mf Initial release of the compiled unit (no source code) RFC 1321
|
||
20 | // 28-Feb-99 mf Added MD5Match function for comparing two digests RFC 1321
|
||
21 | // 13-Sep-99 mf Reworked the entire unit RFC 1321
|
||
22 | // 17-Sep-99 mf Reworked the "Test Driver" project RFC 1321
|
||
23 | // 19-Sep-99 mf Release of sources for MD5 unit and "Test Driver" project RFC 1321
|
||
24 | //
|
||
25 | // -----------------------------------------------------------------------------------------------
|
||
26 | // The latest release of md5.pas will always be available from
|
||
27 | // the distribution site at: http://www.fichtner.net/delphi/md5/
|
||
28 | // -----------------------------------------------------------------------------------------------
|
||
29 | // Please send questions, bug reports and suggestions
|
||
30 | // regarding this code to: mfichtner@fichtner-meyer.com
|
||
31 | // -----------------------------------------------------------------------------------------------
|
||
32 | // This code is provided "as is" without express or
|
||
33 | // implied warranty of any kind. Use it at your own risk.
|
||
34 | // -----------------------------------------------------------------------------------------------
|
||
35 | |||
36 | unit md5;
|
||
37 | |||
38 | // -----------------------------------------------------------------------------------------------
|
||
39 | INTERFACE
|
||
40 | // -----------------------------------------------------------------------------------------------
|
||
41 | |||
42 | uses
|
||
43 | Windows; |
||
44 | |||
45 | type
|
||
46 | MD5Count = array[0..1] of DWORD; |
||
47 | MD5State = array[0..3] of DWORD; |
||
48 | MD5Block = array[0..15] of DWORD; |
||
49 | MD5CBits = array[0..7] of byte; |
||
50 | MD5Digest = array[0..15] of byte; |
||
51 | MD5Buffer = array[0..63] of byte; |
||
52 | MD5Context = record
|
||
53 | State: MD5State; |
||
54 | Count: MD5Count; |
||
55 | Buffer: MD5Buffer; |
||
56 | end;
|
||
57 | |||
58 | procedure MD5Init(var Context: MD5Context); |
||
59 | procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword); |
||
60 | procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest); |
||
61 | |||
62 | function MD5String(M: string): MD5Digest; |
||
63 | function MD5File(N: string): MD5Digest; |
||
64 | function MD5Print(D: MD5Digest): string; |
||
65 | |||
66 | function MD5Match(D1, D2: MD5Digest): boolean;
|
||
67 | |||
68 | // -----------------------------------------------------------------------------------------------
|
||
69 | IMPLEMENTATION
|
||
70 | // -----------------------------------------------------------------------------------------------
|
||
71 | |||
72 | var
|
||
73 | PADDING: MD5Buffer = ( |
||
74 | $80, $00, $00, $00, $00, $00, $00, $00, |
||
75 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
76 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
77 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
78 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
79 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
80 | $00, $00, $00, $00, $00, $00, $00, $00, |
||
81 | $00, $00, $00, $00, $00, $00, $00, $00 |
||
82 | ); |
||
83 | |||
84 | function F(x, y, z: DWORD): DWORD;
|
||
85 | begin
|
||
86 | Result := (x and y) or ((not x) and z); |
||
87 | end;
|
||
88 | |||
89 | function G(x, y, z: DWORD): DWORD;
|
||
90 | begin
|
||
91 | Result := (x and z) or (y and (not z)); |
||
92 | end;
|
||
93 | |||
94 | function H(x, y, z: DWORD): DWORD;
|
||
95 | begin
|
||
96 | Result := x xor y xor z; |
||
97 | end;
|
||
98 | |||
99 | function I(x, y, z: DWORD): DWORD;
|
||
100 | begin
|
||
101 | Result := y xor (x or (not z)); |
||
102 | end;
|
||
103 | |||
104 | procedure rot(var x: DWORD; n: BYTE); |
||
105 | begin
|
||
106 | x := (x shl n) or (x shr (32 - n)); |
||
107 | end;
|
||
108 | |||
109 | procedure FF(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); |
||
110 | begin
|
||
111 | inc(a, F(b, c, d) + x + ac); |
||
112 | rot(a, s); |
||
113 | inc(a, b); |
||
114 | end;
|
||
115 | |||
116 | procedure GG(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); |
||
117 | begin
|
||
118 | inc(a, G(b, c, d) + x + ac); |
||
119 | rot(a, s); |
||
120 | inc(a, b); |
||
121 | end;
|
||
122 | |||
123 | procedure HH(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); |
||
124 | begin
|
||
125 | inc(a, H(b, c, d) + x + ac); |
||
126 | rot(a, s); |
||
127 | inc(a, b); |
||
128 | end;
|
||
129 | |||
130 | procedure II(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); |
||
131 | begin
|
||
132 | inc(a, I(b, c, d) + x + ac); |
||
133 | rot(a, s); |
||
134 | inc(a, b); |
||
135 | end;
|
||
136 | |||
137 | // -----------------------------------------------------------------------------------------------
|
||
138 | |||
139 | // Encode Count bytes at Source into (Count / 4) DWORDs at Target
|
||
140 | procedure Encode(Source, Target: pointer; Count: longword);
|
||
141 | var
|
||
142 | S: PByte; |
||
143 | T: PDWORD; |
||
144 | I: longword; |
||
145 | begin
|
||
146 | S := Source; |
||
147 | T := Target; |
||
148 | for I := 1 to Count div 4 do begin |
||
149 | T^ := S^; |
||
150 | inc(S); |
||
151 | T^ := T^ or (S^ shl 8); |
||
152 | inc(S); |
||
153 | T^ := T^ or (S^ shl 16); |
||
154 | inc(S); |
||
155 | T^ := T^ or (S^ shl 24); |
||
156 | inc(S); |
||
157 | inc(T); |
||
158 | end;
|
||
159 | end;
|
||
160 | |||
161 | // Decode Count DWORDs at Source into (Count * 4) Bytes at Target
|
||
162 | procedure Decode(Source, Target: pointer; Count: longword);
|
||
163 | var
|
||
164 | S: PDWORD; |
||
165 | T: PByte; |
||
166 | I: longword; |
||
167 | begin
|
||
168 | S := Source; |
||
169 | T := Target; |
||
170 | for I := 1 to Count do begin |
||
171 | T^ := S^ and $ff; |
||
172 | inc(T); |
||
173 | T^ := (S^ shr 8) and $ff; |
||
174 | inc(T); |
||
175 | T^ := (S^ shr 16) and $ff; |
||
176 | inc(T); |
||
177 | T^ := (S^ shr 24) and $ff; |
||
178 | inc(T); |
||
179 | inc(S); |
||
180 | end;
|
||
181 | end;
|
||
182 | |||
183 | // Transform State according to first 64 bytes at Buffer
|
||
184 | procedure Transform(Buffer: pointer; var State: MD5State); |
||
185 | var
|
||
186 | a, b, c, d: DWORD; |
||
187 | Block: MD5Block; |
||
188 | begin
|
||
189 | Encode(Buffer, @Block, 64);
|
||
190 | a := State[0];
|
||
191 | b := State[1];
|
||
192 | c := State[2];
|
||
193 | d := State[3];
|
||
194 | FF (a, b, c, d, Block[ 0], 7, $d76aa478); |
||
195 | FF (d, a, b, c, Block[ 1], 12, $e8c7b756); |
||
196 | FF (c, d, a, b, Block[ 2], 17, $242070db); |
||
197 | FF (b, c, d, a, Block[ 3], 22, $c1bdceee); |
||
198 | FF (a, b, c, d, Block[ 4], 7, $f57c0faf); |
||
199 | FF (d, a, b, c, Block[ 5], 12, $4787c62a); |
||
200 | FF (c, d, a, b, Block[ 6], 17, $a8304613); |
||
201 | FF (b, c, d, a, Block[ 7], 22, $fd469501); |
||
202 | FF (a, b, c, d, Block[ 8], 7, $698098d8); |
||
203 | FF (d, a, b, c, Block[ 9], 12, $8b44f7af); |
||
204 | FF (c, d, a, b, Block[10], 17, $ffff5bb1); |
||
205 | FF (b, c, d, a, Block[11], 22, $895cd7be); |
||
206 | FF (a, b, c, d, Block[12], 7, $6b901122); |
||
207 | FF (d, a, b, c, Block[13], 12, $fd987193); |
||
208 | FF (c, d, a, b, Block[14], 17, $a679438e); |
||
209 | FF (b, c, d, a, Block[15], 22, $49b40821); |
||
210 | GG (a, b, c, d, Block[ 1], 5, $f61e2562); |
||
211 | GG (d, a, b, c, Block[ 6], 9, $c040b340); |
||
212 | GG (c, d, a, b, Block[11], 14, $265e5a51); |
||
213 | GG (b, c, d, a, Block[ 0], 20, $e9b6c7aa); |
||
214 | GG (a, b, c, d, Block[ 5], 5, $d62f105d); |
||
215 | GG (d, a, b, c, Block[10], 9, $2441453); |
||
216 | GG (c, d, a, b, Block[15], 14, $d8a1e681); |
||
217 | GG (b, c, d, a, Block[ 4], 20, $e7d3fbc8); |
||
218 | GG (a, b, c, d, Block[ 9], 5, $21e1cde6); |
||
219 | GG (d, a, b, c, Block[14], 9, $c33707d6); |
||
220 | GG (c, d, a, b, Block[ 3], 14, $f4d50d87); |
||
221 | GG (b, c, d, a, Block[ 8], 20, $455a14ed); |
||
222 | GG (a, b, c, d, Block[13], 5, $a9e3e905); |
||
223 | GG (d, a, b, c, Block[ 2], 9, $fcefa3f8); |
||
224 | GG (c, d, a, b, Block[ 7], 14, $676f02d9); |
||
225 | GG (b, c, d, a, Block[12], 20, $8d2a4c8a); |
||
226 | HH (a, b, c, d, Block[ 5], 4, $fffa3942); |
||
227 | HH (d, a, b, c, Block[ 8], 11, $8771f681); |
||
228 | HH (c, d, a, b, Block[11], 16, $6d9d6122); |
||
229 | HH (b, c, d, a, Block[14], 23, $fde5380c); |
||
230 | HH (a, b, c, d, Block[ 1], 4, $a4beea44); |
||
231 | HH (d, a, b, c, Block[ 4], 11, $4bdecfa9); |
||
232 | HH (c, d, a, b, Block[ 7], 16, $f6bb4b60); |
||
233 | HH (b, c, d, a, Block[10], 23, $bebfbc70); |
||
234 | HH (a, b, c, d, Block[13], 4, $289b7ec6); |
||
235 | HH (d, a, b, c, Block[ 0], 11, $eaa127fa); |
||
236 | HH (c, d, a, b, Block[ 3], 16, $d4ef3085); |
||
237 | HH (b, c, d, a, Block[ 6], 23, $4881d05); |
||
238 | HH (a, b, c, d, Block[ 9], 4, $d9d4d039); |
||
239 | HH (d, a, b, c, Block[12], 11, $e6db99e5); |
||
240 | HH (c, d, a, b, Block[15], 16, $1fa27cf8); |
||
241 | HH (b, c, d, a, Block[ 2], 23, $c4ac5665); |
||
242 | II (a, b, c, d, Block[ 0], 6, $f4292244); |
||
243 | II (d, a, b, c, Block[ 7], 10, $432aff97); |
||
244 | II (c, d, a, b, Block[14], 15, $ab9423a7); |
||
245 | II (b, c, d, a, Block[ 5], 21, $fc93a039); |
||
246 | II (a, b, c, d, Block[12], 6, $655b59c3); |
||
247 | II (d, a, b, c, Block[ 3], 10, $8f0ccc92); |
||
248 | II (c, d, a, b, Block[10], 15, $ffeff47d); |
||
249 | II (b, c, d, a, Block[ 1], 21, $85845dd1); |
||
250 | II (a, b, c, d, Block[ 8], 6, $6fa87e4f); |
||
251 | II (d, a, b, c, Block[15], 10, $fe2ce6e0); |
||
252 | II (c, d, a, b, Block[ 6], 15, $a3014314); |
||
253 | II (b, c, d, a, Block[13], 21, $4e0811a1); |
||
254 | II (a, b, c, d, Block[ 4], 6, $f7537e82); |
||
255 | II (d, a, b, c, Block[11], 10, $bd3af235); |
||
256 | II (c, d, a, b, Block[ 2], 15, $2ad7d2bb); |
||
257 | II (b, c, d, a, Block[ 9], 21, $eb86d391); |
||
258 | inc(State[0], a);
|
||
259 | inc(State[1], b);
|
||
260 | inc(State[2], c);
|
||
261 | inc(State[3], d);
|
||
262 | end;
|
||
263 | |||
264 | // -----------------------------------------------------------------------------------------------
|
||
265 | |||
266 | // Initialize given Context
|
||
267 | procedure MD5Init(var Context: MD5Context); |
||
268 | begin
|
||
269 | with Context do begin |
||
270 | State[0] := $67452301; |
||
271 | State[1] := $efcdab89; |
||
272 | State[2] := $98badcfe; |
||
273 | State[3] := $10325476; |
||
274 | Count[0] := 0; |
||
275 | Count[1] := 0; |
||
276 | ZeroMemory(@Buffer, SizeOf(MD5Buffer)); |
||
277 | end;
|
||
278 | end;
|
||
279 | |||
280 | // Update given Context to include Length bytes of Input
|
||
281 | procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword); |
||
282 | var
|
||
283 | Index: longword; |
||
284 | PartLen: longword; |
||
285 | I: longword; |
||
286 | begin
|
||
287 | with Context do begin |
||
288 | Index := (Count[0] shr 3) and $3f; |
||
289 | inc(Count[0], Length shl 3); |
||
290 | if Count[0] < (Length shl 3) then inc(Count[1]); |
||
291 | inc(Count[1], Length shr 29); |
||
292 | end;
|
||
293 | PartLen := 64 - Index;
|
||
294 | if Length >= PartLen then begin |
||
295 | CopyMemory(@Context.Buffer[Index], Input, PartLen); |
||
296 | Transform(@Context.Buffer, Context.State); |
||
297 | I := PartLen; |
||
298 | while I + 63 < Length do begin |
||
299 | Transform(@Input[I], Context.State); |
||
300 | inc(I, 64);
|
||
301 | end;
|
||
302 | Index := 0;
|
||
303 | end else I := 0; |
||
304 | CopyMemory(@Context.Buffer[Index], @Input[I], Length - I); |
||
305 | end;
|
||
306 | |||
307 | // Finalize given Context, create Digest and zeroize Context
|
||
308 | procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest); |
||
309 | var
|
||
310 | Bits: MD5CBits; |
||
311 | Index: longword; |
||
312 | PadLen: longword; |
||
313 | begin
|
||
314 | Decode(@Context.Count, @Bits, 2);
|
||
315 | Index := (Context.Count[0] shr 3) and $3f; |
||
316 | if Index < 56 then PadLen := 56 - Index else PadLen := 120 - Index; |
||
317 | MD5Update(Context, @PADDING, PadLen); |
||
318 | MD5Update(Context, @Bits, 8);
|
||
319 | Decode(@Context.State, @Digest, 4);
|
||
320 | ZeroMemory(@Context, SizeOf(MD5Context)); |
||
321 | end;
|
||
322 | |||
323 | // -----------------------------------------------------------------------------------------------
|
||
324 | |||
325 | // Create digest of given Message
|
||
326 | function MD5String(M: string): MD5Digest; |
||
327 | var
|
||
328 | Context: MD5Context; |
||
329 | begin
|
||
330 | MD5Init(Context); |
||
331 | MD5Update(Context, pChar(M), length(M)); |
||
332 | MD5Final(Context, Result); |
||
333 | end;
|
||
334 | |||
335 | // Create digest of file with given Name
|
||
336 | function MD5File(N: string): MD5Digest; |
||
337 | var
|
||
338 | FileHandle: THandle; |
||
339 | MapHandle: THandle; |
||
340 | ViewPointer: pointer; |
||
341 | Context: MD5Context; |
||
342 | begin
|
||
343 | MD5Init(Context); |
||
344 | FileHandle := CreateFile(pChar(N), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
|
||
345 | nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0); |
||
346 | if FileHandle <> INVALID_HANDLE_VALUE then try |
||
347 | MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); |
||
348 | if MapHandle <> 0 then try |
||
349 | ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); |
||
350 | if ViewPointer <> nil then try |
||
351 | MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil));
|
||
352 | finally
|
||
353 | UnmapViewOfFile(ViewPointer); |
||
354 | end;
|
||
355 | finally
|
||
356 | CloseHandle(MapHandle); |
||
357 | end;
|
||
358 | finally
|
||
359 | CloseHandle(FileHandle); |
||
360 | end;
|
||
361 | MD5Final(Context, Result); |
||
362 | end;
|
||
363 | |||
364 | // Create hex representation of given Digest
|
||
365 | function MD5Print(D: MD5Digest): string; |
||
366 | var
|
||
367 | I: byte; |
||
368 | MD5String: string;
|
||
369 | const
|
||
370 | Digits: array[0..15] of char = |
||
371 | ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); |
||
372 | begin
|
||
373 | MD5String := '';
|
||
374 | for I := 0 to 15 do MD5String := MD5String + Digits[(D[I] shr 4) and $0f] + Digits[D[I] and $0f]; |
||
375 | Result := Copy(MD5String, 1, 8) + '-' + Copy(MD5String, 9, 8) + '-' + Copy(MD5String, 17, 8) + '-' + Copy(MD5String, 25, 8); |
||
376 | end;
|
||
377 | |||
378 | // -----------------------------------------------------------------------------------------------
|
||
379 | |||
380 | // Compare two Digests
|
||
381 | function MD5Match(D1, D2: MD5Digest): boolean;
|
||
382 | var
|
||
383 | I: byte; |
||
384 | begin
|
||
385 | I := 0;
|
||
386 | Result := TRUE; |
||
387 | while Result and (I < 16) do begin |
||
388 | Result := D1[I] = D2[I]; |
||
389 | inc(I); |
||
390 | end;
|
||
391 | end;
|
||
392 | |||
393 | end.
|