blob: d79a88ec1c2707053bcc98308e1c3997cade3219 [file] [log] [blame]
Glenn L McGrathae0f1e72003-02-17 08:23:22 +00001/*
2 * Based on shasum from http://www.netsw.org/crypto/hash/
3 *
4 * shasum fixed with reference to coreutils and the nist fip180-1 document
5 * which is incorrect, in section 5
6 * - ft(B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19)
7 * + ft(B,C,D) = (D XOR (B AND (C XOR S))) ( 0 <= t <= 19)
8 *
9 * Copyright (C) 1999 Scott G. Miller
10 * Copyright (C) 2003 Glenn L. McGrath
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27#include <stdio.h>
28#include <getopt.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include "busybox.h"
34
35#ifdef WORDS_BIGENDIAN
36# define SWAP(n) (n)
37#else
38# define SWAP(n) \
39 (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
40#endif
41
42#define f1(X,Y,Z) (Z ^ (X & (Y ^ Z)))
43#define f2(X,Y,Z) (X ^ Y ^ Z)
44#define f3(X,Y,Z) ((X & Y) | (Z & (X | Y)))
45
46#define rol1(x) (x<<1) | ((x>>31) & 1)
47#define rol5(x) ((x<<5) | ((x>>27) & 0x1f))
48#define rol30(x) (x<<30) | ((x>>2) & 0x3fffffff)
49
50static void sha_hash(unsigned int *data, int *hash)
51{
52 RESERVE_CONFIG_BUFFER(word, 80 * sizeof(unsigned int));
53 int *W = (unsigned int *) &word;
54 int a = hash[0];
55 int b = hash[1];
56 int c = hash[2];
57 int d = hash[3];
58 int e = hash[4];
59 int t;
60 int TEMP;
61
62 for (t = 0; t < 16; t++) {
63 W[t] = SWAP(data[t]);
64 }
65
66 /** Data expansion from 16 to 80 blocks **/
67 for (t = 16; t < 80; t++) {
68 int x = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
69 W[t] = rol1(x);
70 }
71
72 /** Main loops **/
73 for (t = 0; t < 20; t++) {
74 TEMP = rol5(a) + f1(b, c, d) + e + W[t] + 0x5a827999;
75 e = d;
76 d = c;
77 c = rol30(b);
78 b = a;
79 a = TEMP;
80 }
81 for (; t < 40; t++) {
82 TEMP = rol5(a) + f2(b, c, d) + e + W[t] + 0x6ed9eba1;
83 e = d;
84 d = c;
85 c = rol30(b);
86 b = a;
87 a = TEMP;
88 }
89 for (; t < 60; t++) {
90 TEMP = rol5(a) + f3(b, c, d) + e + W[t] + 0x8f1bbcdc;
91 e = d;
92 d = c;
93 c = rol30(b);
94 b = a;
95 a = TEMP;
96 }
97 for (; t < 80; t++) {
98 TEMP = rol5(a) + f2(b, c, d) + e + W[t] + 0xca62c1d6;
99 e = d;
100 d = c;
101 c = rol30(b);
102 b = a;
103 a = TEMP;
104 }
105
106 RELEASE_CONFIG_BUFFER(word);
107
108 hash[0] += a;
109 hash[1] += b;
110 hash[2] += c;
111 hash[3] += d;
112 hash[4] += e;
113}
114
115static void sha1sum_stream(FILE * fd, unsigned int *hashval)
116{
117 RESERVE_CONFIG_BUFFER(buffer, 64);
118 int length = 0;
119
120 hashval[0] = 0x67452301;
121 hashval[1] = 0xefcdab89;
122 hashval[2] = 0x98badcfe;
123 hashval[3] = 0x10325476;
124 hashval[4] = 0xc3d2e1f0;
125
126 while (!feof(fd) && !ferror(fd)) {
127 int c = fread(&buffer, 1, 64, fd);
128 length += c;
129 if (feof(fd) || ferror(fd)) {
130 int i;
131 /* If reading from stdin we need to get rid of a tailing character */
132 if (fd == stdin) {
133 c--;
134 length--;
135 }
136 for (i = c; i < 61; i++) {
137 if (i == c) {
138 buffer[i] = 0x80;
139 }
140 else if (i == 60) {
141 /* This ends up being swaped twice */
142 ((unsigned int *) &buffer)[15] = SWAP(length * 8);
143 } else {
144 buffer[i] = 0;
145 }
146 }
147 }
148 sha_hash((unsigned int *) &buffer, hashval);
149 }
150
151 RELEASE_CONFIG_BUFFER(buffer);
152
153 return;
154}
155
156static void print_hash(unsigned short hash_length, unsigned int *hash_val, char *filename)
157{
158 int x;
159
160 for (x = 0; x < hash_length; x++) {
161 printf("%08x", hash_val[x]);
162 }
163 if (filename != NULL) {
164 putchar(' ');
165 putchar(' ');
166 puts(filename);
167 }
168 putchar('\n');
169}
170
171/* This should become a common function used by sha1sum and md5sum,
172 * it needs extra functionality first
173 */
174extern int authenticate(const int argc, char **argv, void (*hash_ptr)(FILE *stream, unsigned int *hashval), const unsigned short hash_length)
175{
176 int opt;
177 unsigned int *hashval;
178
179 while ((opt = getopt(argc, argv, "sc:w")) != -1) {
180 switch (opt) {
181#if 0
182 case 's': /* Dont output anything, status code shows success */
183 break;
184 case 'c': /* Check a list of checksums against stored values */
185 break;
186 case 'w': /* Warn of bad formatting when checking files */
187 break;
188#endif
189 default:
190 show_usage();
191 }
192 }
193
194 hashval = xmalloc(hash_length * sizeof(unsigned int));
195
196 if (argc == optind) {
197 hash_ptr(stdin, hashval);
198 print_hash(hash_length, hashval, NULL);
199 } else {
200 int i;
201
202 for (i = optind; i < argc; i++) {
203 if (!strcmp(argv[i], "-")) {
204 hash_ptr(stdin, hashval);
205 print_hash(hash_length, hashval, NULL);
206 } else {
207 FILE *stream = xfopen(argv[i], "r");
208 hash_ptr(stream, hashval);
209 fclose(stream);
210 print_hash(hash_length, hashval, argv[i]);
211 }
212 }
213 }
214
215 free(hashval);
216
217 return 0;
218}
219
220extern int sha1sum_main(int argc, char **argv)
221{
222 /* sha1 length is 5 nibbles */
223 return (authenticate(argc, argv, sha1sum_stream, 5));
224}