首页 > 技术知识 > 正文

@TOC

概述

大家都知道摘要算法在安全领域,也是一个特别重要的存在,而SHA224是其中比较常见的一种摘要算法,它的特点就是计算复杂度较低,不等长的数据原文输入,可以得出等长的摘要值,这个值是固定为28字节。正是由于这种特殊性,很多重要的数据完整性校验领域,都可以看到SHA24的影子,不过相对于SHA1/SHA256,SHA224还是用得相对少很多。

今天给大家带来SHA224的C源码版本实现,欢迎大家深入学习和讨论。

头文件定义

头文件定义如下,主要定义了SHA224的上下文结构体,以及导出的三个API:

复制#ifndef __SHA224_H__ #define __SHA224_H__ #include #define SHA224_DIGEST_LEN 28 // SHA224 outputs a 28 byte digest typedef struct _sha224_ctx_t { uint32_t total[2]; /*!< The number of Bytes processed. */ uint32_t state[8]; /*!< The intermediate digest state. */ uint8_t buffer[64]; /*!< The data block being processed. */ int32_t is_224; /*!< Determines which function to use: 0: Use SHA-256, or 1: Use SHA-224. */ } sha224_ctx_t; void crypto_sha224_init(sha224_ctx_t *ctx); void crypto_sha224_update(sha224_ctx_t *ctx, const uint8_t *data, uint32_t len); void crypto_sha224_final(sha224_ctx_t *ctx, uint8_t *digest); #endif // __SHA224_H__ C语言版本的实现源码

下面是SHA224的C语言版本实现,主要也是围绕导出的3个API:

复制#include #include #include “sha224.h” #define CONFIG_SHA256_SMALLER 1 /* * 32-bit int32_teger manipulation macros (big endian) */ #ifndef GET_UINT32_BE #define GET_UINT32_BE(n,b,i) do { (n) = ( (uint32_t) (b)[(i) ] << 24 ) | ( (uint32_t) (b)[(i) + 1] << 16 ) | ( (uint32_t) (b)[(i) + 2] << 8 ) | ( (uint32_t) (b)[(i) + 3] ); } while( 0 ) #endif #ifndef PUT_UINT32_BE #define PUT_UINT32_BE(n,b,i) do { (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) ); } while( 0 ) #endif static const uint32_t K[] = { 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, }; #define SHR(x,n) (((x) & 0xFFFFFFFF) >> (n)) #define ROTR(x,n) (SHR(x,n) | ((x) << (32 – (n)))) #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) #define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) #define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define R(t) ( local.W[t] = S1(local.W[(t) – 2]) + local.W[(t) – 7] + S0(local.W[(t) – 15]) + local.W[(t) – 16] ) #define P(a,b,c,d,e,f,g,h,x,K) do { local.temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); local.temp2 = S2(a) + F0((a),(b),(c)); (d) += local.temp1; (h) = local.temp1 + local.temp2; } while( 0 ) /* * SHA-224/256 context setup */ void crypto_sha224_sha256_init( sha224_ctx_t *ctx, int32_t is_224 ) { ctx->total[0] = 0; ctx->total[1] = 0; if( is_224 == 0 ) { /* SHA-256 */ ctx->state[0] = 0x6A09E667; ctx->state[1] = 0xBB67AE85; ctx->state[2] = 0x3C6EF372; ctx->state[3] = 0xA54FF53A; ctx->state[4] = 0x510E527F; ctx->state[5] = 0x9B05688C; ctx->state[6] = 0x1F83D9AB; ctx->state[7] = 0x5BE0CD19; } else { /* SHA-224 */ ctx->state[0] = 0xC1059ED8; ctx->state[1] = 0x367CD507; ctx->state[2] = 0x3070DD17; ctx->state[3] = 0xF70E5939; ctx->state[4] = 0xFFC00B31; ctx->state[5] = 0x68581511; ctx->state[6] = 0x64F98FA7; ctx->state[7] = 0xBEFA4FA4; } ctx->is_224 = is_224; } void crypto_sha224_init( sha224_ctx_t *ctx ) { memset( ctx, 0, sizeof( sha224_ctx_t ) ); crypto_sha224_sha256_init(ctx, 1); } static int32_t local_sha224_process( sha224_ctx_t *ctx, const uint8_t data[64] ) { struct { uint32_t temp1, temp2, W[64]; uint32_t A[8]; } local; uint32_t i; for( i = 0; i < 8; i++ ) { local.A[i] = ctx->state[i]; } #if defined(CONFIG_SHA256_SMALLER) for( i = 0; i < 64; i++ ) { if( i < 16 ) { GET_UINT32_BE( local.W[i], data, 4 * i ); } else { R( i ); } P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.W[i], K[i] ); local.temp1 = local.A[7]; local.A[7] = local.A[6]; local.A[6] = local.A[5]; local.A[5] = local.A[4]; local.A[4] = local.A[3]; local.A[3] = local.A[2]; local.A[2] = local.A[1]; local.A[1] = local.A[0]; local.A[0] = local.temp1; } #else /* CONFIG_SHA256_SMALLER */ for( i = 0; i < 16; i++ ) { GET_UINT32_BE( local.W[i], data, 4 * i ); } for( i = 0; i < 16; i += 8 ) { P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0] ); P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1] ); P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2] ); P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3] ); P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4] ); P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5] ); P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6] ); P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7] ); } for( i = 16; i < 64; i += 8 ) { P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], R(i+0), K[i+0] ); P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], R(i+1), K[i+1] ); P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], R(i+2), K[i+2] ); P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], local.A[4], R(i+3), K[i+3] ); P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], local.A[3], R(i+4), K[i+4] ); P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], local.A[2], R(i+5), K[i+5] ); P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], local.A[1], R(i+6), K[i+6] ); P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5], local.A[6], local.A[7], local.A[0], R(i+7), K[i+7] ); } #endif /* CONFIG_SHA256_SMALLER */ for( i = 0; i < 8; i++ ) { ctx->state[i] += local.A[i]; } return( 0 ); } /* * SHA-224 process buffer */ void crypto_sha224_update( sha224_ctx_t *ctx, const uint8_t *data, uint32_t ilen ) { int32_t ret = -1; uint32_t fill; uint32_t left; 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), data, fill ); if( ( ret = local_sha224_process( ctx, ctx->buffer ) ) != 0 ) { /* error */ return; } data += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { if( ( ret = local_sha224_process( ctx, data ) ) != 0 ) { /* error */ return; } data += 64; ilen -= 64; } if( ilen > 0 ) { memcpy( (void *) (ctx->buffer + left), data, ilen ); } } /* * SHA-224 final digest */ void crypto_sha224_final( sha224_ctx_t *ctx, uint8_t *digest ) { int32_t ret = -1; uint32_t used; uint32_t high, low; /* * Add padding: 0x80 then 0x00 until 8 bytes remain for the length */ used = ctx->total[0] & 0x3F; ctx->buffer[used++] = 0x80; if( used <= 56 ) { /* Enough room for padding + length in current block */ memset( ctx->buffer + used, 0, 56 – used ); } else { /* Well need an extra block */ memset( ctx->buffer + used, 0, 64 – used ); if( ( ret = local_sha224_process( ctx, ctx->buffer ) ) != 0 ) { /* error */ return; } memset( ctx->buffer, 0, 56 ); } /* * Add message length */ high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_UINT32_BE( high, ctx->buffer, 56 ); PUT_UINT32_BE( low, ctx->buffer, 60 ); if( ( ret = local_sha224_process( ctx, ctx->buffer ) ) != 0 ) { /* error */ return; } /* * Output final state */ 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 ); PUT_UINT32_BE( ctx->state[5], digest, 20 ); PUT_UINT32_BE( ctx->state[6], digest, 24 ); if( ctx->is_224 == 0 ) { PUT_UINT32_BE( ctx->state[7], digest, 28 ); } } 测试用例

