我常常需要使用某种摘要算法,但是C语言没有自带的SHA1摘要算法。最近发现Redis里面就有sha1.h和sha1.c,我就稍微调整了一下代码格式就拿来用了。以后直接复制粘贴即可。
sha1.h
#ifndef SHA1_H #define SHA1_H #include <stdint.h> #include <stdlib.h> struct sha1_context { uint32_t state[5]; uint32_t count[2]; uint8_t buffer[64]; }; void sha1_init(struct sha1_context* context); void sha1_update(struct sha1_context* context, const uint8_t* data, size_t len); void sha1_final(struct sha1_context* context, uint8_t digest[20]); #endif
sha1.c
#include "sha1.h" #include <string.h> #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) #if BYTE_ORDER == LITTLE_ENDIAN #define blk0(i) (block[i] = (rol(block[i], 24) & 0xFF00FF00) | (rol(block[i], 8) & 0x00FF00FF)) #elif BYTE_ORDER == BIG_ENDIAN #define blk0(i) block[i] #else #error "Endianness not defined!" #endif #define blk(i) (block[i & 15] = rol(block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i & 15], 1)) #define R0(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); #define R1(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); #define R2(v, w, x, y, z, i) z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); #define R3(v, w, x, y, z, i) z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); #define R4(v, w, x, y, z, i) z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); w=rol(w, 30); static void sha1_transform(uint32_t state[5], const uint8_t buffer[64]) { uint32_t block[16]; memcpy(block, buffer, 64); uint32_t a = state[0]; uint32_t b = state[1]; uint32_t c = state[2]; uint32_t d = state[3]; uint32_t e = state[4]; R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } void sha1_init(struct sha1_context* context) { context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = 0; context->count[1] = 0; } void sha1_update(struct sha1_context* context, const uint8_t* data, size_t len) { uint32_t j = context->count[0]; if((context->count[0] += len << 3) < j) context->count[1]++; context->count[1] += (len >> 29); j = (j >> 3) & 63; uint32_t i; if((j + len) > 63) { i = 64 - j; memcpy(&context->buffer[j], data, i); sha1_transform(context->state, context->buffer); for(; i + 63 < len; i += 64) sha1_transform(context->state, data + i); j = 0; } else i = 0; memcpy(context->buffer + j, data + i, len - i); } void sha1_final(struct sha1_context* context, uint8_t digest[20]) { uint8_t finalcount[8]; for(int i = 0; i < 8; i++) finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); uint8_t c = 0200; sha1_update(context, &c, 1); while((context->count[0] & 504) != 448) { c = 0000; sha1_update(context, &c, 1); } sha1_update(context, finalcount, 8); for(int i = 0; i < 20; i++) digest[i] = (uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); }
使用方法非常简单:
#include "sha1.h" #include <stdio.h> #include <string.h> int main() { char* data = "hello,world!"; uint8_t digest[20]; struct sha1_context sha1; sha1_init(&sha1); sha1_update(&sha1, data, strlen(data)); sha1_final(&sha1, digest); for(int i = 0; i < 20; i++) printf("%02x", digest[i]); printf("\n"); return 0; }
得到"hello,world!"的SHA1摘要结果是4518135c05e0706c0a34168996517bb3f28d94b5。