【安全算法之SHA1】SHA1摘要运算的C语言源码实现
【安全算法之SHA1】SHA1摘要運算的C語言源碼實現
- 概述
- 頭文件定義
- C語言版本的實現源碼
- 測試用例
- github倉庫
- 更多參考鏈接
概述
大家都知道摘要算法在安全領域,也是一個特別重要的存在,而SHA1是其中比較常見的一種摘要算法,它的特點就是計算復雜度較低,不等長的數據原文輸入,可以得出等長的摘要值,這個值是固定為20字節。正是由于這種特殊性,很多重要的數據完整性校驗領域,都可以看到SHA1的影子。
今天給大家帶來SHA1的C源碼版本實現,歡迎大家深入學習和討論。
頭文件定義
頭文件定義如下,主要定義了SHA1的上下文結構體,以及導出的三個API:
#ifndef __SHA1_H__ #define __SHA1_H__#include <stdint.h>#define SHA1_DIGEST_LEN 20 // SHA1 outputs a 20 byte digesttypedef struct _sha1_ctx_t {uint32_t total[2]; /*!< number of bytes processed */uint32_t state[5]; /*!< intermediate digest state */uint8_t buffer[64]; /*!< data block being processed */ } sha1_ctx_t;void crypto_sha1_init(sha1_ctx_t *ctx); void crypto_sha1_update(sha1_ctx_t *ctx, const uint8_t *data, uint32_t len); void crypto_sha1_final(sha1_ctx_t *ctx, uint8_t *digest);#endif // __SHA1_H__C語言版本的實現源碼
下面是SHA1的C語言版本實現,主要也是圍繞導出的3個API:
#include <string.h> #include "sha1.h"/** 32-bit integer manipulation macros (big endian)*/ #ifndef GET_UINT32_BE #define GET_UINT32_BE(n, b, i) \{ \(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \} #endif#ifndef PUT_UINT32_BE #define PUT_UINT32_BE(n, b, i) \{ \(b)[(i)] = (uint8_t)((n) >> 24); \(b)[(i) + 1] = (uint8_t)((n) >> 16); \(b)[(i) + 2] = (uint8_t)((n) >> 8); \(b)[(i) + 3] = (uint8_t)((n)); \} #endifstatic const uint8_t sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };static void local_sha1_process(sha1_ctx_t *ctx,const uint8_t data[64]) {uint32_t temp, W[16], A, B, C, D, E;GET_UINT32_BE(W[0], data, 0);GET_UINT32_BE(W[1], data, 4);GET_UINT32_BE(W[2], data, 8);GET_UINT32_BE(W[3], data, 12);GET_UINT32_BE(W[4], data, 16);GET_UINT32_BE(W[5], data, 20);GET_UINT32_BE(W[6], data, 24);GET_UINT32_BE(W[7], data, 28);GET_UINT32_BE(W[8], data, 32);GET_UINT32_BE(W[9], data, 36);GET_UINT32_BE(W[10], data, 40);GET_UINT32_BE(W[11], data, 44);GET_UINT32_BE(W[12], data, 48);GET_UINT32_BE(W[13], data, 52);GET_UINT32_BE(W[14], data, 56);GET_UINT32_BE(W[15], data, 60);#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))#define R(t) \(temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ \W[t & 0x0F], \(W[t & 0x0F] = S(temp, 1)))#define P(a, b, c, d, e, x) \{ \e += S(a, 5) + F(b, c, d) + K + x; \b = S(b, 30); \}A = ctx->state[0];B = ctx->state[1];C = ctx->state[2];D = ctx->state[3];E = ctx->state[4];#define F(x, y, z) (z ^ (x & (y ^ z))) #define K 0x5A827999P(A, B, C, D, E, W[0]);P(E, A, B, C, D, W[1]);P(D, E, A, B, C, W[2]);P(C, D, E, A, B, W[3]);P(B, C, D, E, A, W[4]);P(A, B, C, D, E, W[5]);P(E, A, B, C, D, W[6]);P(D, E, A, B, C, W[7]);P(C, D, E, A, B, W[8]);P(B, C, D, E, A, W[9]);P(A, B, C, D, E, W[10]);P(E, A, B, C, D, W[11]);P(D, E, A, B, C, W[12]);P(C, D, E, A, B, W[13]);P(B, C, D, E, A, W[14]);P(A, B, C, D, E, W[15]);P(E, A, B, C, D, R(16));P(D, E, A, B, C, R(17));P(C, D, E, A, B, R(18));P(B, C, D, E, A, R(19));#undef K #undef F#define F(x, y, z) (x ^ y ^ z) #define K 0x6ED9EBA1P(A, B, C, D, E, R(20));P(E, A, B, C, D, R(21));P(D, E, A, B, C, R(22));P(C, D, E, A, B, R(23));P(B, C, D, E, A, R(24));P(A, B, C, D, E, R(25));P(E, A, B, C, D, R(26));P(D, E, A, B, C, R(27));P(C, D, E, A, B, R(28));P(B, C, D, E, A, R(29));P(A, B, C, D, E, R(30));P(E, A, B, C, D, R(31));P(D, E, A, B, C, R(32));P(C, D, E, A, B, R(33));P(B, C, D, E, A, R(34));P(A, B, C, D, E, R(35));P(E, A, B, C, D, R(36));P(D, E, A, B, C, R(37));P(C, D, E, A, B, R(38));P(B, C, D, E, A, R(39));#undef K #undef F#define F(x, y, z) ((x & y) | (z & (x | y))) #define K 0x8F1BBCDCP(A, B, C, D, E, R(40));P(E, A, B, C, D, R(41));P(D, E, A, B, C, R(42));P(C, D, E, A, B, R(43));P(B, C, D, E, A, R(44));P(A, B, C, D, E, R(45));P(E, A, B, C, D, R(46));P(D, E, A, B, C, R(47));P(C, D, E, A, B, R(48));P(B, C, D, E, A, R(49));P(A, B, C, D, E, R(50));P(E, A, B, C, D, R(51));P(D, E, A, B, C, R(52));P(C, D, E, A, B, R(53));P(B, C, D, E, A, R(54));P(A, B, C, D, E, R(55));P(E, A, B, C, D, R(56));P(D, E, A, B, C, R(57));P(C, D, E, A, B, R(58));P(B, C, D, E, A, R(59));#undef K #undef F#define F(x, y, z) (x ^ y ^ z) #define K 0xCA62C1D6P(A, B, C, D, E, R(60));P(E, A, B, C, D, R(61));P(D, E, A, B, C, R(62));P(C, D, E, A, B, R(63));P(B, C, D, E, A, R(64));P(A, B, C, D, E, R(65));P(E, A, B, C, D, R(66));P(D, E, A, B, C, R(67));P(C, D, E, A, B, R(68));P(B, C, D, E, A, R(69));P(A, B, C, D, E, R(70));P(E, A, B, C, D, R(71));P(D, E, A, B, C, R(72));P(C, D, E, A, B, R(73));P(B, C, D, E, A, R(74));P(A, B, C, D, E, R(75));P(E, A, B, C, D, R(76));P(D, E, A, B, C, R(77));P(C, D, E, A, B, R(78));P(B, C, D, E, A, R(79));#undef K #undef Fctx->state[0] += A;ctx->state[1] += B;ctx->state[2] += C;ctx->state[3] += D;ctx->state[4] += E; }/** SHA-1 process init*/ void crypto_sha1_init(sha1_ctx_t *ctx) {memset(ctx, 0, sizeof(sha1_ctx_t));ctx->total[0] = 0;ctx->total[1] = 0;ctx->state[0] = 0x67452301;ctx->state[1] = 0xEFCDAB89;ctx->state[2] = 0x98BADCFE;ctx->state[3] = 0x10325476;ctx->state[4] = 0xC3D2E1F0; }/** SHA-1 process buffer*/ void crypto_sha1_update(sha1_ctx_t *ctx, const uint8_t *input,uint32_t ilen) {uint32_t fill;uint32_t left;if (ilen == 0) {return;}left = ctx->total[0] & 0x3F;fill = 64 - left;ctx->total[0] += (uint32_t)ilen;ctx->total[0] &= 0xFFFFFFFF;if (ctx->total[0] < (uint32_t)ilen) {ctx->total[1]++;}if (left && ilen >= fill) {memcpy((void *)(ctx->buffer + left), input, fill);local_sha1_process(ctx, ctx->buffer);input += fill;ilen -= fill;left = 0;}while (ilen >= 64) {local_sha1_process(ctx, input);input += 64;ilen -= 64;}if (ilen > 0) {memcpy((void *)(ctx->buffer + left), input, ilen);} }/** SHA-1 final digest*/ void crypto_sha1_final(sha1_ctx_t *ctx, uint8_t *digest) {uint32_t last, padn;uint32_t high, low;uint8_t msglen[8];high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);low = (ctx->total[0] << 3);PUT_UINT32_BE(high, msglen, 0);PUT_UINT32_BE(low, msglen, 4);last = ctx->total[0] & 0x3F;padn = (last < 56) ? (56 - last) : (120 - last);crypto_sha1_update(ctx, sha1_padding, padn);crypto_sha1_update(ctx, msglen, 8);PUT_UINT32_BE(ctx->state[0], digest, 0);PUT_UINT32_BE(ctx->state[1], digest, 4);PUT_UINT32_BE(ctx->state[2], digest, 8);PUT_UINT32_BE(ctx->state[3], digest, 12);PUT_UINT32_BE(ctx->state[4], digest, 16); }測試用例
針對SHA1導出的三個接口,我編寫了以下測試用例:
#include <stdio.h> #include <string.h>#include "sha1.h" #include "convert.h"int log_hexdump(const char *title, const unsigned char *data, int len) {char str[160], octet[10];int ofs, i, k, d;const unsigned char *buf = (const unsigned char *)data;const char dimm[] = "+------------------------------------------------------------------------------+";printf("%s (%d bytes):\r\n", title, len);printf("%s\r\n", dimm);printf("| Offset : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF |\r\n");printf("%s\r\n", dimm);for (ofs = 0; ofs < (int)len; ofs += 16) {d = snprintf( str, sizeof(str), "| %08X: ", ofs );for (i = 0; i < 16; i++) {if ((i + ofs) < (int)len) {snprintf( octet, sizeof(octet), "%02X ", buf[ofs + i] );} else {snprintf( octet, sizeof(octet), " " );}d += snprintf( &str[d], sizeof(str) - d, "%s", octet );}d += snprintf( &str[d], sizeof(str) - d, " " );k = d;for (i = 0; i < 16; i++) {if ((i + ofs) < (int)len) {str[k++] = (0x20 <= (buf[ofs + i]) && (buf[ofs + i]) <= 0x7E) ? buf[ofs + i] : '.';} else {str[k++] = ' ';}}str[k] = '\0';printf("%s |\r\n", str);}printf("%s\r\n", dimm);return 0; }int main(int argc, const char *argv[]) {const char *data = "C1D0F8FB4958670DBA40AB1F3752EF0D";const char *digest_exp_str = "B36BFDB04A31F6C55E0D592B8F2D3219FBC2424D";uint8_t digest_calc[SHA1_DIGEST_LEN];uint8_t digest_exp_hex[SHA1_DIGEST_LEN];sha1_ctx_t ctx;const char *p_calc = data;uint8_t data_bytes[128];uint16_t len_bytes;char data_str[128];if (argc > 1) {p_calc = argv[1];}utils_hex_string_2_bytes(data, data_bytes, &len_bytes);log_hexdump("data_bytes", data_bytes, len_bytes);utils_bytes_2_hex_string(data_bytes, len_bytes, data_str);printf("data_str: %s\n", data_str);if (!strcmp(data, data_str)) {printf("hex string - bytes convert OK\n");} else {printf("hex string - bytes convert FAIL\n");}crypto_sha1_init(&ctx);crypto_sha1_update(&ctx, (uint8_t *)p_calc, strlen(p_calc));crypto_sha1_final(&ctx, digest_calc);utils_hex_string_2_bytes(digest_exp_str, digest_exp_hex, &len_bytes);if (len_bytes == sizeof(digest_calc) && !memcmp(digest_calc, digest_exp_hex, sizeof(digest_calc))) {printf("SHA1 digest test OK\n");log_hexdump("digest_calc", digest_calc, sizeof(digest_calc));} else {log_hexdump("digest_calc", digest_calc, sizeof(digest_calc));log_hexdump("digest_exp", digest_exp_hex, sizeof(digest_exp_hex));printf("SHA1 digest test FAIL\n");}return 0; }測試用例比較簡單,就是對字符串C1D0F8FB4958670DBA40AB1F3752EF0D進行SHA1運算,期望的摘要結果的hexstring是B36BFDB04A31F6C55E0D592B8F2D3219FBC2424D,這個期望值是用算法工具算出來的。
先用API接口算出摘要值,再與期望值比較,這里有個hexstringtobyte的轉換,如果比較一致則表示API計算OK;反之,接口計算失敗。
同時,也歡迎大家設計提供更多的測試案例代碼。
github倉庫
以上代碼和測試用例,及編譯運行等,可以參考我的github倉庫,有詳細的流程介紹,歡迎大家交流討論。如果有幫助到你的話,記得幫忙點亮一顆星哦。
更多參考鏈接
[1] 【安全算法的github倉庫】
[2] 【安全算法之概述】一文帶你簡要了解常見常用的安全算法
[3] 【安全算法之base64】base64加解密的C語言源碼實現
[4] 【安全算法之MD5】MD5摘要運算的C語言源碼實現
[5] 【安全算法之SHA1】SHA1摘要運算的C語言源碼實現
[6] 【安全算法之SHA224】SHA224摘要運算的C語言源碼實現
[7] 【安全算法之SHA256】SHA256摘要運算的C語言源碼實現
[8] 【安全算法之SHA384】SHA384摘要運算的C語言源碼實現
[9] 【安全算法之SHA512】SHA512摘要運算的C語言源碼實現
總結
以上是生活随笔為你收集整理的【安全算法之SHA1】SHA1摘要运算的C语言源码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA入门_继承与重载_饲养员喂养动物
- 下一篇: 移动端h5不支持font-family里