one-file-projects/sha1.c

118 lines
2.2 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
uint32_t h0;
uint32_t h1;
uint32_t h2;
uint32_t h3;
uint32_t h4;
} hash_t;
hash_t* sha1(const char* s, hash_t* h);
void printhash(hash_t* h);
void main(int argc, char** argv) {
hash_t h;
const char* str;
if(argc > 1) {
str = argv[1];
} else {
str = "test";
}
sha1(str,&h);
printhash(&h);
}
void printhash(hash_t* h) {
printf("%08x%08x%08x%08x%08x\n",
h->h0,
h->h1,
h->h2,
h->h3,
h->h4);
}
#define left_shift(n,X) (((X) << (n)) | ((X) >> (32-(n))))
void apply_round(const char* block, hash_t* state) {
uint32_t A,B,C,D,E;
uint32_t W[80];
uint32_t temp, K, f;
for(int i = 0; i < 16; i++) {
W[i] = (unsigned char)block[i*4] << 24;
W[i] |= (unsigned char)block[i*4+1] << 16;
W[i] |= (unsigned char)block[i*4+2] << 8;
W[i] |= (unsigned char)block[i*4+3];
}
for(int i = 16; i < 80; i++) {
W[i] = left_shift(1, W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]);
}
A = state->h0;
B = state->h1;
C = state->h2;
D = state->h3;
E = state->h4;
for(int i = 0; i < 80; i++) {
if(0 <= i && i <= 19) {
f = (B & C) | ( (~B) & D );
K = 0x5A827999;
} else if(20 <= i && i <= 39) {
f = B ^ C ^ D;
K = 0x6ED9EBA1;
} else if(40 <= i && i <= 59) {
f = (B & C) | (B & D) | (C & D);
K = 0x8F1BBCDC;
} else if(60 <= i && i <= 79) {
f = B ^ C ^ D;
K = 0xCA62C1D6;
}
temp = left_shift(5,A) + f + E + W[i] + K;
E = D; D = C; C = left_shift(30,B); B = A; A = temp;
}
state->h0 += A;
state->h1 += B;
state->h2 += C;
state->h3 += D;
state->h4 += E;
}
hash_t* sha1(const char* s, hash_t* H) {
H->h0 = 0x67452301;
H->h1 = 0xEFCDAB89;
H->h2 = 0x98BADCFE;
H->h3 = 0x10325476;
H->h4 = 0xC3D2E1F0;
size_t slen = strlen(s);
size_t bitlen = slen*8;
unsigned long long padlen = (slen + 64 - (slen%512));
if(padlen - slen < 8) padlen += 64;
char buf[padlen];
memset(buf, 0, sizeof(char) * padlen);
memcpy(buf, s, sizeof(char) * slen);
buf[slen] = 0x80;
for(int i = 0; i < 8; i++) {
buf[padlen-i-1] = (bitlen >> (8*i)) & 0xFF;
}
size_t numblocks = padlen / 64;
for(int i = 0; i < numblocks; i++) {
apply_round(&(buf[i*64]),H);
}
return H;
}