PolarSSL v1.2.12
md5.c
Go to the documentation of this file.
1 /*
2  * RFC 1321 compliant MD5 implementation
3  *
4  * Copyright (C) 2006-2013, Brainspark B.V.
5  *
6  * This file is part of PolarSSL (http://www.polarssl.org)
7  * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 /*
26  * The MD5 algorithm was designed by Ron Rivest in 1991.
27  *
28  * http://www.ietf.org/rfc/rfc1321.txt
29  */
30 
31 #include "polarssl/config.h"
32 
33 #if defined(POLARSSL_MD5_C)
34 
35 #include "polarssl/md5.h"
36 
37 #if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
38 #include <stdio.h>
39 #endif
40 
41 /* Implementation that should never be optimized out by the compiler */
42 static void polarssl_zeroize( void *v, size_t n ) {
43  volatile unsigned char *p = v; while( n-- ) *p++ = 0;
44 }
45 
46 #if !defined(POLARSSL_MD5_ALT)
47 
48 /*
49  * 32-bit integer manipulation macros (little endian)
50  */
51 #ifndef GET_UINT32_LE
52 #define GET_UINT32_LE(n,b,i) \
53 { \
54  (n) = ( (uint32_t) (b)[(i) ] ) \
55  | ( (uint32_t) (b)[(i) + 1] << 8 ) \
56  | ( (uint32_t) (b)[(i) + 2] << 16 ) \
57  | ( (uint32_t) (b)[(i) + 3] << 24 ); \
58 }
59 #endif
60 
61 #ifndef PUT_UINT32_LE
62 #define PUT_UINT32_LE(n,b,i) \
63 { \
64  (b)[(i) ] = (unsigned char) ( (n) ); \
65  (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
66  (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
67  (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
68 }
69 #endif
70 
71 /*
72  * MD5 context setup
73  */
74 void md5_starts( md5_context *ctx )
75 {
76  ctx->total[0] = 0;
77  ctx->total[1] = 0;
78 
79  ctx->state[0] = 0x67452301;
80  ctx->state[1] = 0xEFCDAB89;
81  ctx->state[2] = 0x98BADCFE;
82  ctx->state[3] = 0x10325476;
83 }
84 
85 void md5_process( md5_context *ctx, const unsigned char data[64] )
86 {
87  uint32_t X[16], A, B, C, D;
88 
89  GET_UINT32_LE( X[ 0], data, 0 );
90  GET_UINT32_LE( X[ 1], data, 4 );
91  GET_UINT32_LE( X[ 2], data, 8 );
92  GET_UINT32_LE( X[ 3], data, 12 );
93  GET_UINT32_LE( X[ 4], data, 16 );
94  GET_UINT32_LE( X[ 5], data, 20 );
95  GET_UINT32_LE( X[ 6], data, 24 );
96  GET_UINT32_LE( X[ 7], data, 28 );
97  GET_UINT32_LE( X[ 8], data, 32 );
98  GET_UINT32_LE( X[ 9], data, 36 );
99  GET_UINT32_LE( X[10], data, 40 );
100  GET_UINT32_LE( X[11], data, 44 );
101  GET_UINT32_LE( X[12], data, 48 );
102  GET_UINT32_LE( X[13], data, 52 );
103  GET_UINT32_LE( X[14], data, 56 );
104  GET_UINT32_LE( X[15], data, 60 );
105 
106 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
107 
108 #define P(a,b,c,d,k,s,t) \
109 { \
110  a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
111 }
112 
113  A = ctx->state[0];
114  B = ctx->state[1];
115  C = ctx->state[2];
116  D = ctx->state[3];
117 
118 #define F(x,y,z) (z ^ (x & (y ^ z)))
119 
120  P( A, B, C, D, 0, 7, 0xD76AA478 );
121  P( D, A, B, C, 1, 12, 0xE8C7B756 );
122  P( C, D, A, B, 2, 17, 0x242070DB );
123  P( B, C, D, A, 3, 22, 0xC1BDCEEE );
124  P( A, B, C, D, 4, 7, 0xF57C0FAF );
125  P( D, A, B, C, 5, 12, 0x4787C62A );
126  P( C, D, A, B, 6, 17, 0xA8304613 );
127  P( B, C, D, A, 7, 22, 0xFD469501 );
128  P( A, B, C, D, 8, 7, 0x698098D8 );
129  P( D, A, B, C, 9, 12, 0x8B44F7AF );
130  P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
131  P( B, C, D, A, 11, 22, 0x895CD7BE );
132  P( A, B, C, D, 12, 7, 0x6B901122 );
133  P( D, A, B, C, 13, 12, 0xFD987193 );
134  P( C, D, A, B, 14, 17, 0xA679438E );
135  P( B, C, D, A, 15, 22, 0x49B40821 );
136 
137 #undef F
138 
139 #define F(x,y,z) (y ^ (z & (x ^ y)))
140 
141  P( A, B, C, D, 1, 5, 0xF61E2562 );
142  P( D, A, B, C, 6, 9, 0xC040B340 );
143  P( C, D, A, B, 11, 14, 0x265E5A51 );
144  P( B, C, D, A, 0, 20, 0xE9B6C7AA );
145  P( A, B, C, D, 5, 5, 0xD62F105D );
146  P( D, A, B, C, 10, 9, 0x02441453 );
147  P( C, D, A, B, 15, 14, 0xD8A1E681 );
148  P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
149  P( A, B, C, D, 9, 5, 0x21E1CDE6 );
150  P( D, A, B, C, 14, 9, 0xC33707D6 );
151  P( C, D, A, B, 3, 14, 0xF4D50D87 );
152  P( B, C, D, A, 8, 20, 0x455A14ED );
153  P( A, B, C, D, 13, 5, 0xA9E3E905 );
154  P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
155  P( C, D, A, B, 7, 14, 0x676F02D9 );
156  P( B, C, D, A, 12, 20, 0x8D2A4C8A );
157 
158 #undef F
159 
160 #define F(x,y,z) (x ^ y ^ z)
161 
162  P( A, B, C, D, 5, 4, 0xFFFA3942 );
163  P( D, A, B, C, 8, 11, 0x8771F681 );
164  P( C, D, A, B, 11, 16, 0x6D9D6122 );
165  P( B, C, D, A, 14, 23, 0xFDE5380C );
166  P( A, B, C, D, 1, 4, 0xA4BEEA44 );
167  P( D, A, B, C, 4, 11, 0x4BDECFA9 );
168  P( C, D, A, B, 7, 16, 0xF6BB4B60 );
169  P( B, C, D, A, 10, 23, 0xBEBFBC70 );
170  P( A, B, C, D, 13, 4, 0x289B7EC6 );
171  P( D, A, B, C, 0, 11, 0xEAA127FA );
172  P( C, D, A, B, 3, 16, 0xD4EF3085 );
173  P( B, C, D, A, 6, 23, 0x04881D05 );
174  P( A, B, C, D, 9, 4, 0xD9D4D039 );
175  P( D, A, B, C, 12, 11, 0xE6DB99E5 );
176  P( C, D, A, B, 15, 16, 0x1FA27CF8 );
177  P( B, C, D, A, 2, 23, 0xC4AC5665 );
178 
179 #undef F
180 
181 #define F(x,y,z) (y ^ (x | ~z))
182 
183  P( A, B, C, D, 0, 6, 0xF4292244 );
184  P( D, A, B, C, 7, 10, 0x432AFF97 );
185  P( C, D, A, B, 14, 15, 0xAB9423A7 );
186  P( B, C, D, A, 5, 21, 0xFC93A039 );
187  P( A, B, C, D, 12, 6, 0x655B59C3 );
188  P( D, A, B, C, 3, 10, 0x8F0CCC92 );
189  P( C, D, A, B, 10, 15, 0xFFEFF47D );
190  P( B, C, D, A, 1, 21, 0x85845DD1 );
191  P( A, B, C, D, 8, 6, 0x6FA87E4F );
192  P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
193  P( C, D, A, B, 6, 15, 0xA3014314 );
194  P( B, C, D, A, 13, 21, 0x4E0811A1 );
195  P( A, B, C, D, 4, 6, 0xF7537E82 );
196  P( D, A, B, C, 11, 10, 0xBD3AF235 );
197  P( C, D, A, B, 2, 15, 0x2AD7D2BB );
198  P( B, C, D, A, 9, 21, 0xEB86D391 );
199 
200 #undef F
201 
202  ctx->state[0] += A;
203  ctx->state[1] += B;
204  ctx->state[2] += C;
205  ctx->state[3] += D;
206 }
207 
208 /*
209  * MD5 process buffer
210  */
211 void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen )
212 {
213  size_t fill;
214  uint32_t left;
215 
216  if( ilen <= 0 )
217  return;
218 
219  left = ctx->total[0] & 0x3F;
220  fill = 64 - left;
221 
222  ctx->total[0] += (uint32_t) ilen;
223  ctx->total[0] &= 0xFFFFFFFF;
224 
225  if( ctx->total[0] < (uint32_t) ilen )
226  ctx->total[1]++;
227 
228  if( left && ilen >= fill )
229  {
230  memcpy( (void *) (ctx->buffer + left), input, fill );
231  md5_process( ctx, ctx->buffer );
232  input += fill;
233  ilen -= fill;
234  left = 0;
235  }
236 
237  while( ilen >= 64 )
238  {
239  md5_process( ctx, input );
240  input += 64;
241  ilen -= 64;
242  }
243 
244  if( ilen > 0 )
245  {
246  memcpy( (void *) (ctx->buffer + left), input, ilen );
247  }
248 }
249 
250 static const unsigned char md5_padding[64] =
251 {
252  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
253  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
256 };
257 
258 /*
259  * MD5 final digest
260  */
261 void md5_finish( md5_context *ctx, unsigned char output[16] )
262 {
263  uint32_t last, padn;
264  uint32_t high, low;
265  unsigned char msglen[8];
266 
267  high = ( ctx->total[0] >> 29 )
268  | ( ctx->total[1] << 3 );
269  low = ( ctx->total[0] << 3 );
270 
271  PUT_UINT32_LE( low, msglen, 0 );
272  PUT_UINT32_LE( high, msglen, 4 );
273 
274  last = ctx->total[0] & 0x3F;
275  padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
276 
277  md5_update( ctx, md5_padding, padn );
278  md5_update( ctx, msglen, 8 );
279 
280  PUT_UINT32_LE( ctx->state[0], output, 0 );
281  PUT_UINT32_LE( ctx->state[1], output, 4 );
282  PUT_UINT32_LE( ctx->state[2], output, 8 );
283  PUT_UINT32_LE( ctx->state[3], output, 12 );
284 }
285 
286 #endif /* !POLARSSL_MD5_ALT */
287 
288 /*
289  * output = MD5( input buffer )
290  */
291 void md5( const unsigned char *input, size_t ilen, unsigned char output[16] )
292 {
293  md5_context ctx;
294 
295  md5_starts( &ctx );
296  md5_update( &ctx, input, ilen );
297  md5_finish( &ctx, output );
298 
299  polarssl_zeroize( &ctx, sizeof( md5_context ) );
300 }
301 
302 #if defined(POLARSSL_FS_IO)
303 /*
304  * output = MD5( file contents )
305  */
306 int md5_file( const char *path, unsigned char output[16] )
307 {
308  FILE *f;
309  size_t n;
310  md5_context ctx;
311  unsigned char buf[1024];
312 
313  if( ( f = fopen( path, "rb" ) ) == NULL )
315 
316  md5_starts( &ctx );
317 
318  while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
319  md5_update( &ctx, buf, n );
320 
321  md5_finish( &ctx, output );
322 
323  polarssl_zeroize( &ctx, sizeof( md5_context ) );
324 
325  if( ferror( f ) != 0 )
326  {
327  fclose( f );
329  }
330 
331  fclose( f );
332  return( 0 );
333 }
334 #endif /* POLARSSL_FS_IO */
335 
336 /*
337  * MD5 HMAC context setup
338  */
339 void md5_hmac_starts( md5_context *ctx, const unsigned char *key, size_t keylen )
340 {
341  size_t i;
342  unsigned char sum[16];
343 
344  if( keylen > 64 )
345  {
346  md5( key, keylen, sum );
347  keylen = 16;
348  key = sum;
349  }
350 
351  memset( ctx->ipad, 0x36, 64 );
352  memset( ctx->opad, 0x5C, 64 );
353 
354  for( i = 0; i < keylen; i++ )
355  {
356  ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
357  ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
358  }
359 
360  md5_starts( ctx );
361  md5_update( ctx, ctx->ipad, 64 );
362 
363  polarssl_zeroize( sum, sizeof( sum ) );
364 }
365 
366 /*
367  * MD5 HMAC process buffer
368  */
369 void md5_hmac_update( md5_context *ctx, const unsigned char *input, size_t ilen )
370 {
371  md5_update( ctx, input, ilen );
372 }
373 
374 /*
375  * MD5 HMAC final digest
376  */
377 void md5_hmac_finish( md5_context *ctx, unsigned char output[16] )
378 {
379  unsigned char tmpbuf[16];
380 
381  md5_finish( ctx, tmpbuf );
382  md5_starts( ctx );
383  md5_update( ctx, ctx->opad, 64 );
384  md5_update( ctx, tmpbuf, 16 );
385  md5_finish( ctx, output );
386 
387  polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) );
388 }
389 
390 /*
391  * MD5 HMAC context reset
392  */
393 void md5_hmac_reset( md5_context *ctx )
394 {
395  md5_starts( ctx );
396  md5_update( ctx, ctx->ipad, 64 );
397 }
398 
399 /*
400  * output = HMAC-MD5( hmac key, input buffer )
401  */
402 void md5_hmac( const unsigned char *key, size_t keylen,
403  const unsigned char *input, size_t ilen,
404  unsigned char output[16] )
405 {
406  md5_context ctx;
407 
408  md5_hmac_starts( &ctx, key, keylen );
409  md5_hmac_update( &ctx, input, ilen );
410  md5_hmac_finish( &ctx, output );
411 
412  polarssl_zeroize( &ctx, sizeof( md5_context ) );
413 }
414 
415 #if defined(POLARSSL_SELF_TEST)
416 /*
417  * RFC 1321 test vectors
418  */
419 static unsigned char md5_test_buf[7][81] =
420 {
421  { "" },
422  { "a" },
423  { "abc" },
424  { "message digest" },
425  { "abcdefghijklmnopqrstuvwxyz" },
426  { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
427  { "12345678901234567890123456789012345678901234567890123456789012" \
428  "345678901234567890" }
429 };
430 
431 static const int md5_test_buflen[7] =
432 {
433  0, 1, 3, 14, 26, 62, 80
434 };
435 
436 static const unsigned char md5_test_sum[7][16] =
437 {
438  { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
439  0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
440  { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
441  0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
442  { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
443  0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
444  { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
445  0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
446  { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
447  0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
448  { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
449  0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
450  { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
451  0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
452 };
453 
454 /*
455  * RFC 2202 test vectors
456  */
457 static unsigned char md5_hmac_test_key[7][26] =
458 {
459  { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" },
460  { "Jefe" },
461  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" },
462  { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
463  "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
464  { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" },
465  { "" }, /* 0xAA 80 times */
466  { "" }
467 };
468 
469 static const int md5_hmac_test_keylen[7] =
470 {
471  16, 4, 16, 25, 16, 80, 80
472 };
473 
474 static unsigned char md5_hmac_test_buf[7][74] =
475 {
476  { "Hi There" },
477  { "what do ya want for nothing?" },
478  { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
479  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
480  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
481  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
482  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
483  { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
484  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
485  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
486  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
487  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
488  { "Test With Truncation" },
489  { "Test Using Larger Than Block-Size Key - Hash Key First" },
490  { "Test Using Larger Than Block-Size Key and Larger"
491  " Than One Block-Size Data" }
492 };
493 
494 static const int md5_hmac_test_buflen[7] =
495 {
496  8, 28, 50, 50, 20, 54, 73
497 };
498 
499 static const unsigned char md5_hmac_test_sum[7][16] =
500 {
501  { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
502  0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D },
503  { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
504  0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 },
505  { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
506  0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 },
507  { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
508  0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 },
509  { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
510  0xF9, 0xBA, 0xB9, 0x95 },
511  { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
512  0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD },
513  { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
514  0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E }
515 };
516 
517 /*
518  * Checkup routine
519  */
520 int md5_self_test( int verbose )
521 {
522  int i, buflen;
523  unsigned char buf[1024];
524  unsigned char md5sum[16];
525  md5_context ctx;
526 
527  for( i = 0; i < 7; i++ )
528  {
529  if( verbose != 0 )
530  printf( " MD5 test #%d: ", i + 1 );
531 
532  md5( md5_test_buf[i], md5_test_buflen[i], md5sum );
533 
534  if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
535  {
536  if( verbose != 0 )
537  printf( "failed\n" );
538 
539  return( 1 );
540  }
541 
542  if( verbose != 0 )
543  printf( "passed\n" );
544  }
545 
546  if( verbose != 0 )
547  printf( "\n" );
548 
549  for( i = 0; i < 7; i++ )
550  {
551  if( verbose != 0 )
552  printf( " HMAC-MD5 test #%d: ", i + 1 );
553 
554  if( i == 5 || i == 6 )
555  {
556  memset( buf, '\xAA', buflen = 80 );
557  md5_hmac_starts( &ctx, buf, buflen );
558  }
559  else
560  md5_hmac_starts( &ctx, md5_hmac_test_key[i],
561  md5_hmac_test_keylen[i] );
562 
563  md5_hmac_update( &ctx, md5_hmac_test_buf[i],
564  md5_hmac_test_buflen[i] );
565 
566  md5_hmac_finish( &ctx, md5sum );
567 
568  buflen = ( i == 4 ) ? 12 : 16;
569 
570  if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 )
571  {
572  if( verbose != 0 )
573  printf( "failed\n" );
574 
575  return( 1 );
576  }
577 
578  if( verbose != 0 )
579  printf( "passed\n" );
580  }
581 
582  if( verbose != 0 )
583  printf( "\n" );
584 
585  return( 0 );
586 }
587 
588 #endif
589 
590 #endif