Mercurial > hg > xemacs-beta
comparison src/md5.c @ 276:6330739388db r21-0b36
Import from CVS: tag r21-0b36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:30:37 +0200 |
parents | 727739f917cb |
children | 7df0dd720c89 |
comparison
equal
deleted
inserted
replaced
275:a68ae4439f57 | 276:6330739388db |
---|---|
1 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm | 1 /* md5.c - Functions to compute MD5 message digest of files or memory blocks |
2 */ | 2 according to the definition of MD5 in RFC 1321 from April 1992. |
3 | 3 Copyright (C) 1995, 1996 Free Software Foundation, Inc. |
4 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All | 4 NOTE: The canonical source of this file is maintained with the GNU C |
5 rights reserved. | 5 Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. |
6 | 6 |
7 License to copy and use this software is granted provided that it | 7 This program is free software; you can redistribute it and/or modify it |
8 is identified as the "RSA Data Security, Inc. MD5 Message-Digest | 8 under the terms of the GNU General Public License as published by the |
9 Algorithm" in all material mentioning or referencing this software | 9 Free Software Foundation; either version 2, or (at your option) any |
10 or this function. | 10 later version. |
11 | 11 |
12 License is also granted to make and use derivative works provided | 12 This program is distributed in the hope that it will be useful, |
13 that such works are identified as "derived from the RSA Data | 13 but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 Security, Inc. MD5 Message-Digest Algorithm" in all material | 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 mentioning or referencing the derived work. | 15 GNU General Public License for more details. |
16 | 16 |
17 RSA Data Security, Inc. makes no representations concerning either | 17 You should have received a copy of the GNU General Public License |
18 the merchantability of this software or the suitability of this | 18 along with this program; if not, write to the Free Software Foundation, |
19 software for any particular purpose. It is provided "as is" | 19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
20 without express or implied warranty of any kind. | 20 |
21 | 21 /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ |
22 These notices must be retained in any copies of any part of this | 22 |
23 documentation and/or software. | 23 /* XEmacs frontend written by Ben Wing, Jareth Hein and Hrvoje Niksic. */ |
24 */ | 24 |
25 | 25 #ifdef HAVE_CONFIG_H |
26 /* Synched up with: Not in FSF. */ | 26 # include <config.h> |
27 /* This file has been Mule-ized. */ | 27 #endif |
28 | 28 |
29 #include <config.h> | 29 #include <sys/types.h> |
30 | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 | |
34 #include <stdio.h> | |
35 | |
36 #if defined HAVE_LIMITS_H || _LIBC | |
37 # include <limits.h> | |
38 #endif | |
39 | |
40 /* The following contortions are an attempt to use the C preprocessor | |
41 to determine an unsigned integral type that is 32 bits wide. An | |
42 alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but | |
43 doing that would require that the configure script compile and *run* | |
44 the resulting executable. Locally running cross-compiled executables | |
45 is usually not possible. */ | |
46 | |
47 #ifdef _LIBC | |
48 # include <sys/types.h> | |
49 typedef u_int32_t md5_uint32; | |
50 #else | |
51 # if defined __STDC__ && __STDC__ | |
52 # define UINT_MAX_32_BITS 4294967295U | |
53 # else | |
54 # define UINT_MAX_32_BITS 0xFFFFFFFF | |
55 # endif | |
56 | |
57 /* If UINT_MAX isn't defined, assume it's a 32-bit type. | |
58 This should be valid for all systems GNU cares about because | |
59 that doesn't include 16-bit systems, and only modern systems | |
60 (that certainly have <limits.h>) have 64+-bit integral types. */ | |
61 | |
62 # ifndef UINT_MAX | |
63 # define UINT_MAX UINT_MAX_32_BITS | |
64 # endif | |
65 | |
66 # if UINT_MAX == UINT_MAX_32_BITS | |
67 typedef unsigned int md5_uint32; | |
68 # else | |
69 # if USHRT_MAX == UINT_MAX_32_BITS | |
70 typedef unsigned short md5_uint32; | |
71 # else | |
72 # if ULONG_MAX == UINT_MAX_32_BITS | |
73 typedef unsigned long md5_uint32; | |
74 # else | |
75 /* The following line is intended to evoke an error. | |
76 Using #error is not portable enough. */ | |
77 "Cannot determine unsigned 32-bit data type." | |
78 # endif | |
79 # endif | |
80 # endif | |
81 #endif | |
82 | |
30 #include "lisp.h" | 83 #include "lisp.h" |
31 | |
32 #include "buffer.h" | 84 #include "buffer.h" |
33 #include "insdel.h" | |
34 #include "lstream.h" | 85 #include "lstream.h" |
35 #ifdef FILE_CODING | 86 #ifdef FILE_CODING |
36 #include "file-coding.h" | 87 # include "file-coding.h" |
37 #endif | 88 #endif |
38 | 89 |
39 typedef unsigned char *POINTER;/* POINTER defines a generic pointer type */ | 90 /* Structure to save state of computation between the single steps. */ |
40 typedef unsigned short int UINT2;/* UINT2 defines a two byte word */ | 91 struct md5_ctx |
41 typedef unsigned int UINT4;/* UINT4 defines a four byte word */ | 92 { |
42 | 93 md5_uint32 A; |
43 #define PROTO_LIST(list) list | 94 md5_uint32 B; |
44 #define MD_CTX MD5_CTX | 95 md5_uint32 C; |
45 #define MDInit MD5Init | 96 md5_uint32 D; |
46 #define MDUpdate MD5Update | 97 |
47 #define MDFinal MD5Final | 98 md5_uint32 total[2]; |
48 | 99 md5_uint32 buflen; |
49 /* MD5 context. */ | 100 char buffer[128]; |
50 typedef struct { | |
51 UINT4 state[4]; /* state (ABCD) */ | |
52 UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ | |
53 unsigned char buffer[64]; /* input buffer */ | |
54 } MD5_CTX; | |
55 | |
56 void MD5Init PROTO_LIST ((MD5_CTX *)); | |
57 void MD5Update PROTO_LIST | |
58 ((MD5_CTX *, CONST unsigned char *, unsigned int)); | |
59 void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); | |
60 | |
61 /* Constants for MD5Transform routine. | |
62 */ | |
63 #define S11 7 | |
64 #define S12 12 | |
65 #define S13 17 | |
66 #define S14 22 | |
67 #define S21 5 | |
68 #define S22 9 | |
69 #define S23 14 | |
70 #define S24 20 | |
71 #define S31 4 | |
72 #define S32 11 | |
73 #define S33 16 | |
74 #define S34 23 | |
75 #define S41 6 | |
76 #define S42 10 | |
77 #define S43 15 | |
78 #define S44 21 | |
79 | |
80 static void MD5Transform PROTO_LIST ((UINT4 [4], CONST unsigned char [64])); | |
81 static void Encode PROTO_LIST | |
82 ((unsigned char *, UINT4 *, unsigned int)); | |
83 static void Decode PROTO_LIST | |
84 ((UINT4 *, CONST unsigned char *, unsigned int)); | |
85 static void MD5_memcpy PROTO_LIST ((POINTER, CONST POINTER, unsigned int)); | |
86 static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); | |
87 | |
88 static unsigned char PADDING[64] = { | |
89 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
92 }; | 101 }; |
93 | 102 |
94 /* F, G, H and I are basic MD5 functions. | 103 #ifdef WORDS_BIGENDIAN |
95 */ | 104 # define SWAP(n) \ |
96 #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) | 105 (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) |
97 #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) | 106 #else |
98 #define H(x, y, z) ((x) ^ (y) ^ (z)) | 107 # define SWAP(n) (n) |
99 #define I(x, y, z) ((y) ^ ((x) | (~z))) | 108 #endif |
100 | 109 |
101 /* ROTATE_LEFT rotates x left n bits. | 110 |
102 */ | 111 /* This array contains the bytes used to pad the buffer to the next |
103 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) | 112 64-byte boundary. (RFC 1321, 3.1: Step 1) */ |
104 | 113 static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; |
105 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. | 114 |
106 Rotation is separate from addition to prevent recomputation. | 115 |
107 */ | 116 static void md5_process_block (CONST void *, size_t, struct md5_ctx *); |
108 #define FF(a, b, c, d, x, s, ac) { \ | 117 |
109 (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ | 118 |
110 (a) = ROTATE_LEFT ((a), (s)); \ | 119 /* Initialize structure containing state of computation. |
111 (a) += (b); \ | 120 (RFC 1321, 3.3: Step 3) */ |
112 } | |
113 #define GG(a, b, c, d, x, s, ac) { \ | |
114 (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ | |
115 (a) = ROTATE_LEFT ((a), (s)); \ | |
116 (a) += (b); \ | |
117 } | |
118 #define HH(a, b, c, d, x, s, ac) { \ | |
119 (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ | |
120 (a) = ROTATE_LEFT ((a), (s)); \ | |
121 (a) += (b); \ | |
122 } | |
123 #define II(a, b, c, d, x, s, ac) { \ | |
124 (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ | |
125 (a) = ROTATE_LEFT ((a), (s)); \ | |
126 (a) += (b); \ | |
127 } | |
128 | |
129 /* MD5 initialization. Begins an MD5 operation, writing a new context. | |
130 */ | |
131 void | |
132 MD5Init (MD5_CTX *context) | |
133 { | |
134 context->count[0] = context->count[1] = 0; | |
135 | |
136 /* Load magic initialization constants. */ | |
137 context->state[0] = 0x67452301; | |
138 context->state[1] = 0xefcdab89; | |
139 context->state[2] = 0x98badcfe; | |
140 context->state[3] = 0x10325476; | |
141 } | |
142 | |
143 /* MD5 block update operation. Continues an MD5 message-digest | |
144 operation, processing another message block, and updating the | |
145 context. | |
146 */ | |
147 void | |
148 MD5Update (MD5_CTX *context, CONST unsigned char *input, unsigned int inputLen) | |
149 { | |
150 unsigned int i, indice, partLen; | |
151 | |
152 /* Compute number of bytes mod 64 */ | |
153 indice = (unsigned int)((context->count[0] >> 3) & 0x3F); | |
154 | |
155 /* Update number of bits */ | |
156 if ((context->count[0] += ((UINT4)inputLen << 3)) | |
157 < ((UINT4)inputLen << 3)) | |
158 context->count[1]++; | |
159 context->count[1] += ((UINT4)inputLen >> 29); | |
160 | |
161 partLen = 64 - indice; | |
162 | |
163 /* Transform as many times as possible. */ | |
164 if (inputLen >= partLen) | |
165 { | |
166 MD5_memcpy ((POINTER)&context->buffer[indice], (CONST POINTER)input, | |
167 partLen); | |
168 MD5Transform (context->state, context->buffer); | |
169 | |
170 for (i = partLen; i + 63 < inputLen; i += 64) | |
171 MD5Transform (context->state, &input[i]); | |
172 | |
173 indice = 0; | |
174 } | |
175 else | |
176 i = 0; | |
177 | |
178 /* Buffer remaining input */ | |
179 MD5_memcpy ((POINTER)&context->buffer[indice], (CONST POINTER)&input[i], | |
180 inputLen-i); | |
181 } | |
182 | |
183 /* MD5 finalization. Ends an MD5 message-digest operation, writing the | |
184 message digest and zeroizing the context. */ | |
185 void | |
186 MD5Final (unsigned char digest[16], MD5_CTX *context) | |
187 { | |
188 unsigned char bits[8]; | |
189 unsigned int indice, padLen; | |
190 | |
191 /* Save number of bits */ | |
192 Encode (bits, context->count, 8); | |
193 | |
194 /* Pad out to 56 mod 64. | |
195 */ | |
196 indice = (unsigned int)((context->count[0] >> 3) & 0x3f); | |
197 padLen = (indice < 56) ? (56 - indice) : (120 - indice); | |
198 MD5Update (context, PADDING, padLen); | |
199 | |
200 /* Append length (before padding) */ | |
201 MD5Update (context, bits, 8); | |
202 /* Store state in digest */ | |
203 Encode (digest, context->state, 16); | |
204 | |
205 /* Zeroize sensitive information. | |
206 */ | |
207 MD5_memset ((POINTER)context, 0, sizeof (*context)); | |
208 } | |
209 | |
210 /* MD5 basic transformation. Transforms state based on block. | |
211 */ | |
212 static void | 121 static void |
213 MD5Transform (UINT4 state[4], CONST unsigned char block[64]) | 122 md5_init_ctx (struct md5_ctx *ctx) |
214 { | 123 { |
215 UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; | 124 ctx->A = 0x67452301; |
216 | 125 ctx->B = 0xefcdab89; |
217 Decode (x, block, 64); | 126 ctx->C = 0x98badcfe; |
218 | 127 ctx->D = 0x10325476; |
219 /* Round 1 */ | 128 |
220 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ | 129 ctx->total[0] = ctx->total[1] = 0; |
221 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ | 130 ctx->buflen = 0; |
222 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ | 131 } |
223 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ | 132 |
224 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ | 133 /* Put result from CTX in first 16 bytes following RESBUF. The result |
225 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ | 134 must be in little endian byte order. |
226 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ | 135 |
227 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ | 136 IMPORTANT: On some systems it is required that RESBUF is correctly |
228 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ | 137 aligned for a 32 bits value. */ |
229 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ | 138 static void * |
230 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ | 139 md5_read_ctx (CONST struct md5_ctx *ctx, void *resbuf) |
231 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ | 140 { |
232 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ | 141 ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); |
233 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ | 142 ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); |
234 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ | 143 ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); |
235 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ | 144 ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); |
236 | 145 |
237 /* Round 2 */ | 146 return resbuf; |
238 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ | 147 } |
239 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ | 148 |
240 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ | 149 /* Process the remaining bytes in the internal buffer and the usual |
241 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ | 150 prolog according to the standard and write the result to RESBUF. |
242 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ | 151 |
243 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ | 152 IMPORTANT: On some systems it is required that RESBUF is correctly |
244 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ | 153 aligned for a 32 bits value. */ |
245 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ | 154 static void * |
246 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ | 155 md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) |
247 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ | 156 { |
248 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ | 157 /* Take yet unprocessed bytes into account. */ |
249 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ | 158 md5_uint32 bytes = ctx->buflen; |
250 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ | 159 size_t pad; |
251 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ | 160 |
252 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ | 161 /* Now count remaining bytes. */ |
253 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ | 162 ctx->total[0] += bytes; |
254 | 163 if (ctx->total[0] < bytes) |
255 /* Round 3 */ | 164 ++ctx->total[1]; |
256 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ | 165 |
257 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ | 166 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; |
258 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ | 167 memcpy (&ctx->buffer[bytes], fillbuf, pad); |
259 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ | 168 |
260 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ | 169 /* Put the 64-bit file length in *bits* at the end of the buffer. */ |
261 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ | 170 *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); |
262 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ | 171 *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | |
263 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ | 172 (ctx->total[0] >> 29)); |
264 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ | 173 |
265 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ | 174 /* Process last bytes. */ |
266 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ | 175 md5_process_block (ctx->buffer, bytes + pad + 8, ctx); |
267 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ | 176 |
268 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ | 177 return md5_read_ctx (ctx, resbuf); |
269 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ | 178 } |
270 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ | 179 |
271 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ | 180 #ifndef emacs /* unused in Emacs */ |
272 | 181 /* Compute MD5 message digest for bytes read from STREAM. The |
273 /* Round 4 */ | 182 resulting message digest number will be written into the 16 bytes |
274 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ | 183 beginning at RESBLOCK. */ |
275 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ | 184 int |
276 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ | 185 md5_stream (FILE *stream, void *resblock) |
277 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ | 186 { |
278 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ | 187 /* Important: BLOCKSIZE must be a multiple of 64. */ |
279 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ | 188 #define BLOCKSIZE 4096 |
280 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ | 189 struct md5_ctx ctx; |
281 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ | 190 char buffer[BLOCKSIZE + 72]; |
282 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ | 191 size_t sum; |
283 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ | 192 |
284 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ | 193 /* Initialize the computation context. */ |
285 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ | 194 md5_init_ctx (&ctx); |
286 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ | 195 |
287 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ | 196 /* Iterate over full file contents. */ |
288 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ | 197 while (1) |
289 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ | 198 { |
290 | 199 /* We read the file in blocks of BLOCKSIZE bytes. One call of the |
291 state[0] += a; | 200 computation function processes the whole buffer so that with the |
292 state[1] += b; | 201 next round of the loop another block can be read. */ |
293 state[2] += c; | 202 size_t n; |
294 state[3] += d; | 203 sum = 0; |
295 | 204 |
296 /* Zeroize sensitive information. | 205 /* Read block. Take care for partial reads. */ |
297 */ | 206 do |
298 MD5_memset ((POINTER)x, 0, sizeof (x)); | 207 { |
299 } | 208 n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); |
300 | 209 |
301 /* Encodes input (UINT4) into output (unsigned char). Assumes len is | 210 sum += n; |
302 a multiple of 4. | 211 } |
303 */ | 212 while (sum < BLOCKSIZE && n != 0); |
213 if (n == 0 && ferror (stream)) | |
214 return 1; | |
215 | |
216 /* If end of file is reached, end the loop. */ | |
217 if (n == 0) | |
218 break; | |
219 | |
220 /* Process buffer with BLOCKSIZE bytes. Note that | |
221 BLOCKSIZE % 64 == 0 | |
222 */ | |
223 md5_process_block (buffer, BLOCKSIZE, &ctx); | |
224 } | |
225 | |
226 /* Add the last bytes if necessary. */ | |
227 if (sum > 0) | |
228 md5_process_bytes (buffer, sum, &ctx); | |
229 | |
230 /* Construct result in desired memory. */ | |
231 md5_finish_ctx (&ctx, resblock); | |
232 return 0; | |
233 } | |
234 | |
235 /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The | |
236 result is always in little endian byte order, so that a byte-wise | |
237 output yields to the wanted ASCII representation of the message | |
238 digest. */ | |
239 void * | |
240 md5_buffer (const char *buffer, size_t len, void *resblock) | |
241 { | |
242 struct md5_ctx ctx; | |
243 | |
244 /* Initialize the computation context. */ | |
245 md5_init_ctx (&ctx); | |
246 | |
247 /* Process whole buffer but last len % 64 bytes. */ | |
248 md5_process_bytes (buffer, len, &ctx); | |
249 | |
250 /* Put result in desired memory area. */ | |
251 return md5_finish_ctx (&ctx, resblock); | |
252 } | |
253 #endif /* not emacs */ | |
254 | |
255 | |
304 static void | 256 static void |
305 Encode (unsigned char *output, UINT4 *input, unsigned int len) | 257 md5_process_bytes (CONST void *buffer, size_t len, struct md5_ctx *ctx) |
306 { | 258 { |
307 unsigned int i, j; | 259 /* When we already have some bits in our internal buffer concatenate |
308 | 260 both inputs first. */ |
309 for (i = 0, j = 0; j < len; i++, j += 4) | 261 if (ctx->buflen != 0) |
310 { | 262 { |
311 output[j] = (unsigned char)(input[i] & 0xff); | 263 size_t left_over = ctx->buflen; |
312 output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); | 264 size_t add = 128 - left_over > len ? len : 128 - left_over; |
313 output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); | 265 |
314 output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); | 266 memcpy (&ctx->buffer[left_over], buffer, add); |
315 } | 267 ctx->buflen += add; |
316 } | 268 |
317 | 269 if (left_over + add > 64) |
318 /* Decodes input (unsigned char) into output (UINT4). Assumes len is | 270 { |
319 a multiple of 4. | 271 md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); |
320 */ | 272 /* The regions in the following copy operation cannot overlap. */ |
273 memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], | |
274 (left_over + add) & 63); | |
275 ctx->buflen = (left_over + add) & 63; | |
276 } | |
277 | |
278 buffer = (const char *) buffer + add; | |
279 len -= add; | |
280 } | |
281 | |
282 /* Process available complete blocks. */ | |
283 if (len > 64) | |
284 { | |
285 md5_process_block (buffer, len & ~63, ctx); | |
286 buffer = (const char *) buffer + (len & ~63); | |
287 len &= 63; | |
288 } | |
289 | |
290 /* Move remaining bytes in internal buffer. */ | |
291 if (len > 0) | |
292 { | |
293 memcpy (ctx->buffer, buffer, len); | |
294 ctx->buflen = len; | |
295 } | |
296 } | |
297 | |
298 | |
299 /* These are the four functions used in the four steps of the MD5 algorithm | |
300 and defined in the RFC 1321. The first function is a little bit optimized | |
301 (as found in Colin Plumbs public domain implementation). */ | |
302 /* #define FF(b, c, d) ((b & c) | (~b & d)) */ | |
303 #define FF(b, c, d) (d ^ (b & (c ^ d))) | |
304 #define FG(b, c, d) FF (d, b, c) | |
305 #define FH(b, c, d) (b ^ c ^ d) | |
306 #define FI(b, c, d) (c ^ (b | ~d)) | |
307 | |
308 /* Process LEN bytes of BUFFER, accumulating context into CTX. | |
309 It is assumed that LEN % 64 == 0. */ | |
310 | |
321 static void | 311 static void |
322 Decode (UINT4 *output, CONST unsigned char *input, unsigned int len) | 312 md5_process_block (CONST void *buffer, size_t len, struct md5_ctx *ctx) |
323 { | 313 { |
324 unsigned int i, j; | 314 md5_uint32 correct_words[16]; |
325 | 315 const md5_uint32 *words = buffer; |
326 for (i = 0, j = 0; j < len; i++, j += 4) | 316 size_t nwords = len / sizeof (md5_uint32); |
327 output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | | 317 const md5_uint32 *endp = words + nwords; |
328 (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); | 318 md5_uint32 A = ctx->A; |
329 } | 319 md5_uint32 B = ctx->B; |
330 | 320 md5_uint32 C = ctx->C; |
331 static void | 321 md5_uint32 D = ctx->D; |
332 MD5_memcpy (POINTER output, CONST POINTER input, unsigned int len) | 322 |
333 { | 323 /* First increment the byte count. RFC 1321 specifies the possible |
334 memcpy (output, input, len); | 324 length of the file up to 2^64 bits. Here we only compute the |
335 } | 325 number of bytes. Do a double word increment. */ |
336 | 326 ctx->total[0] += len; |
337 static void | 327 if (ctx->total[0] < len) |
338 MD5_memset (POINTER output, int value, unsigned int len) | 328 ++ctx->total[1]; |
339 { | 329 |
340 memset (output, value, len); | 330 /* Process all bytes in the buffer with 64 bytes in each round of |
341 } | 331 the loop. */ |
342 | 332 while (words < endp) |
343 /* unused */ | 333 { |
344 #if 0 | 334 md5_uint32 *cwp = correct_words; |
345 static void | 335 md5_uint32 A_save = A; |
346 LispMDString (char *string) | 336 md5_uint32 B_save = B; |
347 { | 337 md5_uint32 C_save = C; |
348 MD_CTX context; | 338 md5_uint32 D_save = D; |
349 unsigned char digest[16]; | 339 |
350 unsigned int len = strlen(string); | 340 /* First round: using the given function, the context and a constant |
351 | 341 the next context is computed. Because the algorithms processing |
352 MDInit (&context); | 342 unit is a 32-bit word and it is determined to work on words in |
353 MDUpdate (&context, string, len); | 343 little endian byte order we perhaps have to change the byte order |
354 MDFinal (digest, &context); | 344 before the computation. To reduce the work for the next steps |
355 } | 345 we store the swapped words in the array CORRECT_WORDS. */ |
356 #endif | 346 |
347 #define OP(a, b, c, d, s, T) \ | |
348 do \ | |
349 { \ | |
350 a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ | |
351 ++words; \ | |
352 CYCLIC (a, s); \ | |
353 a += b; \ | |
354 } \ | |
355 while (0) | |
356 | |
357 /* It is unfortunate that C does not provide an operator for | |
358 cyclic rotation. Hope the C compiler is smart enough. */ | |
359 #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) | |
360 | |
361 /* Before we start, one word to the strange constants. | |
362 They are defined in RFC 1321 as | |
363 | |
364 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 | |
365 */ | |
366 | |
367 /* Round 1. */ | |
368 OP (A, B, C, D, 7, 0xd76aa478); | |
369 OP (D, A, B, C, 12, 0xe8c7b756); | |
370 OP (C, D, A, B, 17, 0x242070db); | |
371 OP (B, C, D, A, 22, 0xc1bdceee); | |
372 OP (A, B, C, D, 7, 0xf57c0faf); | |
373 OP (D, A, B, C, 12, 0x4787c62a); | |
374 OP (C, D, A, B, 17, 0xa8304613); | |
375 OP (B, C, D, A, 22, 0xfd469501); | |
376 OP (A, B, C, D, 7, 0x698098d8); | |
377 OP (D, A, B, C, 12, 0x8b44f7af); | |
378 OP (C, D, A, B, 17, 0xffff5bb1); | |
379 OP (B, C, D, A, 22, 0x895cd7be); | |
380 OP (A, B, C, D, 7, 0x6b901122); | |
381 OP (D, A, B, C, 12, 0xfd987193); | |
382 OP (C, D, A, B, 17, 0xa679438e); | |
383 OP (B, C, D, A, 22, 0x49b40821); | |
384 | |
385 /* For the second to fourth round we have the possibly swapped words | |
386 in CORRECT_WORDS. Redefine the macro to take an additional first | |
387 argument specifying the function to use. */ | |
388 #undef OP | |
389 #define OP(f, a, b, c, d, k, s, T) \ | |
390 do \ | |
391 { \ | |
392 a += f (b, c, d) + correct_words[k] + T; \ | |
393 CYCLIC (a, s); \ | |
394 a += b; \ | |
395 } \ | |
396 while (0) | |
397 | |
398 /* Round 2. */ | |
399 OP (FG, A, B, C, D, 1, 5, 0xf61e2562); | |
400 OP (FG, D, A, B, C, 6, 9, 0xc040b340); | |
401 OP (FG, C, D, A, B, 11, 14, 0x265e5a51); | |
402 OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); | |
403 OP (FG, A, B, C, D, 5, 5, 0xd62f105d); | |
404 OP (FG, D, A, B, C, 10, 9, 0x02441453); | |
405 OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); | |
406 OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); | |
407 OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); | |
408 OP (FG, D, A, B, C, 14, 9, 0xc33707d6); | |
409 OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); | |
410 OP (FG, B, C, D, A, 8, 20, 0x455a14ed); | |
411 OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); | |
412 OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); | |
413 OP (FG, C, D, A, B, 7, 14, 0x676f02d9); | |
414 OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); | |
415 | |
416 /* Round 3. */ | |
417 OP (FH, A, B, C, D, 5, 4, 0xfffa3942); | |
418 OP (FH, D, A, B, C, 8, 11, 0x8771f681); | |
419 OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); | |
420 OP (FH, B, C, D, A, 14, 23, 0xfde5380c); | |
421 OP (FH, A, B, C, D, 1, 4, 0xa4beea44); | |
422 OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); | |
423 OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); | |
424 OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); | |
425 OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); | |
426 OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); | |
427 OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); | |
428 OP (FH, B, C, D, A, 6, 23, 0x04881d05); | |
429 OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); | |
430 OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); | |
431 OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); | |
432 OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); | |
433 | |
434 /* Round 4. */ | |
435 OP (FI, A, B, C, D, 0, 6, 0xf4292244); | |
436 OP (FI, D, A, B, C, 7, 10, 0x432aff97); | |
437 OP (FI, C, D, A, B, 14, 15, 0xab9423a7); | |
438 OP (FI, B, C, D, A, 5, 21, 0xfc93a039); | |
439 OP (FI, A, B, C, D, 12, 6, 0x655b59c3); | |
440 OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); | |
441 OP (FI, C, D, A, B, 10, 15, 0xffeff47d); | |
442 OP (FI, B, C, D, A, 1, 21, 0x85845dd1); | |
443 OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); | |
444 OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); | |
445 OP (FI, C, D, A, B, 6, 15, 0xa3014314); | |
446 OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); | |
447 OP (FI, A, B, C, D, 4, 6, 0xf7537e82); | |
448 OP (FI, D, A, B, C, 11, 10, 0xbd3af235); | |
449 OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); | |
450 OP (FI, B, C, D, A, 9, 21, 0xeb86d391); | |
451 | |
452 /* Add the starting values of the context. */ | |
453 A += A_save; | |
454 B += B_save; | |
455 C += C_save; | |
456 D += D_save; | |
457 } | |
458 | |
459 /* Put checksum in context given as argument. */ | |
460 ctx->A = A; | |
461 ctx->B = B; | |
462 ctx->C = C; | |
463 ctx->D = D; | |
464 } | |
357 | 465 |
358 | 466 |
359 /* XEmacs interface code. */ | 467 #ifdef emacs |
360 Lisp_Object Qmd5; | |
361 | |
362 DEFUN ("md5", Fmd5, 1, 5, 0, /* | |
363 Return the MD5 (a secure message digest algorithm) of an object. | |
364 OBJECT is either a string or a buffer. | |
365 Optional arguments START and END denote buffer positions for computing the | |
366 hash of a portion of OBJECT. The optional CODING argument specifies the coding | |
367 system the text is to be represented in while computing the digest. This only | |
368 has meaning with MULE, and defaults to the current format of the data. | |
369 If ERROR-ME-NOT is nil, report an error if the coding system can't be | |
370 determined. Else assume binary coding if all else fails. | |
371 */ | |
372 (object, start, end, coding, error_me_not)) | |
373 { | |
374 /* This function can GC */ | |
375 MD_CTX context; | |
376 unsigned char digest[16]; | |
377 unsigned char thehash[32]; | |
378 int i; | |
379 | |
380 MDInit (&context); | |
381 | |
382 if (NILP (object)) | |
383 { | |
384 MDUpdate (&context, (CONST unsigned char *) "", 0); | |
385 } | |
386 else | |
387 { | |
388 Lisp_Object instream, outstream; | |
389 Lstream *istr, *ostr; | |
390 static Extbyte_dynarr *conversion_out_dynarr; | |
391 char tempbuf[1024]; /* some random amount */ | |
392 struct gcpro gcpro1, gcpro2; | |
393 #ifdef FILE_CODING | 468 #ifdef FILE_CODING |
394 Lisp_Object conv_out_stream, coding_system; | 469 /* Find out what format the buffer will be saved in, so we can make |
395 Lstream *costr; | 470 the digest based on what it will look like on disk. */ |
396 struct gcpro gcpro3; | 471 static Lisp_Object |
397 #endif | 472 md5_coding_system (Lisp_Object object, Lisp_Object coding, Lisp_Object istream, |
398 | 473 int error_me_not) |
399 if (!conversion_out_dynarr) | 474 { |
400 conversion_out_dynarr = Dynarr_new (Extbyte); | 475 Lisp_Object coding_system; |
401 else | 476 |
402 Dynarr_reset (conversion_out_dynarr); | 477 if (NILP (coding)) |
403 | 478 { |
404 /* set up the in stream */ | |
405 if (BUFFERP (object)) | 479 if (BUFFERP (object)) |
406 { | 480 { |
407 struct buffer *b = decode_buffer (object, 1); | 481 /* Use the file coding for this buffer by default. */ |
408 Bufpos begv, endv; | 482 coding_system = XBUFFER (object)->buffer_file_coding_system; |
409 /* Figure out where we need to get info from */ | |
410 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL); | |
411 | |
412 instream = make_lisp_buffer_input_stream (b, begv, endv, 0); | |
413 } | 483 } |
414 else | 484 else |
415 { | 485 { |
416 Bytecount bstart, bend; | 486 /* Attempt to autodetect the coding of the string. This is |
417 CHECK_STRING (object); | 487 VERY hit-and-miss. */ |
418 get_string_range_byte (object, start, end, &bstart, &bend, | 488 enum eol_type eol = EOL_AUTODETECT; |
419 GB_HISTORICAL_STRING_BEHAVIOR); | 489 coding_system = Fget_coding_system (Qundecided); |
420 instream = make_lisp_string_input_stream (object, bstart, bend); | 490 determine_real_coding_system (XLSTREAM (istream), |
491 &coding_system, &eol); | |
421 } | 492 } |
422 istr = XLSTREAM (instream); | 493 if (NILP (coding_system)) |
423 | 494 coding_system = Fget_coding_system (Qbinary); |
424 #ifdef FILE_CODING | |
425 /* Find out what format the buffer will be saved in, so we can make | |
426 the digest based on what it will look like on disk */ | |
427 if (NILP(coding)) | |
428 { | |
429 if (BUFFERP(object)) | |
430 { | |
431 /* Use the file coding for this buffer by default */ | |
432 coding_system = XBUFFER(object)->buffer_file_coding_system; | |
433 } | |
434 else | |
435 { | |
436 /* attempt to autodetect the coding of the string. Note: this VERY hit-and-miss */ | |
437 enum eol_type eol = EOL_AUTODETECT; | |
438 coding_system = Fget_coding_system(Qundecided); | |
439 determine_real_coding_system(istr, &coding_system, &eol); | |
440 } | |
441 if (NILP(coding_system)) | |
442 coding_system = Fget_coding_system(Qbinary); | |
443 else | |
444 { | |
445 coding_system = Ffind_coding_system (coding_system); | |
446 if (NILP(coding_system)) | |
447 coding_system = Fget_coding_system(Qbinary); | |
448 } | |
449 } | |
450 else | 495 else |
451 { | 496 { |
452 coding_system = Ffind_coding_system (coding); | 497 coding_system = Ffind_coding_system (coding_system); |
453 if (NILP(coding_system)) | 498 if (NILP (coding_system)) |
454 { | 499 coding_system = Fget_coding_system (Qbinary); |
455 if (NILP(error_me_not)) | |
456 signal_simple_error("No such coding system", coding); | |
457 else | |
458 coding_system = Fget_coding_system(Qbinary); /* default to binary */ | |
459 } | |
460 } | 500 } |
461 #endif | 501 } |
462 | 502 else |
463 /* setup the out stream */ | 503 { |
464 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr); | 504 coding_system = Ffind_coding_system (coding); |
465 ostr = XLSTREAM (outstream); | 505 if (NILP (coding_system)) |
506 { | |
507 if (error_me_not) | |
508 /* Default to binary. */ | |
509 coding_system = Fget_coding_system (Qbinary); | |
510 else | |
511 signal_simple_error ("No such coding system", coding); | |
512 } | |
513 } | |
514 return coding_system; | |
515 } | |
516 #endif /* FILE_CODING */ | |
517 | |
518 | |
519 DEFUN ("md5", Fmd5, 1, 5, 0, /* | |
520 Return the MD5 message digest of OBJECT, a buffer or string. | |
521 | |
522 Optional arguments START and END denote positions for computing the | |
523 digest of a portion of OBJECT. | |
524 | |
525 The optional CODING argument specifies the coding system the text is to be | |
526 represented in while computing the digest. If unspecified, it defaults | |
527 to the current format of the data, or is guessed. | |
528 | |
529 If NOERROR is non-nil, silently assume binary coding if the guesswork | |
530 fails. Normally, an error is signaled in such case. | |
531 | |
532 CODING and NOERROR arguments are meaningful only in XEmacsen with | |
533 file-coding or Mule support. Otherwise, they are ignored. | |
534 */ | |
535 (object, start, end, coding, noerror)) | |
536 { | |
537 /* This function can GC */ | |
538 /* Can this really GC? How? */ | |
539 struct md5_ctx ctx; | |
540 unsigned char digest[16]; | |
541 unsigned char thehash[33]; | |
542 int i; | |
543 | |
544 Lisp_Object instream; | |
545 struct gcpro gcpro1; | |
466 #ifdef FILE_CODING | 546 #ifdef FILE_CODING |
467 /* setup the conversion stream */ | 547 Lisp_Object raw_instream; |
468 conv_out_stream = make_encoding_output_stream (ostr, coding_system); | 548 struct gcpro ngcpro1; |
469 costr = XLSTREAM (conv_out_stream); | 549 #endif |
470 GCPRO3 (instream, outstream, conv_out_stream); | 550 |
471 #else | 551 /* Set up the input stream. */ |
472 GCPRO2 (instream, outstream); | 552 if (BUFFERP (object)) |
473 #endif | 553 { |
474 | 554 struct buffer *b; |
475 /* Get the data while doing the conversion */ | 555 Bufpos begv, endv; |
476 while (1) { | 556 CHECK_LIVE_BUFFER (object); |
477 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf)); | 557 b = XBUFFER (object); |
478 if (!size_in_bytes) | 558 /* Figure out where we need to get info from */ |
479 break; | 559 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL); |
480 /* It does seem the flushes are necessary... */ | 560 |
561 instream = make_lisp_buffer_input_stream (b, begv, endv, 0); | |
562 } | |
563 else | |
564 { | |
565 Bytecount bstart, bend; | |
566 CHECK_STRING (object); | |
567 get_string_range_byte (object, start, end, &bstart, &bend, | |
568 GB_HISTORICAL_STRING_BEHAVIOR); | |
569 instream = make_lisp_string_input_stream (object, bstart, bend); | |
570 } | |
571 GCPRO1 (instream); | |
572 | |
481 #ifdef FILE_CODING | 573 #ifdef FILE_CODING |
482 Lstream_write (costr, tempbuf, size_in_bytes); | 574 /* Determine the coding and set up the conversion stream. */ |
483 Lstream_flush (costr); | 575 coding = md5_coding_system (object, coding, instream, !NILP (noerror)); |
484 #else | 576 raw_instream = instream; |
485 Lstream_write (ostr, tempbuf, size_in_bytes); | 577 instream = make_encoding_input_stream (XLSTREAM (instream), coding); |
486 #endif | 578 NGCPRO1 (raw_instream); |
487 Lstream_flush (ostr); | 579 #endif |
488 | 580 |
489 /* Update the digest */ | 581 /* Initialize MD5 context. */ |
490 | 582 md5_init_ctx (&ctx); |
491 MDUpdate (&context, (unsigned char *)Dynarr_atp(conversion_out_dynarr, 0), | 583 |
492 Dynarr_length(conversion_out_dynarr)); | 584 /* Get the data while doing the conversion. */ |
493 /* reset the dynarr */ | 585 while (1) |
494 Lstream_rewind(ostr); | 586 { |
495 } | 587 Bufbyte tempbuf[1024]; /* some random amount */ |
496 Lstream_close (istr); | 588 int size_in_bytes = Lstream_read (XLSTREAM (instream), |
589 tempbuf, sizeof (tempbuf)); | |
590 if (!size_in_bytes) | |
591 break; | |
592 | |
593 /* Process the bytes. */ | |
594 md5_process_bytes (tempbuf, size_in_bytes, &ctx); | |
595 } | |
596 Lstream_delete (XLSTREAM (instream)); | |
497 #ifdef FILE_CODING | 597 #ifdef FILE_CODING |
498 Lstream_close (costr); | 598 Lstream_delete (XLSTREAM (raw_instream)); |
499 #endif | 599 NUNGCPRO; |
500 Lstream_close (ostr); | 600 #endif |
501 | 601 UNGCPRO; |
502 UNGCPRO; | 602 |
503 Lstream_delete (istr); | 603 md5_finish_ctx (&ctx, digest); |
504 Lstream_delete (ostr); | |
505 #ifdef FILE_CODING | |
506 Lstream_delete (costr); | |
507 #endif | |
508 } | |
509 | |
510 MDFinal (digest, &context); | |
511 for (i = 0; i < 16; i++) | 604 for (i = 0; i < 16; i++) |
512 sprintf ((char *) (thehash + (i * 2)), "%02x", digest[i]); | 605 sprintf ((char *) (thehash + (i * 2)), "%02x", digest[i]); |
513 | 606 |
514 return (make_string (thehash, 32)); | 607 return make_string (thehash, 32); |
515 } | 608 } |
516 | 609 |
517 void | 610 void |
518 syms_of_md5 (void) | 611 syms_of_md5 (void) |
519 { | 612 { |
520 DEFSUBR (Fmd5); | 613 DEFSUBR (Fmd5); |
521 defsymbol (&Qmd5, "md5"); | |
522 } | 614 } |
523 | 615 |
524 void | 616 void |
525 vars_of_md5 (void) | 617 vars_of_md5 (void) |
526 { | 618 { |
527 Fprovide (Qmd5); | 619 Fprovide (intern ("md5")); |
528 } | 620 } |
621 #endif /* emacs */ |