blob: 1148aac19a1c7587cd41629b581172bac0a72b09 [file] [log] [blame]
Glenn L McGrathae0f1e72003-02-17 08:23:22 +00001/*
2 * Based on shasum from http://www.netsw.org/crypto/hash/
Eric Andersen61f6db12003-07-03 09:41:41 +00003 * Majorly hacked up to use Dr Brian Gladman's sha1 code
Glenn L McGrathae0f1e72003-02-17 08:23:22 +00004 *
5 * Copyright (C) 1999 Scott G. Miller
6 * Copyright (C) 2003 Glenn L. McGrath
Eric Andersen61f6db12003-07-03 09:41:41 +00007 * Copyright (C) 2003 Erik Andersen
Glenn L McGrathae0f1e72003-02-17 08:23:22 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#include <stdio.h>
25#include <getopt.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
Eric Andersen61f6db12003-07-03 09:41:41 +000029#include <limits.h>
30#include <stdint.h>
Glenn L McGrath008c0192003-02-17 12:18:16 +000031#include <endian.h>
Eric Andersen61f6db12003-07-03 09:41:41 +000032#include <byteswap.h>
Glenn L McGrathae0f1e72003-02-17 08:23:22 +000033#include "busybox.h"
34
Eric Andersen61f6db12003-07-03 09:41:41 +000035
36/*
37 ---------------------------------------------------------------------------
38 Begin Dr. Gladman's sha1 code
39 ---------------------------------------------------------------------------
40*/
41
42/*
43 ---------------------------------------------------------------------------
44 Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
45 All rights reserved.
46
47 LICENSE TERMS
48
49 The free distribution and use of this software in both source and binary
50 form is allowed (with or without changes) provided that:
51
52 1. distributions of this source code include the above copyright
53 notice, this list of conditions and the following disclaimer;
54
55 2. distributions in binary form include the above copyright
56 notice, this list of conditions and the following disclaimer
57 in the documentation and/or other associated materials;
58
59 3. the copyright holder's name is not used to endorse products
60 built using this software without specific written permission.
61
62 ALTERNATIVELY, provided that this notice is retained in full, this product
63 may be distributed under the terms of the GNU General Public License (GPL),
64 in which case the provisions of the GPL apply INSTEAD OF those given above.
65
66 DISCLAIMER
67
68 This software is provided 'as is' with no explicit or implied warranties
69 in respect of its properties, including, but not limited to, correctness
70 and/or fitness for purpose.
71 ---------------------------------------------------------------------------
72 Issue Date: 10/11/2002
73
74 This is a byte oriented version of SHA1 that operates on arrays of bytes
75 stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor
76*/
77
78#define SHA1_BLOCK_SIZE 64
79#define SHA1_DIGEST_SIZE 20
80#define SHA1_HASH_SIZE SHA1_DIGEST_SIZE
81#define SHA2_GOOD 0
82#define SHA2_BAD 1
83
84/* type to hold the SHA1 context */
85typedef struct
86{ uint32_t count[2];
87 uint32_t hash[5];
88 uint32_t wbuf[16];
89} sha1_ctx;
90
91#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
92
Glenn L McGrath008c0192003-02-17 12:18:16 +000093#if __BYTE_ORDER == __BIG_ENDIAN
Eric Andersen61f6db12003-07-03 09:41:41 +000094# define swap_b32(x) (x)
95#elif defined(bswap_32)
96# define swap_b32(x) bswap_32(x)
Glenn L McGrathae0f1e72003-02-17 08:23:22 +000097#else
Eric Andersen61f6db12003-07-03 09:41:41 +000098# define swap_b32(x) ((rotl32((x), 8) & 0x00ff00ff) | (rotl32((x), 24) & 0xff00ff00))
Glenn L McGrathae0f1e72003-02-17 08:23:22 +000099#endif
100
Eric Andersen61f6db12003-07-03 09:41:41 +0000101#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000102
Eric Andersen61f6db12003-07-03 09:41:41 +0000103/* reverse byte order in 32-bit words */
104#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
105#define parity(x,y,z) ((x) ^ (y) ^ (z))
106#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000107
Eric Andersen61f6db12003-07-03 09:41:41 +0000108/* A normal version as set out in the FIPS. This version uses */
109/* partial loop unrolling and is optimised for the Pentium 4 */
110#define rnd(f,k) \
111 t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \
112 e = d; d = c; c = rotl32(b, 30); b = t
113
114void sha1_compile(sha1_ctx ctx[1])
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000115{
Eric Andersen61f6db12003-07-03 09:41:41 +0000116 uint32_t w[80], i, a, b, c, d, e, t;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000117
Eric Andersen61f6db12003-07-03 09:41:41 +0000118 /* note that words are compiled from the buffer into 32-bit */
119 /* words in big-endian order so an order reversal is needed */
120 /* here on little endian machines */
121 for(i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
122 w[i] = swap_b32(ctx->wbuf[i]);
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000123
Eric Andersen61f6db12003-07-03 09:41:41 +0000124 for(i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
125 w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000126
Eric Andersen61f6db12003-07-03 09:41:41 +0000127 a = ctx->hash[0];
128 b = ctx->hash[1];
129 c = ctx->hash[2];
130 d = ctx->hash[3];
131 e = ctx->hash[4];
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000132
Eric Andersen61f6db12003-07-03 09:41:41 +0000133 for(i = 0; i < 20; ++i)
134 {
135 rnd(ch, 0x5a827999);
136 }
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000137
Eric Andersen61f6db12003-07-03 09:41:41 +0000138 for(i = 20; i < 40; ++i)
139 {
140 rnd(parity, 0x6ed9eba1);
141 }
142
143 for(i = 40; i < 60; ++i)
144 {
145 rnd(maj, 0x8f1bbcdc);
146 }
147
148 for(i = 60; i < 80; ++i)
149 {
150 rnd(parity, 0xca62c1d6);
151 }
152
153 ctx->hash[0] += a;
154 ctx->hash[1] += b;
155 ctx->hash[2] += c;
156 ctx->hash[3] += d;
157 ctx->hash[4] += e;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000158}
159
Eric Andersen61f6db12003-07-03 09:41:41 +0000160void sha1_begin(sha1_ctx ctx[1])
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000161{
Eric Andersen61f6db12003-07-03 09:41:41 +0000162 ctx->count[0] = ctx->count[1] = 0;
163 ctx->hash[0] = 0x67452301;
164 ctx->hash[1] = 0xefcdab89;
165 ctx->hash[2] = 0x98badcfe;
166 ctx->hash[3] = 0x10325476;
167 ctx->hash[4] = 0xc3d2e1f0;
168}
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000169
Eric Andersen61f6db12003-07-03 09:41:41 +0000170/* SHA1 hash data in an array of bytes into hash buffer and call the */
171/* hash_compile function as required. */
172void sha1_hash(const unsigned char data[], unsigned int len, sha1_ctx ctx[1])
173{
174 uint32_t pos = (uint32_t)(ctx->count[0] & SHA1_MASK),
175 freeb = SHA1_BLOCK_SIZE - pos;
176 const unsigned char *sp = data;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000177
Eric Andersen61f6db12003-07-03 09:41:41 +0000178 if((ctx->count[0] += len) < len)
179 ++(ctx->count[1]);
180
181 while(len >= freeb) /* tranfer whole blocks while possible */
182 {
183 memcpy(((unsigned char*)ctx->wbuf) + pos, sp, freeb);
184 sp += freeb; len -= freeb; freeb = SHA1_BLOCK_SIZE; pos = 0;
185 sha1_compile(ctx);
186 }
187
188 memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
189}
190
191/* SHA1 Final padding and digest calculation */
192#if __BYTE_ORDER == __LITTLE_ENDIAN
193static uint32_t mask[4] =
194 { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
195static uint32_t bits[4] =
196 { 0x00000080, 0x00008000, 0x00800000, 0x80000000 };
197#else
198static uint32_t mask[4] =
199 { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
200static uint32_t bits[4] =
201 { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
202#endif
203
204void sha1_end(unsigned char hval[], sha1_ctx ctx[1])
205{
206 uint32_t i, cnt = (uint32_t)(ctx->count[0] & SHA1_MASK);
207
208 /* mask out the rest of any partial 32-bit word and then set */
209 /* the next byte to 0x80. On big-endian machines any bytes in */
210 /* the buffer will be at the top end of 32 bit words, on little */
211 /* endian machines they will be at the bottom. Hence the AND */
212 /* and OR masks above are reversed for little endian systems */
213 ctx->wbuf[cnt >> 2] = (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3];
214
215 /* we need 9 or more empty positions, one for the padding byte */
216 /* (above) and eight for the length count. If there is not */
217 /* enough space pad and empty the buffer */
218 if(cnt > SHA1_BLOCK_SIZE - 9)
219 {
220 if(cnt < 60) ctx->wbuf[15] = 0;
221 sha1_compile(ctx);
222 cnt = 0;
223 }
224 else /* compute a word index for the empty buffer positions */
225 cnt = (cnt >> 2) + 1;
226
227 while(cnt < 14) /* and zero pad all but last two positions */
228 ctx->wbuf[cnt++] = 0;
229
230 /* assemble the eight byte counter in the buffer in big-endian */
231 /* format */
232
233 ctx->wbuf[14] = swap_b32((ctx->count[1] << 3) | (ctx->count[0] >> 29));
234 ctx->wbuf[15] = swap_b32(ctx->count[0] << 3);
235
236 sha1_compile(ctx);
237
238 /* extract the hash value as bytes in case the hash buffer is */
239 /* misaligned for 32-bit words */
240
241 for(i = 0; i < SHA1_DIGEST_SIZE; ++i)
242 hval[i] = (unsigned char)(ctx->hash[i >> 2] >> 8 * (~i & 3));
243}
244
245#if 0
246void sha1(unsigned char hval[], const unsigned char data[], unsigned int len)
247{ sha1_ctx cx[1];
248
249 sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx);
250}
251#endif
252
253/*
254 ---------------------------------------------------------------------------
255 End of Dr. Gladman's sha1 code
256 ---------------------------------------------------------------------------
257*/
258
259/* Using a larger blocksize can make things _much_ faster
260 * by avoiding a zillion tiny little reads */
261#define BLOCKSIZE 65536
262/* Ensure that BLOCKSIZE is a multiple of 64. */
263#if BLOCKSIZE % SHA1_BLOCK_SIZE != 0
264# error "BLOCKSIZE not a multiple of 64"
265#endif
266
267static int sha1sum_stream(FILE *stream, unsigned char *hashval)
268{
269 int result = 0;
270 sha1_ctx cx[1];
271 size_t sum, n;
272 RESERVE_CONFIG_BUFFER(buffer, BLOCKSIZE + 72);
273
274 /* Initialize the computation context. */
275 sha1_begin(cx);
276
277 /* Iterate over full file contents. */
278 while (1)
279 {
280 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
281 computation function processes the whole buffer so that with the
282 next round of the loop another block can be read. */
283 sum = 0;
284
285 /* Read block. Take care for partial reads. */
286 while (1)
287 {
288 n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
289 sum += n;
290
291 if (sum == BLOCKSIZE)
292 break;
293
294 if (n == 0) {
295 /* Check for the error flag IFF N == 0, so that we don't
296 exit the loop after a partial read due to e.g., EAGAIN
297 or EWOULDBLOCK. */
298 if (feof (stream)) {
299 sum = 0;
300 goto process_partial_block;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000301 }
Eric Andersen61f6db12003-07-03 09:41:41 +0000302 if (ferror (stream)) {
303 result++;
304 goto all_done;
305 }
306 goto process_partial_block;
307 }
308
309 /* We've read at least one byte, so ignore errors. But always
310 check for EOF, since feof may be true even though N > 0.
311 Otherwise, we could end up calling fread after EOF. */
312 if (feof (stream))
313 goto process_partial_block;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000314 }
315
Eric Andersen61f6db12003-07-03 09:41:41 +0000316 /* Process buffer */
317 sha1_hash(buffer, BLOCKSIZE, cx);
318 }
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000319
Eric Andersen61f6db12003-07-03 09:41:41 +0000320process_partial_block:
321
322 /* Process any remaining bytes. */
323 if (sum > 0)
324 sha1_hash(buffer, sum, cx);
325
326 /* Finalize and write the hash into our buffer. */
327 sha1_end(hashval, cx);
328
329all_done:
330
331 RELEASE_CONFIG_BUFFER(buffer);
332 return result;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000333}
334
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000335#define FLAG_SILENT 1
336#define FLAG_CHECK 2
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000337#define FLAG_WARN 4
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000338
Eric Andersen61f6db12003-07-03 09:41:41 +0000339static unsigned char *hash_bin_to_hex(unsigned char *hash_value, unsigned char hash_length)
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000340{
Eric Andersen61f6db12003-07-03 09:41:41 +0000341 int x, len, max;
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000342 unsigned char *hex_value;
343
Eric Andersen61f6db12003-07-03 09:41:41 +0000344 max = (hash_length * 2) + 2;
345 hex_value = xmalloc(max);
346 for (x = len = 0; x < hash_length; x++) {
347 len += snprintf(hex_value+len, max-len, "%02x", hash_value[x]);
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000348 }
349 return(hex_value);
350}
351
352FILE *wfopen_file_or_stdin(const char *file_ptr)
353{
354 FILE *stream;
355
356 if ((file_ptr[0] == '-') && (file_ptr[1] == '\0')) {
357 stream = stdin;
358 } else {
359 stream = bb_wfopen(file_ptr, "r");
360 }
361
362 return(stream);
363}
364
365/* This could become a common function for md5 as well, by using md5_stream */
Eric Andersen61f6db12003-07-03 09:41:41 +0000366extern int authenticate(int argc, char **argv,
367 int (*hash_ptr)(FILE *stream, unsigned char *hashval),
368 const unsigned char hash_length)
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000369{
Eric Andersen61f6db12003-07-03 09:41:41 +0000370 unsigned char hash_value[hash_length];
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000371 unsigned int flags;
372 int return_value = EXIT_SUCCESS;
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000373
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000374#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
375 flags = bb_getopt_ulflags(argc, argv, "scw");
376#else
377 flags = bb_getopt_ulflags(argc, argv, "s");
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000378#endif
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000379
380#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
381 if (!(flags & FLAG_CHECK)) {
382 if (flags & FLAG_SILENT) {
383 bb_error_msg_and_die("the -s option is meaningful only when verifying checksums");
384 }
385 else if (flags & FLAG_WARN) {
386 bb_error_msg_and_die("the -w option is meaningful only when verifying checksums");
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000387 }
388 }
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000389#endif
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000390
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000391 if (argc == optind) {
Glenn L McGratha9e46172003-06-07 17:11:00 +0000392 argv[argc++] = "-";
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000393 }
394
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000395#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
396 if (flags & FLAG_CHECK) {
397 FILE *pre_computed_stream;
398 int count_total = 0;
399 int count_failed = 0;
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000400 unsigned char *file_ptr = argv[optind];
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000401
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000402 if (optind + 1 != argc) {
403 bb_error_msg_and_die("only one argument may be specified when using -c");
404 }
405 pre_computed_stream = wfopen_file_or_stdin(file_ptr);
406 while (!feof(pre_computed_stream) && !ferror(pre_computed_stream)) {
407 FILE *stream;
408 char *line;
409 char *line_ptr;
410 char *hex_value;
Glenn L McGratha7212042003-06-07 17:38:33 +0000411
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000412 line = bb_get_chomped_line_from_file(pre_computed_stream);
413 if (line == NULL) {
414 break;
415 }
416 count_total++;
417 line_ptr = strchr(line, ' ');
418 if (line_ptr == NULL) {
419 if (flags & FLAG_WARN) {
420 bb_error_msg("Invalid format");
421 }
422 free(line);
423 continue;
424 }
425 *line_ptr = '\0';
426 line_ptr++;
427 if ((flags & FLAG_WARN) && (*line_ptr != ' ')) {
428 bb_error_msg("Invalid format");
429 free(line);
430 continue;
431 }
432 line_ptr++;
433 stream = bb_wfopen(line_ptr, "r");
434 if (hash_ptr(stream, hash_value) == EXIT_FAILURE) {
Eric Andersen61f6db12003-07-03 09:41:41 +0000435 bb_perror_msg("%s", file_ptr);
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000436 return_value = EXIT_FAILURE;
437 }
438 if (fclose(stream) == EOF) {
439 bb_perror_msg("Couldnt close file %s", file_ptr);
440 }
441 hex_value = hash_bin_to_hex(hash_value, hash_length);
442 printf("%s: ", line_ptr);
443 if (strcmp(hex_value, line) != 0) {
444 puts("FAILED");
445 count_failed++;
446 } else {
447 puts("ok");
448 }
449 free(line);
450 }
451 if (count_failed) {
452 bb_error_msg("WARNING: %d of %d computed checksum did NOT match", count_failed, count_total);
453 }
454 if (bb_fclose_nonstdin(pre_computed_stream) == EOF) {
455 bb_perror_msg_and_die("Couldnt close file %s", file_ptr);
456 }
457 } else
458#endif
459 while (optind < argc) {
460 FILE *stream;
461 unsigned char *file_ptr = argv[optind];
462
463 optind++;
464
465 stream = wfopen_file_or_stdin(file_ptr);
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000466 if (stream == NULL) {
Glenn L McGratha7212042003-06-07 17:38:33 +0000467 return_value = EXIT_FAILURE;
468 continue;
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000469 }
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000470 if (hash_ptr(stream, hash_value) == EXIT_FAILURE) {
Eric Andersen61f6db12003-07-03 09:41:41 +0000471 bb_perror_msg("%s", file_ptr);
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000472 return_value = EXIT_FAILURE;
473 }
474 else if (!flags & FLAG_SILENT) {
475 char *hex_value = hash_bin_to_hex(hash_value, hash_length);
476 printf("%s %s\n", hex_value, file_ptr);
477 free(hex_value);
478 }
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000479
Glenn L McGrath6c43f742003-06-08 13:32:12 +0000480 if (bb_fclose_nonstdin(stream) == EOF) {
481 bb_perror_msg("Couldnt close file %s", file_ptr);
482 return_value = EXIT_FAILURE;
483 }
Glenn L McGrath138d71b2003-06-07 17:06:28 +0000484 }
485
Glenn L McGratha7212042003-06-07 17:38:33 +0000486 return(return_value);
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000487}
488
489extern int sha1sum_main(int argc, char **argv)
490{
Eric Andersen61f6db12003-07-03 09:41:41 +0000491 return (authenticate(argc, argv, sha1sum_stream, SHA1_HASH_SIZE));
Glenn L McGrathae0f1e72003-02-17 08:23:22 +0000492}