fix no-ssl build
[exim.git] / src / src / pdkim / sha1.c
CommitLineData
80a47a2c
TK
1/*
2 * FIPS-180-1 compliant SHA-1 implementation
3 *
62d3e98d
TK
4 * Copyright (C) 2006-2010, 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>
80a47a2c 8 *
62d3e98d 9 * All rights reserved.
80a47a2c
TK
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 SHA-1 standard was published by NIST in 1993.
27 *
28 * http://www.itl.nist.gov/fipspubs/fip180-1.htm
29 */
30
ac3ad426
AM
31#include "polarssl/config.h"
32
33#if defined(POLARSSL_SHA1_C)
34
35#include "polarssl/sha1.h"
80a47a2c
TK
36
37#include <string.h>
38#include <stdio.h>
39
40/*
41 * 32-bit integer manipulation macros (big endian)
42 */
43#ifndef GET_ULONG_BE
44#define GET_ULONG_BE(n,b,i) \
45{ \
46 (n) = ( (unsigned long) (b)[(i) ] << 24 ) \
47 | ( (unsigned long) (b)[(i) + 1] << 16 ) \
48 | ( (unsigned long) (b)[(i) + 2] << 8 ) \
49 | ( (unsigned long) (b)[(i) + 3] ); \
50}
51#endif
52
53#ifndef PUT_ULONG_BE
54#define PUT_ULONG_BE(n,b,i) \
55{ \
56 (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
57 (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
58 (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
59 (b)[(i) + 3] = (unsigned char) ( (n) ); \
60}
61#endif
62
63/*
64 * SHA-1 context setup
65 */
66void sha1_starts( sha1_context *ctx )
67{
68 ctx->total[0] = 0;
69 ctx->total[1] = 0;
70
71 ctx->state[0] = 0x67452301;
72 ctx->state[1] = 0xEFCDAB89;
73 ctx->state[2] = 0x98BADCFE;
74 ctx->state[3] = 0x10325476;
75 ctx->state[4] = 0xC3D2E1F0;
76}
77
62d3e98d 78static void sha1_process( sha1_context *ctx, const unsigned char data[64] )
80a47a2c
TK
79{
80 unsigned long temp, W[16], A, B, C, D, E;
81
82 GET_ULONG_BE( W[ 0], data, 0 );
83 GET_ULONG_BE( W[ 1], data, 4 );
84 GET_ULONG_BE( W[ 2], data, 8 );
85 GET_ULONG_BE( W[ 3], data, 12 );
86 GET_ULONG_BE( W[ 4], data, 16 );
87 GET_ULONG_BE( W[ 5], data, 20 );
88 GET_ULONG_BE( W[ 6], data, 24 );
89 GET_ULONG_BE( W[ 7], data, 28 );
90 GET_ULONG_BE( W[ 8], data, 32 );
91 GET_ULONG_BE( W[ 9], data, 36 );
92 GET_ULONG_BE( W[10], data, 40 );
93 GET_ULONG_BE( W[11], data, 44 );
94 GET_ULONG_BE( W[12], data, 48 );
95 GET_ULONG_BE( W[13], data, 52 );
96 GET_ULONG_BE( W[14], data, 56 );
97 GET_ULONG_BE( W[15], data, 60 );
98
99#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
100
101#define R(t) \
102( \
103 temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
104 W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
105 ( W[t & 0x0F] = S(temp,1) ) \
106)
107
108#define P(a,b,c,d,e,x) \
109{ \
110 e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
111}
112
113 A = ctx->state[0];
114 B = ctx->state[1];
115 C = ctx->state[2];
116 D = ctx->state[3];
117 E = ctx->state[4];
118
119#define F(x,y,z) (z ^ (x & (y ^ z)))
120#define K 0x5A827999
121
122 P( A, B, C, D, E, W[0] );
123 P( E, A, B, C, D, W[1] );
124 P( D, E, A, B, C, W[2] );
125 P( C, D, E, A, B, W[3] );
126 P( B, C, D, E, A, W[4] );
127 P( A, B, C, D, E, W[5] );
128 P( E, A, B, C, D, W[6] );
129 P( D, E, A, B, C, W[7] );
130 P( C, D, E, A, B, W[8] );
131 P( B, C, D, E, A, W[9] );
132 P( A, B, C, D, E, W[10] );
133 P( E, A, B, C, D, W[11] );
134 P( D, E, A, B, C, W[12] );
135 P( C, D, E, A, B, W[13] );
136 P( B, C, D, E, A, W[14] );
137 P( A, B, C, D, E, W[15] );
138 P( E, A, B, C, D, R(16) );
139 P( D, E, A, B, C, R(17) );
140 P( C, D, E, A, B, R(18) );
141 P( B, C, D, E, A, R(19) );
142
143#undef K
144#undef F
145
146#define F(x,y,z) (x ^ y ^ z)
147#define K 0x6ED9EBA1
148
149 P( A, B, C, D, E, R(20) );
150 P( E, A, B, C, D, R(21) );
151 P( D, E, A, B, C, R(22) );
152 P( C, D, E, A, B, R(23) );
153 P( B, C, D, E, A, R(24) );
154 P( A, B, C, D, E, R(25) );
155 P( E, A, B, C, D, R(26) );
156 P( D, E, A, B, C, R(27) );
157 P( C, D, E, A, B, R(28) );
158 P( B, C, D, E, A, R(29) );
159 P( A, B, C, D, E, R(30) );
160 P( E, A, B, C, D, R(31) );
161 P( D, E, A, B, C, R(32) );
162 P( C, D, E, A, B, R(33) );
163 P( B, C, D, E, A, R(34) );
164 P( A, B, C, D, E, R(35) );
165 P( E, A, B, C, D, R(36) );
166 P( D, E, A, B, C, R(37) );
167 P( C, D, E, A, B, R(38) );
168 P( B, C, D, E, A, R(39) );
169
170#undef K
171#undef F
172
173#define F(x,y,z) ((x & y) | (z & (x | y)))
174#define K 0x8F1BBCDC
175
176 P( A, B, C, D, E, R(40) );
177 P( E, A, B, C, D, R(41) );
178 P( D, E, A, B, C, R(42) );
179 P( C, D, E, A, B, R(43) );
180 P( B, C, D, E, A, R(44) );
181 P( A, B, C, D, E, R(45) );
182 P( E, A, B, C, D, R(46) );
183 P( D, E, A, B, C, R(47) );
184 P( C, D, E, A, B, R(48) );
185 P( B, C, D, E, A, R(49) );
186 P( A, B, C, D, E, R(50) );
187 P( E, A, B, C, D, R(51) );
188 P( D, E, A, B, C, R(52) );
189 P( C, D, E, A, B, R(53) );
190 P( B, C, D, E, A, R(54) );
191 P( A, B, C, D, E, R(55) );
192 P( E, A, B, C, D, R(56) );
193 P( D, E, A, B, C, R(57) );
194 P( C, D, E, A, B, R(58) );
195 P( B, C, D, E, A, R(59) );
196
197#undef K
198#undef F
199
200#define F(x,y,z) (x ^ y ^ z)
201#define K 0xCA62C1D6
202
203 P( A, B, C, D, E, R(60) );
204 P( E, A, B, C, D, R(61) );
205 P( D, E, A, B, C, R(62) );
206 P( C, D, E, A, B, R(63) );
207 P( B, C, D, E, A, R(64) );
208 P( A, B, C, D, E, R(65) );
209 P( E, A, B, C, D, R(66) );
210 P( D, E, A, B, C, R(67) );
211 P( C, D, E, A, B, R(68) );
212 P( B, C, D, E, A, R(69) );
213 P( A, B, C, D, E, R(70) );
214 P( E, A, B, C, D, R(71) );
215 P( D, E, A, B, C, R(72) );
216 P( C, D, E, A, B, R(73) );
217 P( B, C, D, E, A, R(74) );
218 P( A, B, C, D, E, R(75) );
219 P( E, A, B, C, D, R(76) );
220 P( D, E, A, B, C, R(77) );
221 P( C, D, E, A, B, R(78) );
222 P( B, C, D, E, A, R(79) );
223
224#undef K
225#undef F
226
227 ctx->state[0] += A;
228 ctx->state[1] += B;
229 ctx->state[2] += C;
230 ctx->state[3] += D;
231 ctx->state[4] += E;
232}
233
234/*
235 * SHA-1 process buffer
236 */
62d3e98d 237void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen )
80a47a2c
TK
238{
239 int fill;
240 unsigned long left;
241
242 if( ilen <= 0 )
243 return;
244
245 left = ctx->total[0] & 0x3F;
246 fill = 64 - left;
247
248 ctx->total[0] += ilen;
249 ctx->total[0] &= 0xFFFFFFFF;
250
251 if( ctx->total[0] < (unsigned long) ilen )
252 ctx->total[1]++;
253
254 if( left && ilen >= fill )
255 {
256 memcpy( (void *) (ctx->buffer + left),
257 (void *) input, fill );
258 sha1_process( ctx, ctx->buffer );
259 input += fill;
260 ilen -= fill;
261 left = 0;
262 }
263
264 while( ilen >= 64 )
265 {
266 sha1_process( ctx, input );
267 input += 64;
268 ilen -= 64;
269 }
270
271 if( ilen > 0 )
272 {
273 memcpy( (void *) (ctx->buffer + left),
274 (void *) input, ilen );
275 }
276}
277
278static const unsigned char sha1_padding[64] =
279{
280 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
281 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
282 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
284};
285
286/*
287 * SHA-1 final digest
288 */
289void sha1_finish( sha1_context *ctx, unsigned char output[20] )
290{
291 unsigned long last, padn;
292 unsigned long high, low;
293 unsigned char msglen[8];
294
295 high = ( ctx->total[0] >> 29 )
296 | ( ctx->total[1] << 3 );
297 low = ( ctx->total[0] << 3 );
298
299 PUT_ULONG_BE( high, msglen, 0 );
300 PUT_ULONG_BE( low, msglen, 4 );
301
302 last = ctx->total[0] & 0x3F;
303 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
304
305 sha1_update( ctx, (unsigned char *) sha1_padding, padn );
306 sha1_update( ctx, msglen, 8 );
307
308 PUT_ULONG_BE( ctx->state[0], output, 0 );
309 PUT_ULONG_BE( ctx->state[1], output, 4 );
310 PUT_ULONG_BE( ctx->state[2], output, 8 );
311 PUT_ULONG_BE( ctx->state[3], output, 12 );
312 PUT_ULONG_BE( ctx->state[4], output, 16 );
313}
314
315/*
316 * output = SHA-1( input buffer )
317 */
0d04a285 318void polarssl_sha1( const unsigned char *input, int ilen, unsigned char output[20] )
80a47a2c
TK
319{
320 sha1_context ctx;
321
322 sha1_starts( &ctx );
323 sha1_update( &ctx, input, ilen );
324 sha1_finish( &ctx, output );
325
326 memset( &ctx, 0, sizeof( sha1_context ) );
327}
328
329/*
330 * output = SHA-1( file contents )
331 */
62d3e98d 332int sha1_file( const char *path, unsigned char output[20] )
80a47a2c
TK
333{
334 FILE *f;
335 size_t n;
336 sha1_context ctx;
337 unsigned char buf[1024];
338
339 if( ( f = fopen( path, "rb" ) ) == NULL )
340 return( 1 );
341
342 sha1_starts( &ctx );
343
344 while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
345 sha1_update( &ctx, buf, (int) n );
346
347 sha1_finish( &ctx, output );
348
349 memset( &ctx, 0, sizeof( sha1_context ) );
350
351 if( ferror( f ) != 0 )
352 {
353 fclose( f );
354 return( 2 );
355 }
356
357 fclose( f );
358 return( 0 );
359}
360
361/*
362 * SHA-1 HMAC context setup
363 */
62d3e98d 364void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, int keylen )
80a47a2c
TK
365{
366 int i;
367 unsigned char sum[20];
368
369 if( keylen > 64 )
370 {
0d04a285 371 polarssl_sha1( key, keylen, sum );
80a47a2c
TK
372 keylen = 20;
373 key = sum;
374 }
375
376 memset( ctx->ipad, 0x36, 64 );
377 memset( ctx->opad, 0x5C, 64 );
378
379 for( i = 0; i < keylen; i++ )
380 {
381 ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
382 ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
383 }
384
385 sha1_starts( ctx );
386 sha1_update( ctx, ctx->ipad, 64 );
387
388 memset( sum, 0, sizeof( sum ) );
389}
390
391/*
392 * SHA-1 HMAC process buffer
393 */
62d3e98d 394void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, int ilen )
80a47a2c
TK
395{
396 sha1_update( ctx, input, ilen );
397}
398
399/*
400 * SHA-1 HMAC final digest
401 */
402void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
403{
404 unsigned char tmpbuf[20];
405
406 sha1_finish( ctx, tmpbuf );
407 sha1_starts( ctx );
408 sha1_update( ctx, ctx->opad, 64 );
409 sha1_update( ctx, tmpbuf, 20 );
410 sha1_finish( ctx, output );
411
412 memset( tmpbuf, 0, sizeof( tmpbuf ) );
413}
414
62d3e98d
TK
415/*
416 * SHA1 HMAC context reset
417 */
418void sha1_hmac_reset( sha1_context *ctx )
419{
420 sha1_starts( ctx );
421 sha1_update( ctx, ctx->ipad, 64 );
422}
423
80a47a2c
TK
424/*
425 * output = HMAC-SHA-1( hmac key, input buffer )
426 */
62d3e98d
TK
427void sha1_hmac( const unsigned char *key, int keylen,
428 const unsigned char *input, int ilen,
80a47a2c
TK
429 unsigned char output[20] )
430{
431 sha1_context ctx;
432
433 sha1_hmac_starts( &ctx, key, keylen );
434 sha1_hmac_update( &ctx, input, ilen );
435 sha1_hmac_finish( &ctx, output );
436
437 memset( &ctx, 0, sizeof( sha1_context ) );
438}
ac3ad426
AM
439
440#if defined(POLARSSL_SELF_TEST)
441/*
442 * FIPS-180-1 test vectors
443 */
444static unsigned char sha1_test_buf[3][57] =
445{
446 { "abc" },
447 { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
448 { "" }
449};
450
451static const int sha1_test_buflen[3] =
452{
453 3, 56, 1000
454};
455
456static const unsigned char sha1_test_sum[3][20] =
457{
458 { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
459 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
460 { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
461 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
462 { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
463 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
464};
465
466/*
467 * RFC 2202 test vectors
468 */
469static unsigned char sha1_hmac_test_key[7][26] =
470{
471 { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
472 "\x0B\x0B\x0B\x0B" },
473 { "Jefe" },
474 { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
475 "\xAA\xAA\xAA\xAA" },
476 { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
477 "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
478 { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
479 "\x0C\x0C\x0C\x0C" },
480 { "" }, /* 0xAA 80 times */
481 { "" }
482};
483
484static const int sha1_hmac_test_keylen[7] =
485{
486 20, 4, 20, 25, 20, 80, 80
487};
488
489static unsigned char sha1_hmac_test_buf[7][74] =
490{
491 { "Hi There" },
492 { "what do ya want for nothing?" },
493 { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
494 "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
495 "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
496 "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
497 "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
498 { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
499 "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
500 "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
501 "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
502 "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
503 { "Test With Truncation" },
504 { "Test Using Larger Than Block-Size Key - Hash Key First" },
505 { "Test Using Larger Than Block-Size Key and Larger"
506 " Than One Block-Size Data" }
507};
508
509static const int sha1_hmac_test_buflen[7] =
510{
511 8, 28, 50, 50, 20, 54, 73
512};
513
514static const unsigned char sha1_hmac_test_sum[7][20] =
515{
516 { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
517 0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
518 { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
519 0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
520 { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
521 0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
522 { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
523 0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
524 { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
525 0x7B, 0xE1 },
526 { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
527 0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
528 { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
529 0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
530};
531
532/*
533 * Checkup routine
534 */
535int sha1_self_test( int verbose )
536{
537 int i, j, buflen;
538 unsigned char buf[1024];
539 unsigned char sha1sum[20];
540 sha1_context ctx;
541
542 /*
543 * SHA-1
544 */
545 for( i = 0; i < 3; i++ )
546 {
547 if( verbose != 0 )
548 printf( " SHA-1 test #%d: ", i + 1 );
549
550 sha1_starts( &ctx );
551
552 if( i == 2 )
553 {
554 memset( buf, 'a', buflen = 1000 );
555
556 for( j = 0; j < 1000; j++ )
557 sha1_update( &ctx, buf, buflen );
558 }
559 else
560 sha1_update( &ctx, sha1_test_buf[i],
561 sha1_test_buflen[i] );
562
563 sha1_finish( &ctx, sha1sum );
564
565 if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
566 {
567 if( verbose != 0 )
568 printf( "failed\n" );
569
570 return( 1 );
571 }
572
573 if( verbose != 0 )
574 printf( "passed\n" );
575 }
576
577 if( verbose != 0 )
578 printf( "\n" );
579
580 for( i = 0; i < 7; i++ )
581 {
582 if( verbose != 0 )
583 printf( " HMAC-SHA-1 test #%d: ", i + 1 );
584
585 if( i == 5 || i == 6 )
586 {
587 memset( buf, '\xAA', buflen = 80 );
588 sha1_hmac_starts( &ctx, buf, buflen );
589 }
590 else
591 sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
592 sha1_hmac_test_keylen[i] );
593
594 sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
595 sha1_hmac_test_buflen[i] );
596
597 sha1_hmac_finish( &ctx, sha1sum );
598
599 buflen = ( i == 4 ) ? 12 : 20;
600
601 if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
602 {
603 if( verbose != 0 )
604 printf( "failed\n" );
605
606 return( 1 );
607 }
608
609 if( verbose != 0 )
610 printf( "passed\n" );
611 }
612
613 if( verbose != 0 )
614 printf( "\n" );
615
616 return( 0 );
617}
618
619#endif
620
621#endif