d94cb4b533fcae5ef128af211bb0a0ec89c3ba3d
[oweals/busybox.git] / coreutils / sha1sum.c
1 /*
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 #include <endian.h>
33 #include "busybox.h"
34
35 #if __BYTE_ORDER == __BIG_ENDIAN
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
50 static 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
115 static 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
156 static 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  */
174 extern 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                         bb_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 = bb_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
220 extern int sha1sum_main(int argc, char **argv)
221 {
222         /* sha1 length is 5 nibbles */
223         return (authenticate(argc, argv, sha1sum_stream, 5));
224 }