Rob Landley | 2896480 | 2008-01-19 17:08:39 -0600 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: |
| 2 | * |
| 3 | * sha1sum.c - Calculate sha1 cryptographic hash for input. |
| 4 | * |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 5 | * Copyright 2007 Rob Landley <rob@landley.net> |
| 6 | * |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 7 | * 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 Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 9 | * |
| 10 | * Not in SUSv3. |
Rob Landley | 2896480 | 2008-01-19 17:08:39 -0600 | [diff] [blame] | 11 | |
Rob Landley | 55928b1 | 2008-01-19 17:43:27 -0600 | [diff] [blame] | 12 | USE_SHA1SUM(NEWTOY(sha1sum, NULL, TOYFLAG_USR|TOYFLAG_BIN)) |
| 13 | |
Rob Landley | 2896480 | 2008-01-19 17:08:39 -0600 | [diff] [blame] | 14 | config SHA1SUM |
| 15 | bool "sha1sum" |
| 16 | default y |
| 17 | help |
| 18 | usage: sha1sum [file...] |
| 19 | |
| 20 | Calculate sha1 hash of files (or stdin). |
| 21 | */ |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 22 | |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 23 | #include <toys.h> |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 24 | |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 25 | struct sha1 { |
| 26 | uint32_t state[5]; |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 27 | uint32_t oldstate[5]; |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 28 | uint64_t count; |
| 29 | union { |
| 30 | unsigned char c[64]; |
| 31 | uint32_t i[16]; |
| 32 | } buffer; |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 33 | }; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 34 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 35 | static void sha1_init(struct sha1 *this); |
| 36 | static void sha1_transform(struct sha1 *this); |
| 37 | static void sha1_update(struct sha1 *this, char *data, unsigned int len); |
| 38 | static void sha1_final(struct sha1 *this, char digest[20]); |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 39 | |
| 40 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) |
| 41 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 42 | // blk0() and blk() perform the initial expand. |
| 43 | // The idea of expanding during the round function comes from SSLeay |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 44 | #if 1 |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 45 | #define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \ |
| 46 | |(rol(block[i],8)&0x00FF00FF)) |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 47 | #else // big endian? |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 48 | #define blk0(i) block[i] |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 49 | #endif |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 50 | #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 Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 52 | |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 53 | static const uint32_t rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6}; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 54 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 55 | // Hash a single 512-bit block. This is the core of the algorithm. |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 56 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 57 | static void sha1_transform(struct sha1 *this) |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 58 | { |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 59 | int i, j, k, count; |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 60 | uint32_t *block = this->buffer.i; |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 61 | uint32_t *rot[5], *temp; |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 62 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 63 | // Copy context->state[] to working vars |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 64 | for (i=0; i<5; i++) { |
| 65 | this->oldstate[i] = this->state[i]; |
| 66 | rot[i] = this->state + i; |
| 67 | } |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 68 | // 4 rounds of 20 operations each. |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 69 | 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 Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 92 | // Add the previous values of state[] |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 93 | for (i=0; i<5; i++) this->state[i] += this->oldstate[i]; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 97 | // Initialize a struct sha1. |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 98 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 99 | static void sha1_init(struct sha1 *this) |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 100 | { |
Rob Landley | b911de3 | 2007-11-24 21:26:56 -0600 | [diff] [blame] | 101 | /* SHA1 initialization constants */ |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 102 | 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 Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 107 | this->count = 0; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 108 | } |
| 109 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 110 | // Fill the 64-byte working buffer and call sha1_transform() when full. |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 111 | |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 112 | void sha1_update(struct sha1 *this, char *data, unsigned int len) |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 113 | { |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 114 | unsigned int i, j; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 115 | |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 116 | j = this->count & 63; |
| 117 | this->count += len; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 118 | |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 119 | // 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 Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 133 | |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 134 | // Add padding and return the message digest. |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 135 | |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 136 | void sha1_final(struct sha1 *this, char digest[20]) |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 137 | { |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 138 | uint64_t count = this->count << 3; |
| 139 | unsigned int i; |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 140 | char buf; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 141 | |
Rob Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 142 | // 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 Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 144 | // 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 Landley | f198082 | 2007-11-24 22:02:07 -0600 | [diff] [blame] | 148 | |
| 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 Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 158 | for (i = 0; i < 20; i++) |
| 159 | digest[i] = this->state[i>>2] >> ((3-(i & 3)) * 8); |
Rob Landley | 64d2e82 | 2007-12-03 19:59:34 -0600 | [diff] [blame] | 160 | // Wipe variables. Cryptogropher paranoia. |
Rob Landley | 57389ec | 2007-11-24 22:05:29 -0600 | [diff] [blame] | 161 | memset(this, 0, sizeof(struct sha1)); |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 162 | } |
| 163 | |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 164 | // Callback for loopfiles() |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 165 | |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 166 | static void do_sha1(int fd, char *name) |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 167 | { |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 168 | struct sha1 this; |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 169 | int len; |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 170 | |
Rob Landley | 0a22c5c | 2007-11-24 21:33:23 -0600 | [diff] [blame] | 171 | sha1_init(&this); |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 172 | for (;;) { |
| 173 | len = read(fd, toybuf, sizeof(toybuf)); |
| 174 | if (len<1) break; |
| 175 | sha1_update(&this, toybuf, len); |
Rob Landley | b911de3 | 2007-11-24 21:26:56 -0600 | [diff] [blame] | 176 | } |
Rob Landley | ce6750a | 2007-11-29 18:32:20 -0600 | [diff] [blame] | 177 | sha1_final(&this, toybuf); |
| 178 | for (len = 0; len < 20; len++) printf("%02x", toybuf[len]); |
| 179 | printf(" %s\n", name); |
| 180 | } |
| 181 | |
| 182 | void sha1sum_main(void) |
| 183 | { |
| 184 | loopfiles(toys.optargs, do_sha1); |
Rob Landley | 509dd14 | 2007-11-24 21:25:18 -0600 | [diff] [blame] | 185 | } |