grimoire/c/sha1.c

138 lines
2.7 KiB
C

#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static uint64_t pad_length(uint64_t len) {
uint64_t space_needed = 1;
while(((len + space_needed) % 64) != 56) {
space_needed += 1;
}
return space_needed;
}
static uint32_t rotate(uint8_t bits, uint32_t word) {
return (word << bits) | (word >> (32 - bits));
}
unsigned char *sha1(const char *msg, uint64_t len) {
uint64_t ml = len * CHAR_BIT;
uint64_t needed = pad_length(len);
unsigned char *buf = malloc(len + needed + 8);
if(buf == NULL) {
return NULL;
}
strncpy((char *) buf, msg, len);
buf[len++] = 0x80;
for(; needed > 1; --needed) {
buf[len++] = 0x00;
}
uint8_t count = 8;
while(count--) {
buf[len++] = (ml & ((uint64_t) 0xFF << 56)) >> 56;
ml = ml << 8;
}
uint32_t h[] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0
};
uint64_t chunk = 0;
for(; chunk < len; chunk += 64) {
uint32_t w[80] = { 0 };
uint8_t i = 0;
for(; i < 16; i++) {
w[i] = buf[chunk + (i * 4)] << 24;
w[i] |= buf[chunk + (i * 4 + 1)] << 16;
w[i] |= buf[chunk + (i * 4 + 2)] << 8;
w[i] |= buf[chunk + (i * 4 + 3)];
}
for(i = 16; i < 80; ++i) {
w[i] = rotate(1, w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);
}
uint32_t a = h[0];
uint32_t b = h[1];
uint32_t c = h[2];
uint32_t d = h[3];
uint32_t e = h[4];
for(i = 0; i < 80; ++i) {
uint32_t f = 0;
uint32_t k = 0;
if(i >= 0 && i <= 19) {
f = (b & c) | ((~b) & d);
k = (uint32_t) 0x5A827999;
} else if(i >= 20 && i <= 39) {
f = b ^ c ^ d;
k = (uint32_t) 0x6ED9EBA1;
} else if(i >= 40 && i <= 59) {
f = (b & c) | (b & d) | (c & d);
k = (uint32_t) 0x8F1BBCDC;
} else if(i >= 60 && i <= 79) {
f = b ^ c ^ d;
k = (uint32_t) 0xCA62C1D6;
}
uint32_t temp = rotate(5, a) + f + e + k + w[i];
e = d;
d = c;
c = rotate(30, b);
b = a;
a = temp;
}
h[0] += a;
h[1] += b;
h[2] += c;
h[3] += d;
h[4] += e;
}
unsigned char *hh = malloc(20);
if(hh == NULL) {
return NULL;
}
for(count = 0; count < 5; count++) {
hh[count * 4] = h[count] >> 24;
hh[(count * 4) + 1] = (h[count] >> 16) & 0xFF;
hh[(count * 4) + 2] = (h[count] >> 8) & 0xFF;
hh[(count * 4) + 3] = h[count] & 0xFF;
}
return hh;
}
int main(int argc, char **argv) {
for(++argv; argc > 1; ++argv, --argc) {
unsigned char *hash = sha1(*argv, strlen(*argv));
uint8_t count = 0;
for(; count < 20; ++count) {
printf("%02X", (unsigned) hash[count]);
}
printf("\n");
}
return 0;
}