blob: 3229cd125fbbb1b6bb73b1b4ec68526b03f9f164 [file] [log] [blame]
Rob Landley28964802008-01-19 17:08:39 -06001/* vi: set sw=4 ts=4:
2 *
3 * sha1sum.c - Calculate sha1 cryptographic hash for input.
4 *
Rob Landleyce6750a2007-11-29 18:32:20 -06005 * Copyright 2007 Rob Landley <rob@landley.net>
6 *
Rob Landley0a22c5c2007-11-24 21:33:23 -06007 * Based on the public domain SHA-1 in C by Steve Reid <steve@edmweb.com>
8 * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/
Rob Landley64d2e822007-12-03 19:59:34 -06009 *
10 * Not in SUSv3.
Rob Landley28964802008-01-19 17:08:39 -060011
Rob Landley55928b12008-01-19 17:43:27 -060012USE_SHA1SUM(NEWTOY(sha1sum, NULL, TOYFLAG_USR|TOYFLAG_BIN))
13
Rob Landley28964802008-01-19 17:08:39 -060014config SHA1SUM
15 bool "sha1sum"
16 default y
17 help
18 usage: sha1sum [file...]
19
20 Calculate sha1 hash of files (or stdin).
21*/
Rob Landley509dd142007-11-24 21:25:18 -060022
Rob Landleyce6750a2007-11-29 18:32:20 -060023#include <toys.h>
Rob Landley509dd142007-11-24 21:25:18 -060024
Rob Landley0a22c5c2007-11-24 21:33:23 -060025struct sha1 {
26 uint32_t state[5];
Rob Landley57389ec2007-11-24 22:05:29 -060027 uint32_t oldstate[5];
Rob Landleyf1980822007-11-24 22:02:07 -060028 uint64_t count;
29 union {
30 unsigned char c[64];
31 uint32_t i[16];
32 } buffer;
Rob Landley0a22c5c2007-11-24 21:33:23 -060033};
Rob Landley509dd142007-11-24 21:25:18 -060034
Rob Landley64d2e822007-12-03 19:59:34 -060035static void sha1_init(struct sha1 *this);
36static void sha1_transform(struct sha1 *this);
37static void sha1_update(struct sha1 *this, char *data, unsigned int len);
38static void sha1_final(struct sha1 *this, char digest[20]);
Rob Landley509dd142007-11-24 21:25:18 -060039
40#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
41
Rob Landley64d2e822007-12-03 19:59:34 -060042// blk0() and blk() perform the initial expand.
43// The idea of expanding during the round function comes from SSLeay
Rob Landleyce6750a2007-11-29 18:32:20 -060044#if 1
Rob Landleyf1980822007-11-24 22:02:07 -060045#define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \
46 |(rol(block[i],8)&0x00FF00FF))
Rob Landleyce6750a2007-11-29 18:32:20 -060047#else // big endian?
Rob Landleyf1980822007-11-24 22:02:07 -060048#define blk0(i) block[i]
Rob Landley509dd142007-11-24 21:25:18 -060049#endif
Rob Landleyf1980822007-11-24 22:02:07 -060050#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
51 ^block[(i+2)&15]^block[i&15],1))
Rob Landley509dd142007-11-24 21:25:18 -060052
Rob Landley57389ec2007-11-24 22:05:29 -060053static const uint32_t rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
Rob Landley509dd142007-11-24 21:25:18 -060054
Rob Landley64d2e822007-12-03 19:59:34 -060055// Hash a single 512-bit block. This is the core of the algorithm.
Rob Landley509dd142007-11-24 21:25:18 -060056
Rob Landley64d2e822007-12-03 19:59:34 -060057static void sha1_transform(struct sha1 *this)
Rob Landley509dd142007-11-24 21:25:18 -060058{
Rob Landley57389ec2007-11-24 22:05:29 -060059 int i, j, k, count;
Rob Landleyf1980822007-11-24 22:02:07 -060060 uint32_t *block = this->buffer.i;
Rob Landley57389ec2007-11-24 22:05:29 -060061 uint32_t *rot[5], *temp;
Rob Landley0a22c5c2007-11-24 21:33:23 -060062
Rob Landley64d2e822007-12-03 19:59:34 -060063 // Copy context->state[] to working vars
Rob Landley57389ec2007-11-24 22:05:29 -060064 for (i=0; i<5; i++) {
65 this->oldstate[i] = this->state[i];
66 rot[i] = this->state + i;
67 }
Rob Landley64d2e822007-12-03 19:59:34 -060068 // 4 rounds of 20 operations each.
Rob Landley57389ec2007-11-24 22:05:29 -060069 for (i=count=0; i<4; i++) {
70 for (j=0; j<20; j++) {
71 uint32_t work;
72
73 work = *rot[2] ^ *rot[3];
74 if (!i) work = (work & *rot[1]) ^ *rot[3];
75 else {
76 if (i==2)
77 work = ((*rot[1]|*rot[2])&*rot[3])|(*rot[1]&*rot[2]);
78 else work ^= *rot[1];
79 }
80 if (!i && j<16) work += blk0(count);
81 else work += blk(count);
82 *rot[4] += work + rol(*rot[0],5) + rconsts[i];
83 *rot[1] = rol(*rot[1],30);
84
85 // Rotate by one for next time.
86 temp = rot[4];
87 for (k=4; k; k--) rot[k] = rot[k-1];
88 *rot = temp;
89 count++;
90 }
91 }
Rob Landley64d2e822007-12-03 19:59:34 -060092 // Add the previous values of state[]
Rob Landley57389ec2007-11-24 22:05:29 -060093 for (i=0; i<5; i++) this->state[i] += this->oldstate[i];
Rob Landley509dd142007-11-24 21:25:18 -060094}
95
96
Rob Landley64d2e822007-12-03 19:59:34 -060097// Initialize a struct sha1.
Rob Landley509dd142007-11-24 21:25:18 -060098
Rob Landley64d2e822007-12-03 19:59:34 -060099static void sha1_init(struct sha1 *this)
Rob Landley509dd142007-11-24 21:25:18 -0600100{
Rob Landleyb911de32007-11-24 21:26:56 -0600101 /* SHA1 initialization constants */
Rob Landley0a22c5c2007-11-24 21:33:23 -0600102 this->state[0] = 0x67452301;
103 this->state[1] = 0xEFCDAB89;
104 this->state[2] = 0x98BADCFE;
105 this->state[3] = 0x10325476;
106 this->state[4] = 0xC3D2E1F0;
Rob Landleyf1980822007-11-24 22:02:07 -0600107 this->count = 0;
Rob Landley509dd142007-11-24 21:25:18 -0600108}
109
Rob Landley64d2e822007-12-03 19:59:34 -0600110// Fill the 64-byte working buffer and call sha1_transform() when full.
Rob Landley509dd142007-11-24 21:25:18 -0600111
Rob Landleyce6750a2007-11-29 18:32:20 -0600112void sha1_update(struct sha1 *this, char *data, unsigned int len)
Rob Landley509dd142007-11-24 21:25:18 -0600113{
Rob Landley0a22c5c2007-11-24 21:33:23 -0600114 unsigned int i, j;
Rob Landley509dd142007-11-24 21:25:18 -0600115
Rob Landleyf1980822007-11-24 22:02:07 -0600116 j = this->count & 63;
117 this->count += len;
Rob Landley509dd142007-11-24 21:25:18 -0600118
Rob Landleyf1980822007-11-24 22:02:07 -0600119 // Enough data to process a frame?
120 if ((j + len) > 63) {
121 i = 64-j;
122 memcpy(this->buffer.c + j, data, i);
123 sha1_transform(this);
124 for ( ; i + 63 < len; i += 64) {
125 memcpy(this->buffer.c, data + i, 64);
126 sha1_transform(this);
127 }
128 j = 0;
129 } else i = 0;
130 // Grab remaining chunk
131 memcpy(this->buffer.c + j, data + i, len - i);
132}
Rob Landley509dd142007-11-24 21:25:18 -0600133
Rob Landley64d2e822007-12-03 19:59:34 -0600134// Add padding and return the message digest.
Rob Landley509dd142007-11-24 21:25:18 -0600135
Rob Landleyce6750a2007-11-29 18:32:20 -0600136void sha1_final(struct sha1 *this, char digest[20])
Rob Landley509dd142007-11-24 21:25:18 -0600137{
Rob Landleyf1980822007-11-24 22:02:07 -0600138 uint64_t count = this->count << 3;
139 unsigned int i;
Rob Landleyce6750a2007-11-29 18:32:20 -0600140 char buf;
Rob Landley509dd142007-11-24 21:25:18 -0600141
Rob Landleyf1980822007-11-24 22:02:07 -0600142 // End the message by appending a "1" bit to the data, ending with the
143 // message size (in bits, big endian), and adding enough zero bits in
Rob Landley64d2e822007-12-03 19:59:34 -0600144 // between to pad to the end of the next 64-byte frame.
145 //
146 // Since our input up to now has been in whole bytes, we can deal with
147 // bytes here too.
Rob Landleyf1980822007-11-24 22:02:07 -0600148
149 buf = 0x80;
150 do {
151 sha1_update(this, &buf, 1);
152 buf = 0;
153 } while ((this->count & 63) != 56);
154 for (i = 0; i < 8; i++)
155 this->buffer.c[56+i] = count >> (8*(7-i));
156 sha1_transform(this);
157
Rob Landleyce6750a2007-11-29 18:32:20 -0600158 for (i = 0; i < 20; i++)
159 digest[i] = this->state[i>>2] >> ((3-(i & 3)) * 8);
Rob Landley64d2e822007-12-03 19:59:34 -0600160 // Wipe variables. Cryptogropher paranoia.
Rob Landley57389ec2007-11-24 22:05:29 -0600161 memset(this, 0, sizeof(struct sha1));
Rob Landley509dd142007-11-24 21:25:18 -0600162}
163
Rob Landleyce6750a2007-11-29 18:32:20 -0600164// Callback for loopfiles()
Rob Landley509dd142007-11-24 21:25:18 -0600165
Rob Landleyce6750a2007-11-29 18:32:20 -0600166static void do_sha1(int fd, char *name)
Rob Landley509dd142007-11-24 21:25:18 -0600167{
Rob Landley0a22c5c2007-11-24 21:33:23 -0600168 struct sha1 this;
Rob Landleyce6750a2007-11-29 18:32:20 -0600169 int len;
Rob Landley509dd142007-11-24 21:25:18 -0600170
Rob Landley0a22c5c2007-11-24 21:33:23 -0600171 sha1_init(&this);
Rob Landleyce6750a2007-11-29 18:32:20 -0600172 for (;;) {
173 len = read(fd, toybuf, sizeof(toybuf));
174 if (len<1) break;
175 sha1_update(&this, toybuf, len);
Rob Landleyb911de32007-11-24 21:26:56 -0600176 }
Rob Landleyce6750a2007-11-29 18:32:20 -0600177 sha1_final(&this, toybuf);
178 for (len = 0; len < 20; len++) printf("%02x", toybuf[len]);
179 printf(" %s\n", name);
180}
181
182void sha1sum_main(void)
183{
184 loopfiles(toys.optargs, do_sha1);
Rob Landley509dd142007-11-24 21:25:18 -0600185}