针对SHA224导出的三个接口,我编写了以下测试用例:

复制#include #include #include “sha224.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): “, title, len); printf(“%s “, dimm); printf(“| Offset : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF | “); printf(“%s “, 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] = ; printf(“%s | “, str); } printf(“%s “, dimm); return 0; } int main(int argc, const char *argv[]) { const char *data = “C1D0F8FB4958670DBA40AB1F3752EF0D”; const char *digest_exp_str = “0AC2C8BF595E3CA47BBFEFEAD8B2E6489536EDCF2C0D49A5BC290058”; uint8_t digest_calc[SHA224_DIGEST_LEN]; uint8_t digest_exp_hex[SHA224_DIGEST_LEN]; sha224_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 “, data_str); if (!strcmp(data, data_str)) { printf(“hex string – bytes convert OK “); } else { printf(“hex string – bytes convert FAIL “); } crypto_sha224_init(&ctx); crypto_sha224_update(&ctx, (uint8_t *)p_calc, strlen(p_calc)); crypto_sha224_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(“SHA224 digest test OK “); 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(“SHA224 digest test FAIL “); } return 0; }

测试用例比较简单,就是对字符串C1D0F8FB4958670DBA40AB1F3752EF0D进行SHA224运算,期望的摘要结果的hexstring是 0AC2C8BF595E3CA47BBFEFEAD8B2E6489536EDCF2C0D49A5BC290058 ,这个期望值是用算法工具算出来的。

先用API接口算出摘要值,再与期望值比较,这里有个hexstringtobyte的转换,如果比较一致则表示API计算OK;反之,接口计算失败。

同时,也欢迎大家设计提供更多的测试案例代码。

github仓库

以上代码和测试用例,及编译运行等,可以参考我的github仓库,有详细的流程介绍,欢迎大家交流讨论。如果有帮助到你的话,记得帮忙点亮一颗星哦。

审核编辑:汤梓红

猜你喜欢