-
2021-05-24 03:30:17
依据国密SM3散列算法的标准文档,很容易写出其消息扩展函数的C语言实现:
#include
void expand_data(uint32_t W[68], uint32_t data[16])
{
uint32_tj, P1, X;
for(j = 0; j < 16; j++) W[j] = data[j];
for(j = 16; j < 68; j++) {
X = W[j-16] ^ W[j-9] ^ ((W[j-3]<<15) | (W[j-3]>>17));
P1 = X ^ ((X<<15)|(X>>17)) ^((X<<23)|(X>>9));
W[j] = ((W[j-13]<<7)|(W[j-13]>>25)) ^ W[j-6] ^ P1;
}
}
然而经过GCC编译成汇编语言之后,更接近下面的C语言实现
#include
void expand_data(uint32_t W[68], uint32_t data[16])
{
uint32_tj, X;
for(j = 0; j < 16; j++) W[j] = data[j];
for(j = 0; j < 52; j++) {
X = W[j] ^ W[j+7] ^ ((W[j+13]<<15) | (W[j+13]>>17));
W[j+16] = ((W[j+3]<<7)|(W[j+3]>>25)) ^ W[j+10] ^ X ^ ((X<<15)|(X>>17)) ^((X<<23)|(X>>9));
}
}
上述两份C语言代码编译之后得到的汇编代码是完全相同的:
.file"expand_data.c"
.text
.p2align 4,,15
.globl expand_data
.typeexpand_data, @function
expand_data:
.LFB0:
.cfi_startproc
xorl%eax, %eax#j = 0
.p2align 4,,10
.p2align 3
.L2:
movl(%rsi,%rax), %edx#edx = data[j]
movl%edx, (%rdi,%rax)#W[j] = edx
addq$4, %rax#j++
cmpq$64, %rax#(j == 16)
jne.L2#if (!=) goto .L2
xorl%edx, %edx#j = 0
.p2align 4,,10
.p2align 3
.L3:
movl28(%rdi,%rdx), %ecx#ecx = W[j+7]
movl52(%rdi,%rdx), %eax#eax = W[j+13]
xorl(%rdi,%rdx), %ecx#ecx ^ W[j+0]
rorl$17, %eax#eax = W[j+13]>>>17
xorl%eax, %ecx#ecx ^ W[j+13]>>>17
movl12(%rdi,%rdx), %eax#eax = W[j+3]
movl%ecx, %esi#esi = X
rorl$17, %esi#esi = X>>>17
rorl$25, %eax#eax = W[j+3]>>>25
xorl40(%rdi,%rdx), %eax#eax ^ W[j+10]
xorl%ecx, %eax#eax ^ X
rorl$9, %ecx#ecx = X>>>9
xorl%esi, %eax#eax ^ X>>>17
xorl%ecx, %eax#eax ^ X>>>9
movl%eax, 64(%rdi,%rdx)#W[j+16] = eax
addq$4, %rdx#j++
cmpq$208, %rdx#(j == 52)
jne.L3#if (!=) goto .L3
rep; ret
.cfi_endproc
.LFE0:
.sizeexpand_data, .-expand_data
.ident"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-23)"
.section.note.GNU-stack,"",@progbits
阅读GCC产生的汇编代码可知:
1、((x >> 15) | (x << 17))这种会自动变成xor指令,无须使用宏夹杂内联汇编代码污染C语言代码的可读性;
2、GCC会根据需要将临时变量进行寄存器优化,为了可读性多用几个临时变量没啥坏处;
3、GCC似乎不喜欢减法,所以在C语言程序编写时,循环变量也好,数组下标也好,尽量使用加法而不是减法;
更多相关内容 -
SM3算法 C语言 (从OpenSSL库中分离算法:六)
2021-11-16 17:10:17SM3算法 C语言 (从OpenSSL库中分离算法:六) OpenSSL简介: OpenSSL 是用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的一个强大、商业级和功能齐全的工具包,它也是一个通用的密码学库。包含有RSA、SM4、DES、...SM3算法 C语言 (从OpenSSL库中分离算法:六)
OpenSSL简介:
OpenSSL 是用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的一个强大、商业级和功能齐全的工具包,它也是一个通用的密码学库。包含有RSA、SM4、DES、AES等诸多加密算法。
OpenSSL GitHub地址如下:
GitHub - openssl/openssl: TLS/SSL and crypto library
在日常的开发工作中,有时只想用OpenSSL库中的一种算法,此时调用整个OpenSSL库,往往是没必要的;再或者在嵌入式平台使用某一算法,那我们只移植这个算法,没有必要移植整个OpenSSL库。
SM3简介
SM3是我国采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。它可以将任意长度的消息压缩成固定长度的摘要,主要用于数字签名和数据完整性保护等
在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。
移植过程
一、下载代码
从OpenSSL的Github仓库下载代码,可以下载master分支,也可以下载最新的release版本。将下载的文件解压,得到代码。
重点关注红框目录:
- crypto目录内是各种加密算法
- include目录内是各加密算法对外接口的头文件
二、准备环境
新建Visual Studio C++ 控制台项目"sm3test",编译选项是:x86\Debug
三、准备文件
- 复制OpenSSL源码中:/crypto/sm3文件夹到VS工程代码目录下
- 复制OpenSSL源码中:/include/internal/sm3.h文件到VS工程代码目录中sm3文件夹内
- 复制OpenSSL源码中:/include/crypto/md32_common.h文件到VS工程代码目录中sm3文件夹内
- 复制完成后,VS工程代码目录sm3文件夹内文件如下:
删除目录内的如下本项目中无用文件:- build.info
- legacy_sm3.c
四、修改代码
修改调用文件
在VS工程中含有main函数的主文件:sm3test.cpp中,增加包含sm3.h头文件
#include "sm3/sm3.h"
在main函数中添加如下代码
SM3_CTX SMC; ossl_sm3_init(&SMC); const unsigned char Data[1024] = "Hello World"; unsigned char md[SM3_DIGEST_LENGTH] = { 0 }; ossl_sm3_update(&SMC, Data, strlen((const char *) Data)); ossl_sm3_final(md, &SMC); for (int i = 0; i < SM3_DIGEST_LENGTH; i++) { printf("%02x-", *(md + i)); }
修改后的sm3test.cpp代码如下:
#include <iostream> #include "sm3/sm3.h" int main() { SM3_CTX SMC; ossl_sm3_init(&SMC); const unsigned char Data[1024] = "Hello World"; unsigned char md[SM3_DIGEST_LENGTH] = { 0 }; ossl_sm3_update(&SMC, Data, strlen((const char *) Data)); ossl_sm3_final(md, &SMC); for (int i = 0; i < SM3_DIGEST_LENGTH; i++) { printf("%02x-", *(md + i)); } }
修改sm3.h
删除条件编译
OPENSSL_SM3_H
删除头文件
# include <openssl/opensslconf.h>
删除条件编译
OPENSSL_NO_SM3
添加C++调用时的宏
修改或删除后的文件如下:
# pragma once # ifdef __cplusplus extern "C" { # endif # define SM3_DIGEST_LENGTH 32 # define SM3_WORD unsigned int # define SM3_CBLOCK 64 # define SM3_LBLOCK (SM3_CBLOCK/4) typedef struct SM3state_st { SM3_WORD A, B, C, D, E, F, G, H; SM3_WORD Nl, Nh; SM3_WORD data[SM3_LBLOCK]; unsigned int num; } SM3_CTX; int ossl_sm3_init(SM3_CTX* c); int ossl_sm3_update(SM3_CTX* c, const void* data, size_t len); int ossl_sm3_final(unsigned char* md, SM3_CTX* c); # ifdef __cplusplus } # endif
修改sm3_local.h
修改头文件
# include "internal/sm3.h"
改为#include "sm3.h"
修改头文件
# include "crypto/md32_common.h"
改为#include "md32_common.h"
修改或删除后的文件如下:
#include <string.h> #include "sm3.h" #define DATA_ORDER_IS_BIG_ENDIAN #define HASH_LONG SM3_WORD #define HASH_CTX SM3_CTX #define HASH_CBLOCK SM3_CBLOCK #define HASH_UPDATE ossl_sm3_update #define HASH_TRANSFORM ossl_sm3_transform #define HASH_FINAL ossl_sm3_final #define HASH_MAKE_STRING(c, s) \ do { \ unsigned long ll; \ ll=(c)->A; (void)HOST_l2c(ll, (s)); \ ll=(c)->B; (void)HOST_l2c(ll, (s)); \ ll=(c)->C; (void)HOST_l2c(ll, (s)); \ ll=(c)->D; (void)HOST_l2c(ll, (s)); \ ll=(c)->E; (void)HOST_l2c(ll, (s)); \ ll=(c)->F; (void)HOST_l2c(ll, (s)); \ ll=(c)->G; (void)HOST_l2c(ll, (s)); \ ll=(c)->H; (void)HOST_l2c(ll, (s)); \ } while (0) #define HASH_BLOCK_DATA_ORDER ossl_sm3_block_data_order void ossl_sm3_block_data_order(SM3_CTX *c, const void *p, size_t num); void ossl_sm3_transform(SM3_CTX *c, const unsigned char *data); #include "md32_common.h" #define P0(X) (X ^ ROTATE(X, 9) ^ ROTATE(X, 17)) #define P1(X) (X ^ ROTATE(X, 15) ^ ROTATE(X, 23)) #define FF0(X,Y,Z) (X ^ Y ^ Z) #define GG0(X,Y,Z) (X ^ Y ^ Z) #define FF1(X,Y,Z) ((X & Y) | ((X | Y) & Z)) #define GG1(X,Y,Z) ((Z ^ (X & (Y ^ Z)))) #define EXPAND(W0,W7,W13,W3,W10) \ (P1(W0 ^ W7 ^ ROTATE(W13, 15)) ^ ROTATE(W3, 7) ^ W10) #define RND(A, B, C, D, E, F, G, H, TJ, Wi, Wj, FF, GG) \ do { \ const SM3_WORD A12 = ROTATE(A, 12); \ const SM3_WORD A12_SM = A12 + E + TJ; \ const SM3_WORD SS1 = ROTATE(A12_SM, 7); \ const SM3_WORD TT1 = FF(A, B, C) + D + (SS1 ^ A12) + (Wj); \ const SM3_WORD TT2 = GG(E, F, G) + H + SS1 + Wi; \ B = ROTATE(B, 9); \ D = TT1; \ F = ROTATE(F, 19); \ H = P0(TT2); \ } while(0) #define R1(A,B,C,D,E,F,G,H,TJ,Wi,Wj) \ RND(A,B,C,D,E,F,G,H,TJ,Wi,Wj,FF0,GG0) #define R2(A,B,C,D,E,F,G,H,TJ,Wi,Wj) \ RND(A,B,C,D,E,F,G,H,TJ,Wi,Wj,FF1,GG1) #define SM3_A 0x7380166fUL #define SM3_B 0x4914b2b9UL #define SM3_C 0x172442d7UL #define SM3_D 0xda8a0600UL #define SM3_E 0xa96f30bcUL #define SM3_F 0x163138aaUL #define SM3_G 0xe38dee4dUL #define SM3_H 0xb0fb0e4eUL
修改sm3.c
删除头文件
#include <openssl/e_os2.h>
修改或删除后的文件如下:
#include "sm3_local.h" int ossl_sm3_init(SM3_CTX *c) { memset(c, 0, sizeof(*c)); c->A = SM3_A; c->B = SM3_B; c->C = SM3_C; c->D = SM3_D; c->E = SM3_E; c->F = SM3_F; c->G = SM3_G; c->H = SM3_H; return 1; } void ossl_sm3_block_data_order(SM3_CTX *ctx, const void *p, size_t num) { const unsigned char *data = p; register unsigned MD32_REG_T A, B, C, D, E, F, G, H; unsigned MD32_REG_T W00, W01, W02, W03, W04, W05, W06, W07, W08, W09, W10, W11, W12, W13, W14, W15; for (; num--;) { A = ctx->A; B = ctx->B; C = ctx->C; D = ctx->D; E = ctx->E; F = ctx->F; G = ctx->G; H = ctx->H; /* * We have to load all message bytes immediately since SM3 reads * them slightly out of order. */ (void)HOST_c2l(data, W00); (void)HOST_c2l(data, W01); (void)HOST_c2l(data, W02); (void)HOST_c2l(data, W03); (void)HOST_c2l(data, W04); (void)HOST_c2l(data, W05); (void)HOST_c2l(data, W06); (void)HOST_c2l(data, W07); (void)HOST_c2l(data, W08); (void)HOST_c2l(data, W09); (void)HOST_c2l(data, W10); (void)HOST_c2l(data, W11); (void)HOST_c2l(data, W12); (void)HOST_c2l(data, W13); (void)HOST_c2l(data, W14); (void)HOST_c2l(data, W15); R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04); W00 = EXPAND(W00, W07, W13, W03, W10); R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05); W01 = EXPAND(W01, W08, W14, W04, W11); R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06); W02 = EXPAND(W02, W09, W15, W05, W12); R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07); W03 = EXPAND(W03, W10, W00, W06, W13); R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08); W04 = EXPAND(W04, W11, W01, W07, W14); R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09); W05 = EXPAND(W05, W12, W02, W08, W15); R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10); W06 = EXPAND(W06, W13, W03, W09, W00); R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11); W07 = EXPAND(W07, W14, W04, W10, W01); R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12); W08 = EXPAND(W08, W15, W05, W11, W02); R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13); W09 = EXPAND(W09, W00, W06, W12, W03); R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14); W10 = EXPAND(W10, W01, W07, W13, W04); R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15); W11 = EXPAND(W11, W02, W08, W14, W05); R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00); W12 = EXPAND(W12, W03, W09, W15, W06); R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01); W13 = EXPAND(W13, W04, W10, W00, W07); R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02); W14 = EXPAND(W14, W05, W11, W01, W08); R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03); W15 = EXPAND(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); W00 = EXPAND(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); W01 = EXPAND(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); W02 = EXPAND(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); W03 = EXPAND(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); W04 = EXPAND(W04, W11, W01, W07, W14); R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); W05 = EXPAND(W05, W12, W02, W08, W15); R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); W06 = EXPAND(W06, W13, W03, W09, W00); R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); W07 = EXPAND(W07, W14, W04, W10, W01); R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); W08 = EXPAND(W08, W15, W05, W11, W02); R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); W09 = EXPAND(W09, W00, W06, W12, W03); R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); W10 = EXPAND(W10, W01, W07, W13, W04); R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); W11 = EXPAND(W11, W02, W08, W14, W05); R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); W12 = EXPAND(W12, W03, W09, W15, W06); R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); W13 = EXPAND(W13, W04, W10, W00, W07); R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); W14 = EXPAND(W14, W05, W11, W01, W08); R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); W15 = EXPAND(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04); W00 = EXPAND(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05); W01 = EXPAND(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06); W02 = EXPAND(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07); W03 = EXPAND(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08); W04 = EXPAND(W04, W11, W01, W07, W14); R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09); W05 = EXPAND(W05, W12, W02, W08, W15); R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10); W06 = EXPAND(W06, W13, W03, W09, W00); R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11); W07 = EXPAND(W07, W14, W04, W10, W01); R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12); W08 = EXPAND(W08, W15, W05, W11, W02); R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13); W09 = EXPAND(W09, W00, W06, W12, W03); R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14); W10 = EXPAND(W10, W01, W07, W13, W04); R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15); W11 = EXPAND(W11, W02, W08, W14, W05); R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00); W12 = EXPAND(W12, W03, W09, W15, W06); R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01); W13 = EXPAND(W13, W04, W10, W00, W07); R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02); W14 = EXPAND(W14, W05, W11, W01, W08); R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03); W15 = EXPAND(W15, W06, W12, W02, W09); R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); W00 = EXPAND(W00, W07, W13, W03, W10); R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); W01 = EXPAND(W01, W08, W14, W04, W11); R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); W02 = EXPAND(W02, W09, W15, W05, W12); R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); W03 = EXPAND(W03, W10, W00, W06, W13); R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); ctx->A ^= A; ctx->B ^= B; ctx->C ^= C; ctx->D ^= D; ctx->E ^= E; ctx->F ^= F; ctx->G ^= G; ctx->H ^= H; } }
修改md32_common.h
删除头文件
# include <openssl/crypto.h>
删除代码中全部的
OPENSSL_cleanse();
*解释:经查阅openssl代码中的OPENSSL_cleanse函数声明,此函数作用等同与标准C中的memset(p,0,size)功能,是将参数一内存清0,本文件中调用该函数的地方,其参数1均为栈空间,函数结束后将自动回收,因此没必要手动清0,因此该函数可以不调用,若不放心,可以用memset函数替代。
修改或删除后的文件如下:
#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN) # error "DATA_ORDER must be defined!" #endif #ifndef HASH_CBLOCK # error "HASH_CBLOCK must be defined!" #endif #ifndef HASH_LONG # error "HASH_LONG must be defined!" #endif #ifndef HASH_CTX # error "HASH_CTX must be defined!" #endif #ifndef HASH_UPDATE # error "HASH_UPDATE must be defined!" #endif #ifndef HASH_TRANSFORM # error "HASH_TRANSFORM must be defined!" #endif #ifndef HASH_FINAL # error "HASH_FINAL must be defined!" #endif #ifndef HASH_BLOCK_DATA_ORDER # error "HASH_BLOCK_DATA_ORDER must be defined!" #endif #define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) #if defined(DATA_ORDER_IS_BIG_ENDIAN) # define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++))) ) ) # define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff), \ l) #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) # define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<<24) ) # define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff), \ l) #endif /* * Time for some action :-) */ int HASH_UPDATE(HASH_CTX *c, const void *data_, size_t len) { const unsigned char *data = data_; unsigned char *p; HASH_LONG l; size_t n; if (len == 0) return 1; l = (c->Nl + (((HASH_LONG) len) << 3)) & 0xffffffffUL; if (l < c->Nl) /* overflow */ c->Nh++; c->Nh += (HASH_LONG) (len >> 29); /* might cause compiler warning on * 16-bit */ c->Nl = l; n = c->num; if (n != 0) { p = (unsigned char *)c->data; if (len >= HASH_CBLOCK || len + n >= HASH_CBLOCK) { memcpy(p + n, data, HASH_CBLOCK - n); HASH_BLOCK_DATA_ORDER(c, p, 1); n = HASH_CBLOCK - n; data += n; len -= n; c->num = 0; /* * We use memset rather than OPENSSL_cleanse() here deliberately. * Using OPENSSL_cleanse() here could be a performance issue. It * will get properly cleansed on finalisation so this isn't a * security problem. */ memset(p, 0, HASH_CBLOCK); /* keep it zeroed */ } else { memcpy(p + n, data, len); c->num += (unsigned int)len; return 1; } } n = len / HASH_CBLOCK; if (n > 0) { HASH_BLOCK_DATA_ORDER(c, data, n); n *= HASH_CBLOCK; data += n; len -= n; } if (len != 0) { p = (unsigned char *)c->data; c->num = (unsigned int)len; memcpy(p, data, len); } return 1; } void HASH_TRANSFORM(HASH_CTX *c, const unsigned char *data) { HASH_BLOCK_DATA_ORDER(c, data, 1); } int HASH_FINAL(unsigned char *md, HASH_CTX *c) { unsigned char *p = (unsigned char *)c->data; size_t n = c->num; p[n] = 0x80; /* there is always room for one */ n++; if (n > (HASH_CBLOCK - 8)) { memset(p + n, 0, HASH_CBLOCK - n); n = 0; HASH_BLOCK_DATA_ORDER(c, p, 1); } memset(p + n, 0, HASH_CBLOCK - 8 - n); p += HASH_CBLOCK - 8; #if defined(DATA_ORDER_IS_BIG_ENDIAN) (void)HOST_l2c(c->Nh, p); (void)HOST_l2c(c->Nl, p); #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) (void)HOST_l2c(c->Nl, p); (void)HOST_l2c(c->Nh, p); #endif p -= HASH_CBLOCK; HASH_BLOCK_DATA_ORDER(c, p, 1); c->num = 0; #ifndef HASH_MAKE_STRING # error "HASH_MAKE_STRING must be defined!" #else HASH_MAKE_STRING(c, md); #endif return 1; } #ifndef MD32_REG_T # if defined(__alpha) || defined(__sparcv9) || defined(__mips) # define MD32_REG_T long /* * This comment was originally written for MD5, which is why it * discusses A-D. But it basically applies to all 32-bit digests, * which is why it was moved to common header file. * * In case you wonder why A-D are declared as long and not * as MD5_LONG. Doing so results in slight performance * boost on LP64 architectures. The catch is we don't * really care if 32 MSBs of a 64-bit register get polluted * with eventual overflows as we *save* only 32 LSBs in * *either* case. Now declaring 'em long excuses the compiler * from keeping 32 MSBs zeroed resulting in 13% performance * improvement under SPARC Solaris7/64 and 5% under AlphaLinux. * Well, to be honest it should say that this *prevents* * performance degradation. */ # else /* * Above is not absolute and there are LP64 compilers that * generate better code if MD32_REG_T is defined int. The above * pre-processor condition reflects the circumstances under which * the conclusion was made and is subject to further extension. */ # define MD32_REG_T int # endif #endif
五、编译运行
将sm3.h,sm3.c,sm3_local.h,md32_common.h文件,配置添加到VS工程中。
编译运行,输出sm3结果如下:
77-01-58-16-14-3e-e6-27-f4-fa-41-0b-6d-ad-2b-db-9f-cb-df-1e-06-1a-45-2a-68-6b-87-11-a4-84-c5-d7
上述算法,适用于计算字符串、缓冲区的SM3值。至于小文件、大文件的SM3如何计算,可以参考本人的另外两篇关于MD5的博客,与SM3非常相似。
欢迎大家关注、留言讨论、可分享源码
-
SM2/SM3算法C语言实现
2018-06-06 20:07:241、完整的SM2/SM3算法,C语言实现,可用于扫码POS安全认证; 2、SM2加密/解密、SM2签名/验签 3、内含测试程序,在Linux环境下进入目录后make即可编译,已经在ubuntu16.04环境下编译测试OK; 4、已经在银行卡检测中心... -
SM3算法C语言源码
2017-01-09 11:52:55国家密码管理局的SM3算法标准的C语言源码,此代码的计算结果经过国家密码管理局商用密码检测中心的测试,代码简洁,易用性强。 -
SM3算法及HMAC<SM3>算法C语言实现
2021-04-13 16:49:30SM3算法及HMAC<SM3>算法C语言实现。内附详细测试例程。 SM3测试数据取自 GMT 0004-2012 HMAC测试数据来自Crypto++ 源文件列表: test.cpp sm3.cpp sm3.h 包含测试工程: VC++6.0, VC++2008, VC++2013, CentOS7-x64+... -
SM3算法C语言实现
2011-11-03 15:43:54按国密标准开发的C语言版(VC6)的SM3算法源代码 参考xyssl源码库实现 计算结果与标准测试数据完全相同 附带有SM3-HMAC算法 -
SM3密码算法c语言实现
2019-03-17 14:27:30本文件内含sm3国家密码算法设计总则,对sm3进行C语言实现,在Windows环境下可编程实现,包括源代码,内容详细,简单易懂。 -
SM3密码杂凑算法C语言实现
2018-11-27 15:00:14SM3密码杂凑算法C语言实现 信息安全综合实验的一个作业,要求使用miracl库。但实际上,sm3的绝大部分操作都是在32位的字上的,没有任何必要使用这个库,并且由于它对很多操作都不支持,实际上是加大了編程的难度。就...SM3密码杂凑算法C语言实现
信息安全综合实验的一个作业,要求使用miracl库。但实际上,sm3的绝大部分操作都是在32位的字上的,没有任何必要使用这个库,并且由于它对很多操作都不支持,实际上是加大了編程的难度。就当是练手了- -
#include<stdio.h> #include"miracl.h" #include<string.h> #define AND 0 #define OR 3 #define XOR 2 #define PLUS 1 #define MAXN 100 int fill(big m, int l) //消息填充 { //填充1到末尾 sftbit(m, 1, m); add(m, mirvar(1), m); //填充k个0 int k = ((447-l)%512+512)%512; sftbit(m, k, m); //填充64位比特串 sftbit(m, 64 ,m); add(m, mirvar(l), m); return (l+k+65)/512; } void leftshift(big a, int len, big ans) //32位的a 循环左移len位 { len %= 32; big x = mirvar(0); big b = mirvar(0); expb2(32-len, x); copy(a, ans); divide(ans, x, b); sftbit(ans, len, ans); add(ans, b, ans); } void inverse(big x, big ans) //对32位的x进行取反位操作 { char xb[4]; big_to_bytes(4, x, xb, TRUE); for (int i=0;i<4;i++) xb[i] = ~xb[i]; bytes_to_big(4, xb, ans); } void operation(big a, big b, int op, big ans) //对32位的a和b进行操作 { if (op == PLUS) { big x = mirvar(0);expb2(32, x); add(a, b, ans); divide(ans, x, x); return; } char ab[4], bb[4]; big_to_bytes(4, a, ab, TRUE); big_to_bytes(4, b, bb, TRUE); switch(op){ case XOR:for (int i=0;i<4;i++) ab[i] = ab[i] ^ bb[i];break; case AND:for (int i=0;i<4;i++) ab[i] = ab[i] & bb[i];break; case OR:for (int i=0;i<4;i++) ab[i] = ab[i] | bb[i];break; } bytes_to_big(4, ab, ans); } void P(int k, big x, big ans) /*置换函数 P0(X) = X xor (X <<< 9) xor (X<<<17) P1(X) = X xor (X <<< 15) xor (X<<<23)*/ { big a = mirvar(0); big b = mirvar(0); copy(x, a); copy(x, b); if (k == 1) { leftshift(a, 15, a); leftshift(b, 23, b); } else{ leftshift(a, 9, a); leftshift(b, 17, b); } operation(x, a, XOR, ans); operation(ans, b, XOR, ans); } void T(int j, big x) { if (0<=j && j<=15) cinstr(x, "79cc4519"); else if (16<=j && j<=63) cinstr(x, "7a879d8a"); } void expand(big B, big W[], big Wap[]) //填充 { big t[2]; t[0] = mirvar(0);copy(B, t[0]); t[1] = mirvar(0); big x = mirvar(0);expb2(32, x); int l = 0; for (int i=15;i>=0;i--) { divide(t[l], x, t[1-l]); W[i] = mirvar(0); copy(t[l],W[i]); l=1-l; } //Wj = P1(W[j−16] xor W[j−9] xor (W[j−3]<<<15)) xor (W[j−13]<<<7) xor W[j−6] for (int i=16;i<=67;i++) { W[i] = mirvar(0); operation(W[i-16],W[i-9], XOR, W[i]); big t = mirvar(0); leftshift(W[i-3], 15, t); operation(W[i], t, XOR, W[i]); P(1, W[i], W[i]); leftshift(W[i-13], 7, t); operation(W[i], t, XOR, W[i]); operation(W[i], W[i-6], XOR, W[i]); } for (int i=0;i<=63;i++) { Wap[i] = mirvar(0); operation(W[i], W[i+4], XOR, Wap[i]); } } void FF(int j, big X, big Y, big Z, big ans) { if (0<=j && j<=15) { operation(X, Y, XOR, ans); operation(ans, Z, XOR, ans); } else if (16<=j && j<=63) { //(X and Y ) or (X and Z) or (Y and Z ) big t = mirvar(0); operation(X, Y, AND, ans); operation(X, Z, AND, t); operation(ans, t, OR, ans); operation(Y, Z, AND, t); operation(ans, t, OR, ans); } } void GG(int j, big X, big Y, big Z, big ans) { if (0<=j && j<=15) { operation(X, Y, XOR, ans); operation(ans, Z, XOR, ans); } else if (16<=j && j<=63) { //(X and Y) or (not X and Z) big t = mirvar(0); operation(X, Y, AND, ans); inverse(X, t); operation(t, Z, AND, t); operation(ans, t, OR, ans); } } void print(big V[]) { char s[10]; for (int i=0;i<8;i++) { cotstr(V[i], s); for(int j=0;j<8-strlen(s);j++) putchar('0'); printf("%s", s); if (i==7) putchar('\n'); else putchar(' '); } } void compress(big W[], big Wap[], big V[]) //压缩 { big SS1,SS2,TT1,TT2,t; SS1 = mirvar(0);SS2 = mirvar(0); TT1 = mirvar(0);TT2 = mirvar(0); t = mirvar(0); big A,B,C,D,E,F,G,H; A = mirvar(0);copy(V[0], A);B = mirvar(0);copy(V[1], B); C = mirvar(0);copy(V[2], C);D = mirvar(0);copy(V[3], D); E = mirvar(0);copy(V[4], E);F = mirvar(0);copy(V[5], F); G = mirvar(0);copy(V[6], G);H = mirvar(0);copy(V[7], H); for (int i=0;i<=63;i++) { //SS1 = ((A<<<12) + E + (Tj<<<j))<<<7 leftshift(A, 12, SS1); operation(SS1, E, PLUS, SS1); T(i, t); leftshift(t, i, t); operation(SS1, t, PLUS, SS1); leftshift(SS1, 7, SS1); //SS2 = SS1 xor (A<<<12) leftshift(A, 12, SS2); operation(SS1, SS2, XOR, SS2); //TT1 = FFj(A,B,C) + D + SS2 +Wj′ FF(i, A, B, C, TT1); operation(TT1, D, PLUS, TT1); operation(TT1, SS2, PLUS, TT1); operation(TT1, Wap[i], PLUS, TT1); //TT2 = GGj(E, F, G) + H + SS1 +Wj GG(i, E, F, G, TT2); operation(TT2, H, PLUS, TT2); operation(TT2, SS1, PLUS, TT2); operation(TT2, W[i], PLUS, TT2); //D=C; C=B<<<9; B=A; A=TT1; H=G; G=F<<<19; F=E; E=P0(TT2) copy(C,D); leftshift(B, 9, C); copy(A, B); copy(TT1, A); copy(G, H); leftshift(F, 19, G); copy(E, F); P(0, TT2, E); //printf("%2d: ", i); //print(A,B,C,D,E,F,G,H); } //V[i+1] = ABCDEFGH xor V[i] operation(A, V[0], XOR, V[0]);operation(B, V[1], XOR, V[1]); operation(C, V[2], XOR, V[2]);operation(D, V[3], XOR, V[3]); operation(E, V[4], XOR, V[4]);operation(F, V[5], XOR, V[5]); operation(G, V[6], XOR, V[6]);operation(H, V[7], XOR, V[7]); } void iteration(big m, int n, big V[]) //迭代 { big Bi[10], t[2], W[68], Wap[64]; t[0] = mirvar(0);copy(m, t[0]); t[1] = mirvar(0); int l = 0; big x = mirvar(0);expb2(512, x); for (int i=n-1;i>=0;i--) { divide(t[l], x, t[1-l]); Bi[i] = mirvar(0); copy(t[l],Bi[i]); l=1-l; } for (int i=0;i<n;i++) { expand(Bi[i], W, Wap); compress(W, Wap, V); } } int main() { //读入 miracl *mip = mirsys(512*MAXN, 10); mip->IOBASE = 16; char s[64*MAXN]; scanf("%s", s); int l = strlen(s); big m = mirvar(0); for (int i=0;i<l;i++) { sftbit(m, 8, m); add(m, mirvar(s[i]), m); } //填充 l *= 8; int n = fill(m,l); //迭代压缩 big V[8]; for (int i=0;i<8;i++) V[i] = mirvar(0); cinstr(V[0], "7380166f"); cinstr(V[1], "4914b2b9"); cinstr(V[2], "172442d7"); cinstr(V[3], "da8a0600"); cinstr(V[4], "a96f30bc"); cinstr(V[5], "163138aa"); cinstr(V[6], "e38dee4d"); cinstr(V[7], "b0fb0e4e"); iteration(m, n, V); print(V); return 0; }
结果与sm3文档给出的一致。 -
SM2SM3SM4国密算法C语言实现VS2015.zip
2020-07-07 07:54:48SM2SM3SM4国密算法C语言实现VS2015 还包含以下文本档可以学习 SM2椭圆曲线公钥密码算法 SM2椭圆曲线公钥密码算法推荐曲线参数 SM3密码杂凑算法 SM4分组密码算法 -
国密SM2加密算法 C语言实现
2019-10-18 14:59:37基于Miracl大数运算库实现SM2算法,包含加密和签名算法,纯C语言实现,包含Miracl库手册。提供了Linux平台下的Makefile文件,可直接运行。Windows平台需要重新建立项目工程。 -
SM3国密加密算法(C语言)
2021-01-23 20:37:01SM3算法是公开的。实现原理如下图所示: C代码展示: 完整代码见github:https://github.com/CMwshuai/Algorithm.git 1、初始值IV static const unsigned int IV[8] = { 0x7380166F, 0x4914B2B9, 0x...SM3是国产哈希算法,在商用密码体系中,主要用于数字签名及验证、消息认证码生成及验证、随机数生成等。对于用户需要加密的数据在加密后会生成一个固定长度(32字节)的哈希值。SM3算法是公开的。实现原理如下图所示:
C代码展示:
完整代码见github:https://github.com/CMwshuai/Algorithm.git
1、初始值IV
static const unsigned int IV[8] = { 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, 0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E, };
2、常量初始化T
static void _init_T() { int i = 0; for (; i < 16; i++) T[i] = 0x79CC4519; for (; i < 64; i++) T[i] = 0x7A879D8A; }
3、 布尔函数_FF,_GG
static unsigned int _FF( const unsigned int X, const unsigned int Y, const unsigned int Z, const unsigned int j) { if (0 <= j && j < 16) return (X ^ Y ^ Z); else if (16 <= j && j < 64) return ((X & Y) | (X & Z) | (Y & Z)); return 0; } static unsigned int _GG( const unsigned int X, const unsigned int Y, const unsigned int Z, const unsigned int j) { if (0 <= j && j < 16) return (X ^ Y ^ Z); else if (16 <= j && j < 64) return ((X & Y) | ((~X) & Z)); return 0; }
4、置换函数_P0,_P1
static unsigned int _P0(const unsigned int X) { return (X ^ (_rotate_left_move(X, 9)) ^ (_rotate_left_move(X, 17))); } static unsigned int _P1(const unsigned int X) { return (X ^ (_rotate_left_move(X, 15)) ^ (_rotate_left_move(X, 23))); }
5、消息填充
unsigned int nGroupNum = (nSrcLen + 1 + 8 + 64) / 64; unsigned char *ucpMsgBuf = (unsigned char*)malloc(nGroupNum * 64); memset(ucpMsgBuf, 0, nGroupNum * 64); memcpy(ucpMsgBuf, ucpSrcData, nSrcLen); ucpMsgBuf[nSrcLen] = 0x80; int i = 0; for (i = 0; i < 8; i++) { ucpMsgBuf[nGroupNum * 64 - i - 1] = ((unsigned long long)(nSrcLen * 8) >> (i * 8)) & 0xFF; }
6、迭代压缩
static unsigned int _CF(unsigned char* ucpSrcMsg, unsigned int nHash[8]) { unsigned int W68[68] = { 0 }; unsigned int W64[64] = { 0 }; //message extension int j = 0; for (j = 0; j < 16; j++) { W68[j] = ((unsigned int)ucpSrcMsg[j * 4 + 0] << 24) & 0xFF000000 | ((unsigned int)ucpSrcMsg[j * 4 + 1] << 16) & 0x00FF0000 | ((unsigned int)ucpSrcMsg[j * 4 + 2] << 8) & 0x0000FF00 | ((unsigned int)ucpSrcMsg[j * 4 + 3] << 0) & 0x000000FF; } for (j = 16; j < 68; j++) { W68[j] = _P1(W68[j - 16] ^ W68[j - 9] ^ (_rotate_left_move(W68[j - 3], 15))) ^ (_rotate_left_move(W68[j - 13], 7)) ^ W68[j - 6]; } for (j = 0; j < 64; j++) { W64[j] = W68[j] ^ W68[j + 4]; } //iterative process unsigned int A_G[8] = { 0 }; for (j = 0; j < 8; j++) { A_G[j] = nHash[j]; } //tempporary variable unsigned int SS1 = 0, SS2 = 0, TT1 = 0, TT2 = 0; for (j = 0; j < 64; j++) { SS1 = _rotate_left_move((_rotate_left_move(A_G[A], 12) + A_G[E] + _rotate_left_move(T[j], j % 32)), 7); SS2 = SS1 ^ (_rotate_left_move(A_G[A], 12)); TT1 = _FF(A_G[A], A_G[B], A_G[C], j) + A_G[D] + SS2 + W64[j]; TT2 = _GG(A_G[E], A_G[F], A_G[G], j) + A_G[H] + SS1 + W68[j]; A_G[D] = A_G[C]; A_G[C] = _rotate_left_move(A_G[B], 9); A_G[B] = A_G[A]; A_G[A] = TT1; A_G[H] = A_G[G]; A_G[G] = _rotate_left_move(A_G[F], 19); A_G[F] = A_G[E]; A_G[E] = _P0(TT2); } for (j = 0; j < 8; j++) { nHash[j] = A_G[j] ^ nHash[j]; } return 0; }
-
SM3密码算法C语言实现
2017-10-10 15:21:59亲测好用,做了一定的封装。里面还包含一些spec。我也是从网上下载的根据自己的需求改了一下。 -
SM2&SM3&SM4国密算法C语言实现(VS2008)
2016-11-17 11:24:53按照国密文档通过C语言实现SM2密码算法加密/解密、签名/验签,SM3密码杂凑算法,SM4分组密码算法ECB、CBC模式加密/解密。 经过国密标准中数据验证无误。若有问题请及时反馈,期待和大家进行交流学习。 附带国密规范... -
SM4国密加密算法C语言实现
2017-09-13 10:24:29SM4国密加密算法C语言实现 包括 Spec,C代码,测试用例和分组密码有五种工作体制:1.电码本模式(Electronic Codebook Book (ECB));2.密码分组链接模式(Cipher Block Chaining (CBC));3.计算器模式(Counter ... -
SM4对称加密算法-C语言
2020-11-22 16:42:08C语言实现国密SM4对称加解密算法。编译环境:VS2010。请参考我的博客https://blog.csdn.net/u013073067/article/details/86578753 分析代码 -
SM3算法的编程实现
2021-06-19 21:04:51SM3算法的编程实现SM3算法的编程实现【实验目的】【实验环境】【实验预备知识点】【实验步骤】【实验思考题】 SM3算法的编程实现 【实验目的】 1、理解Hash函数的计算原理和特点; 2、理解SM3算法原理; 3、了解SM3... -
国密SM2密码算法的C语言实现
2021-05-24 07:48:26SM2椭圆曲线密码算法是国家密码管理局批准的...本文介绍了SM2椭圆曲线公钥密码算法和加密解密算法中一部分过程的C语言实现。【关键词】 椭圆曲线 SM2 密码算法 公钥 加密解密Implementation of Public Key Cryptogr... -
国密SM3的C语言代码C51移植到8051
2021-05-07 14:04:00SM3杂凑算法是我国自主设计的密码杂凑算法 SM3是中华人民共和国政府采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。 在商用密码体系中... -
SM3国密杂凑值算法的原理和c语言实现
2021-11-03 18:57:33一、SM3算法介绍 杂凑值算法也可称为摘要算法或者哈希算法。通过对数据资料的填充、分组、扩展压缩等方式计算成特定长度的数值,来作为数据指纹或者数据特征使用。常见的MD5算法长度为128bit(16字节),SHA1算法... -
C语言实现SM3
2020-05-28 22:58:27用C语言实现SM3,源码已上传至github -
求 国密sm2 算法 第四部分 公钥加密算法 c语言实现代码,该怎么解决
2021-05-24 08:13:15当前位置:我的异常网» C++»求 国密sm2 算法 第四部分 公钥加密算法 c语言实现求 国密sm2 算法 第四部分 公钥加密算法 c语言实现代码,该怎么解决www.myexceptions.net网友分享于:2014-07-26浏览:0次求 国密sm2 ... -
国密SM2非对称算法C语言实现
2018-07-06 19:31:08国密算法SM2算法 C语言源码 签名验签 加解密, 密钥交换 -
SM2&SM3&SM4国密算法C语言实现.zip
2016-11-17 09:59:31按照国密文档通过C语言实现SM2密码算法加密/解密、签名/验签,SM3密码杂凑算法,SM4分组密码算法ECB、CBC模式加密/解密。 经过详尽的测试目前未发现问题,并附有国密标准中数据检测结果。若有问题请及时反馈,期待和... -
SM4算法 C语言 (从OpenSSL库中分离算法:七)
2021-11-22 20:22:05SM4算法 C语言 (从OpenSSL库中分离算法:七) OpenSSL简介: OpenSSL 是用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的一个强大、商业级和功能齐全的工具包,它也是一个通用的密码学库。包含有RSA、SM4、DES、... -
sm3算法
2017-09-30 09:59:44sm3算法c语言实现 /* 2017.9.24 am 10:00 -11:50 2017.9.24 pm 14:00-17:00 19:00-23:00 2017.9.25 pm 14:00-17:30 */ #include #include #include unsigned int w0[70],w1[70];//用于压缩...