1.在Ubuntu或openEuler中(推荐openEuler)中调试运行教材提供的源代码,至少运行SM2,SM3,SM4代码,使用GmSSL命令验证你代码的正确性,使用Markdown记录详细记录实践过程,每完成一项功能或者一个函数gitcommit一次。
运行SM3
#include <stdio.h>
#include <memory>
#include <cstring>
#include <cstdint> // 包含标准整数类型unsigned char IV[256 / 8] = { 0x73,0x80,0x16,0x6f,0x49,0x14,0xb2,0xb9,0x17,0x24,0x42,0xd7,0xda,0x8a,0x06,0x00,0xa9,0x6f,0x30,0xbc,0x16,0x31,0x38,0xaa,0xe3,0x8d,0xee,0x4d,0xb0,0xfb,0x0e,0x4e };// 循环左移
unsigned long SL(unsigned long X, int n)
{uint64_t x = X; // 修改为标准类型x = x << (n % 32);unsigned long l = (unsigned long)(x >> 32);return x | l;
}unsigned long Tj(int j)
{if (j <= 15){return 0x79cc4519;}else{return 0x7a879d8a;}
}unsigned long FFj(int j, unsigned long X, unsigned long Y, unsigned long Z)
{if (j <= 15){return X ^ Y ^ Z;}else{return (X & Y) | (X & Z) | (Y & Z);}
}unsigned long GGj(int j, unsigned long X, unsigned long Y, unsigned long Z)
{if (j <= 15){return X ^ Y ^ Z;}else{return (X & Y) | (~X & Z);}
}unsigned long P0(unsigned long X)
{return X ^ SL(X, 9) ^ SL(X, 17);
}unsigned long P1(unsigned long X)
{return X ^ SL(X, 15) ^ SL(X, 23);
}// 扩展
void EB(unsigned char Bi[512 / 8], unsigned long W[68], unsigned long W1[64])
{// Bi 分为W0~W15for (int i = 0; i < 16; ++i){W[i] = Bi[i * 4] << 24 | Bi[i * 4 + 1] << 16 | Bi[i * 4 + 2] << 8 | Bi[i * 4 + 3];}for (int j = 16; j <= 67; ++j){W[j] = P1(W[j - 16] ^ W[j - 9] ^ SL(W[j - 3], 15)) ^ SL(W[j - 13], 7) ^ W[j - 6];}for (int j = 0; j <= 63; ++j){W1[j] = W[j] ^ W[j + 4];}
}// 压缩函数
void CF(unsigned char Vi[256 / 8], unsigned char Bi[512 / 8], unsigned char Vi1[256 / 8])
{// Bi 扩展为132个字unsigned long W[68] = { 0 };unsigned long W1[64] = { 0 };EB(Bi, W, W1);// 串联 ABCDEFGH = Viunsigned long R[8] = { 0 };for (int i = 0; i < 8; ++i){R[i] = ((unsigned long)Vi[i * 4]) << 24 | ((unsigned long)Vi[i * 4 + 1]) << 16 | ((unsigned long)Vi[i * 4 + 2]) << 8 | ((unsigned long)Vi[i * 4 + 3]);}unsigned long A = R[0], B = R[1], C = R[2], D = R[3], E = R[4], F = R[5], G = R[6], H = R[7];unsigned long SS1, SS2, TT1, TT2;for (int j = 0; j <= 63; ++j){SS1 = SL(SL(A, 12) + E + SL(Tj(j), j), 7);SS2 = SS1 ^ SL(A, 12);TT1 = FFj(j, A, B, C) + D + SS2 + W1[j];TT2 = GGj(j, E, F, G) + H + SS1 + W[j];D = C;C = SL(B, 9);B = A;A = TT1;H = G;G = SL(F, 19);F = E;E = P0(TT2);}// Vi1 = ABCDEFGH 串联R[0] = A, R[1] = B, R[2] = C, R[3] = D, R[4] = E, R[5] = F, R[6] = G, R[7] = H;for (int i = 0; i < 8; ++i){Vi1[i * 4] = (R[i] >> 24) & 0xFF;Vi1[i * 4 + 1] = (R[i] >> 16) & 0xFF;Vi1[i * 4 + 2] = (R[i] >> 8) & 0xFF;Vi1[i * 4 + 3] = (R[i]) & 0xFF;}// Vi1 = ABCDEFGH ^ Vifor (int i = 0; i < 256 / 8; ++i){Vi1[i] ^= Vi[i];}
}//参数 m 是原始数据,ml 是数据长度,r 是输出参数,存放hash结果
void SM3Hash(unsigned char* m, int ml, unsigned char r[32])
{int l = ml * 8;int k = 448 - 1 - l % 512; // 添加k个0,k 是满足 l + 1 + k ≡ 448mod512 的最小的非负整数if (k <= 0){k += 512;}int n = (l + k + 65) / 512;int m1l = n * 512 / 8; // 填充后的长度,512位的倍数unsigned char* m1 = new unsigned char[m1l];memset(m1, 0, m1l);memcpy(m1, m, l / 8);m1[l / 8] = 0x80; // 消息后补1// 再添加一个64位比特串,该比特串是长度l的二进制表示unsigned long l1 = l;for (int i = 0; i < 64 / 8 && l1 > 0; ++i){m1[m1l - 1 - i] = l1 & 0xFF;l1 = l1 >> 8;}//将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)· · · B(n−1),其中n=(l+k+65)/512。unsigned char** B = new unsigned char*[n];for (int i = 0; i < n; ++i){B[i] = new unsigned char[512 / 8];memcpy(B[i], m1 + (512 / 8)*i, 512 / 8);}delete[] m1;unsigned char** V = new unsigned char*[n + 1];for (int i = 0; i <= n; ++i){V[i] = new unsigned char[256 / 8];memset(V[i], 0, 256 / 8);}// 初始化 V0 = VImemcpy(V[0], IV, 256 / 8);// 压缩函数,V 与扩展的Bfor (int i = 0; i < n; ++i){CF(V[i], B[i], V[i + 1]);}for (int i = 0; i < n; ++i){delete[] B[i];}delete[] B;// V[n]是结果memcpy(r, V[n], 32);for (int i = 0; i <= n; ++i){delete[] V[i];}delete[] V;
}// 打印缓冲区内容
void dumpbuf(unsigned char* buf, int len)
{for (int i = 0; i < len; ++i) {printf("%02x", buf[i]);if ((i + 1) % 16 == 0) printf("\n");elseprintf(" ");}printf("\n");
}int main()
{// 输入数据unsigned char message[] = "abc";int message_len = strlen((char*)message);// 输出缓冲区unsigned char hash_result[32] = { 0 };// 调用 SM3 哈希函数SM3Hash(message, message_len, hash_result);// 输出哈希结果printf("SM3 Hash:\n");dumpbuf(hash_result, 32);return 0;
}
调试运行sm3代码
- 源代码:
在这里插入代码片
- 代码编译运行过程结果:
- 4-2代码编译运行结果(手工实现三段式SM3算法)
- 源代码:
sm3.cpp
#include "sm3.h"
#include <string.h>
#include <stdio.h>/** 32-bit integer manipulation macros (big endian)*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \{ \(n) = ( (unsigned long) (b)[(i) ] << 24 ) \| ( (unsigned long) (b)[(i) + 1] << 16 ) \| ( (unsigned long) (b)[(i) + 2] << 8 ) \| ( (unsigned long) (b)[(i) + 3] ); \}
#endif#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \{ \(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \(b)[(i) + 3] = (unsigned char) ( (n) ); \}
#endif/** SM3 context setup*/
void sm3_starts(sm3_context *ctx)
{ctx->total[0] = 0;ctx->total[1] = 0;ctx->state[0] = 0x7380166F;ctx->state[1] = 0x4914B2B9;ctx->state[2] = 0x172442D7;ctx->state[3] = 0xDA8A0600;ctx->state[4] = 0xA96F30BC;ctx->state[5] = 0x163138AA;ctx->state[6] = 0xE38DEE4D;ctx->state[7] = 0xB0FB0E4E;}static void sm3_process(sm3_context *ctx, unsigned char data[64])
{unsigned long SS1, SS2, TT1, TT2, W[68], W1[64];unsigned long A, B, C, D, E, F, G, H;unsigned long T[64];unsigned long Temp1, Temp2, Temp3, Temp4, Temp5;int j;
#ifdef _DEBUGint i;
#endif// for(j=0; j < 68; j++)// W[j] = 0;// for(j=0; j < 64; j++)// W1[j] = 0;for (j = 0; j < 16; j++)T[j] = 0x79CC4519;for (j = 16; j < 64; j++)T[j] = 0x7A879D8A;GET_ULONG_BE(W[0], data, 0);GET_ULONG_BE(W[1], data, 4);GET_ULONG_BE(W[2], data, 8);GET_ULONG_BE(W[3], data, 12);GET_ULONG_BE(W[4], data, 16);GET_ULONG_BE(W[5], data, 20);GET_ULONG_BE(W[6], data, 24);GET_ULONG_BE(W[7], data, 28);GET_ULONG_BE(W[8], data, 32);GET_ULONG_BE(W[9], data, 36);GET_ULONG_BE(W[10], data, 40);GET_ULONG_BE(W[11], data, 44);GET_ULONG_BE(W[12], data, 48);GET_ULONG_BE(W[13], data, 52);GET_ULONG_BE(W[14], data, 56);GET_ULONG_BE(W[15], data, 60);#ifdef _DEBUGprintf("Message with padding:\n");for (i = 0; i < 8; i++)printf("%08x ", W[i]);printf("\n");for (i = 8; i < 16; i++)printf("%08x ", W[i]);printf("\n");
#endif#define FF0(x,y,z) ( (x) ^ (y) ^ (z))
#define FF1(x,y,z) (((x) & (y)) | ( (x) & (z)) | ( (y) & (z)))#define GG0(x,y,z) ( (x) ^ (y) ^ (z))
#define GG1(x,y,z) (((x) & (y)) | ( (~(x)) & (z)) )#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))#define P0(x) ((x) ^ ROTL((x),9) ^ ROTL((x),17))
#define P1(x) ((x) ^ ROTL((x),15) ^ ROTL((x),23))for (j = 16; j < 68; j++){//W[j] = P1( W[j-16] ^ W[j-9] ^ ROTL(W[j-3],15)) ^ ROTL(W[j - 13],7 ) ^ W[j-6];//Why thd release's result is different with the debug's ?//Below is okay. Interesting, Perhaps VC6 has a bug of Optimizaiton.Temp1 = W[j - 16] ^ W[j - 9];Temp2 = ROTL(W[j - 3], 15);Temp3 = Temp1 ^ Temp2;Temp4 = P1(Temp3);Temp5 = ROTL(W[j - 13], 7) ^ W[j - 6];W[j] = Temp4 ^ Temp5;}#ifdef _DEBUGprintf("Expanding message W0-67:\n");for (i = 0; i < 68; i++){printf("%08x ", W[i]);if (((i + 1) % 8) == 0) printf("\n");}printf("\n");
#endiffor (j = 0; j < 64; j++){W1[j] = W[j] ^ W[j + 4];}#ifdef _DEBUGprintf("Expanding message W'0-63:\n");for (i = 0; i < 64; i++){printf("%08x ", W1[i]);if (((i + 1) % 8) == 0) printf("\n");}printf("\n");
#endifA = ctx->state[0];B = ctx->state[1];C = ctx->state[2];D = ctx->state[3];E = ctx->state[4];F = ctx->state[5];G = ctx->state[6];H = ctx->state[7];
#ifdef _DEBUGprintf("j A B C D E F G H\n");printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", A, B, C, D, E, F, G, H);
#endiffor (j = 0; j < 16; j++){SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[j], j)), 7);SS2 = SS1 ^ ROTL(A, 12);TT1 = FF0(A, B, C) + D + SS2 + W1[j];TT2 = GG0(E, F, G) + H + SS1 + W[j];D = C;C = ROTL(B, 9);B = A;A = TT1;H = G;G = ROTL(F, 19);F = E;E = P0(TT2);
#ifdef _DEBUGprintf("%02d %08x %08x %08x %08x %08x %08x %08x %08x\n", j, A, B, C, D, E, F, G, H);
#endif}for (j = 16; j < 64; j++){SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[j], j)), 7);SS2 = SS1 ^ ROTL(A, 12);TT1 = FF1(A, B, C) + D + SS2 + W1[j];TT2 = GG1(E, F, G) + H + SS1 + W[j];D = C;C = ROTL(B, 9);B = A;A = TT1;H = G;G = ROTL(F, 19);F = E;E = P0(TT2);
#ifdef _DEBUGprintf("%02d %08x %08x %08x %08x %08x %08x %08x %08x\n", j, A, B, C, D, E, F, G, H);
#endif}ctx->state[0] ^= A;ctx->state[1] ^= B;ctx->state[2] ^= C;ctx->state[3] ^= D;ctx->state[4] ^= E;ctx->state[5] ^= F;ctx->state[6] ^= G;ctx->state[7] ^= H;
#ifdef _DEBUGprintf(" %08x %08x %08x %08x %08x %08x %08x %08x\n", ctx->state[0], ctx->state[1], ctx->state[2],ctx->state[3], ctx->state[4], ctx->state[5], ctx->state[6], ctx->state[7]);
#endif
}/** SM3 process buffer*/
void sm3_update(sm3_context *ctx, unsigned char *input, int ilen)
{int fill;unsigned long left;if (ilen <= 0)return;left = ctx->total[0] & 0x3F;fill = 64 - left;ctx->total[0] += ilen;ctx->total[0] &= 0xFFFFFFFF;if (ctx->total[0] < (unsigned long)ilen)ctx->total[1]++;if (left && ilen >= fill){memcpy((void *)(ctx->buffer + left),(void *)input, fill);sm3_process(ctx, ctx->buffer);input += fill;ilen -= fill;left = 0;}while (ilen >= 64){sm3_process(ctx, input);input += 64;ilen -= 64;}if (ilen > 0){memcpy((void *)(ctx->buffer + left),(void *)input, ilen);}
}static const unsigned char sm3_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
};/** SM3 final digest*/
void sm3_finish(sm3_context *ctx, unsigned char output[32])
{unsigned long last, padn;unsigned long high, low;unsigned char msglen[8];high = (ctx->total[0] >> 29)| (ctx->total[1] << 3);low = (ctx->total[0] << 3);PUT_ULONG_BE(high, msglen, 0);PUT_ULONG_BE(low, msglen, 4);last = ctx->total[0] & 0x3F;padn = (last < 56) ? (56 - last) : (120 - last);sm3_update(ctx, (unsigned char *)sm3_padding, padn);sm3_update(ctx, msglen, 8);PUT_ULONG_BE(ctx->state[0], output, 0);PUT_ULONG_BE(ctx->state[1], output, 4);PUT_ULONG_BE(ctx->state[2], output, 8);PUT_ULONG_BE(ctx->state[3], output, 12);PUT_ULONG_BE(ctx->state[4], output, 16);PUT_ULONG_BE(ctx->state[5], output, 20);PUT_ULONG_BE(ctx->state[6], output, 24);PUT_ULONG_BE(ctx->state[7], output, 28);
}/** output = SM3( input buffer )*/
void sm3(unsigned char *input, int ilen,unsigned char output[32])
{sm3_context ctx;sm3_starts(&ctx);sm3_update(&ctx, input, ilen);sm3_finish(&ctx, output);memset(&ctx, 0, sizeof(sm3_context));
}/** output = SM3( file contents )*/
int sm3_file(char *path, unsigned char output[32])
{FILE *f;size_t n;sm3_context ctx;unsigned char buf[1024];if ((f = fopen(path, "rb")) == NULL)return(1);sm3_starts(&ctx);while ((n = fread(buf, 1, sizeof(buf), f)) > 0)sm3_update(&ctx, buf, (int)n);sm3_finish(&ctx, output);memset(&ctx, 0, sizeof(sm3_context));if (ferror(f) != 0){fclose(f);return(2);}fclose(f);return(0);
}
- 代码编译运行过程结果:
- 代码编译运行结果(基于openssl实现sm3)
- 源代码:
#include <stdio.h>
#include <string.h>
#include "sm3hash.h"int main(void)
{const unsigned char sample1[] = { 'a', 'b', 'c', 0 };unsigned int sample1_len = strlen((char *)sample1);const unsigned char sample2[] = { 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64,0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64 };unsigned int sample2_len = sizeof(sample2);unsigned char hash_value[64];unsigned int i, hash_len;sm3_hash(sample1, sample1_len, hash_value, &hash_len);printf("raw data: %s\n", sample1);printf("hash length: %d bytes.\n", hash_len);printf("hash value:\n");for (i = 0; i < hash_len; i++){printf("0x%x ", hash_value[i]);}printf("\n\n");sm3_hash(sample2, sample2_len, hash_value, &hash_len);printf("raw data:\n");for (i = 0; i < sample2_len; i++){printf("0x%x ", sample2[i]);}printf("\n");printf("hash length: %d bytes.\n", hash_len);printf("hash value:\n");for (i = 0; i < hash_len; i++){printf("0x%x ", hash_value[i]);}printf("\n");return 0;
}
-
代码编译运行过程结果:
- 4-4代码编译运行结果(实现HMAC-SM3算法)
-
代码编译运行过程结果:
- 验证部分
使用GmSSL命令得到’abc’和’abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd’的哈希值
- 验证部分
运行SM4
- 调试运行sm4代码
- 代码编译运行结果(16字节版)
- - 代码编译运行结果(实现SM4-ECBCBCCFBOFB 算法(大数据版))
- 验证:32位与64位编译均自检成功
- 其他:sm4的程序似乎与系统位数无关,编译的结果都能通过自检函数
- 代码编译运行结果(16字节版)
运行SM2
- 调试运行sm2代码:
- 代码编译运行结果(sm2签名验签)
- 编译与运行结果:
- 验证:自检均通过,无需用命令验证
2. 在密标委网站http://www.gmbz.org.cn/main/bzlb.html查找SM2,SM3,SM4相关标准,分析代码实现与标准的对应关系。(10分)
SM2(椭圆曲线公钥密码算法)
SM2是中国国家密码管理局发布的基于椭圆曲线密码体系的公钥密码标准。它主要用于加密、解密、签名和验证等操作。SM2算法的核心是椭圆曲线上的点乘运算。
代码实现与标准的对应关系:
- 密钥生成:根据SM2标准,生成椭圆曲线上的公私钥对。
- 加密:使用接收方的公钥进行点加密。
- 解密:使用发送方的私钥进行点解密。
- 签名:使用发送方的私钥生成签名。
- 验证:使用发送方的公钥验证签名。
SM3(密码杂凑算法)
SM3是中国国家标准的密码杂凑算法,类似于国际上的SHA-256算法。它用于生成数据的摘要,以确保数据的完整性。
代码实现与标准的对应关系:
- 数据摘要:按照SM3算法标准,对输入数据进行处理,生成固定长度的摘要。
- 数据完整性验证:通过比较原始数据和摘要来验证数据的完整性。
SM4(对称加密算法)
SM4是中国国家密码管理局公布的一种对称加密标准,类似于AES算法。它主要用于数据的加密和解密。
代码实现与标准的对应关系:
- 加密:根据SM4算法标准,使用密钥对数据进行加密。
- 解密:使用相同的密钥对加密后的数据进行解密。
3. 实验记录中提交 gitee 课程项目链接,提交本次实验相关 git log运行结果
实验过程中遇到的问题
出现找不到文件目录等问题,通过询问kimi,发现是代码编译的不准确导致无法找到正确路径,通过更改代码头文件,删去子目录成功编译文件