《密码系统设计》实验二
在 Ubuntu或openEuler中(推荐 openEuler)中调试运⾏商⽤密码检测中⼼https://www.scctc.org.cn/xzzx/sfydm/ydmxz/提供的源代码,⾄少运⾏SM2,SM3,SM4代码。使⽤GmSSL命令验证你代码的正确性。使⽤Markdown记录详细记录实践过程,每完成⼀项功能或者⼀个函数git commit ⼀次。(14分)
(一)SM2的实践
由于miracl库存在问题,反复尝试无法编译,故参考链接进行实践:
https://github.com/lookingforfyf/SMX_Test/tree/master
qzz@qzz-virtual-machine:~/Desktop/sy2/sm2/SMX_Test-master/SMX_Test/miracl-lib-X86_64/SM2ALG$ make
qzz@qzz-virtual-machine:~/Desktop/sy2/sm2/SMX_Test-master/SMX_Test/miracl-lib-X86_64/SM2ALG$ ./sm2_test
==============================================================================
message = 6D65737361676520646967657374 [for test sign]
data = 656E6372797074696F6E207374616E64617264 [for test enc]
privkey = 3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8
pubx = 09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020
puby = CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13
rand = 59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21
ZA = B2E14C5C79C6DF5B85F4FE7ED8DB7A262B9DA7E07CCB0EA9F4747B8CCDA8A4F3
sign_R = F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3
sign_S = B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA
cipher = 04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF059983C18F809E262923C53AEC295D30383B54E39D609D160AFCB1908D0BD876621886CA989CA9C7D58087307CA93092D651EFA
==============================================================================generate privkey = 3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8 [pass]
generate pubx = 09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020 [pass]
generate puby = CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13 [pass]
generate ZA = B2E14C5C79C6DF5B85F4FE7ED8DB7A262B9DA7E07CCB0EA9F4747B8CCDA8A4F3 [pass]
generate sign_r = F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3 [pass]
generate sign_s = B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA [pass]
generate cipher = 04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73 [pass]E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF059983C18F809E262923C53AEC295D30383B54E39D609D160AFCB1908D0BD876621886CA989CA9C7D58087307CA93092D651EFA
截图如下:

(二)SM3的实践
sm3.h
//
// Created by He-Zh on 2024/10/27.
//#ifndef EXP2_SM3_H
#define EXP2_SM3_H
#include <string.h>
#define SM3_len 256
#define SM3_T1 0x79CC4519
#define SM3_T2 0x7A879D8A
#define SM3_IVA 0x7380166f
#define SM3_IVB 0x4914b2b9
#define SM3_IVC 0x172442d7
#define SM3_IVD 0xda8a0600
#define SM3_IVE 0xa96f30bc
#define SM3_IVF 0x163138aa
#define SM3_IVG 0xe38dee4d
#define SM3_IVH 0xb0fb0e4e
/* Various logical functions */
#define SM3_p1(x) (x^SM3_rotl32(x,15)^SM3_rotl32(x,23))
#define SM3_p0(x) (x^SM3_rotl32(x,9)^SM3_rotl32(x,17))
#define SM3_ff0(a,b,c) (a^b^c)
#define SM3_ff1(a,b,c) ((a&b)|(a&c)|(b&c))
#define SM3_gg0(e,f,g) (e^f^g)
#define SM3_gg1(e,f,g) ((e&f)|((~e)&g))
#define SM3_rotl32(x,n) ((((unsigned int) x) << n) | (((unsigned int) x) >> (32 - n)))
#define SM3_rotr32(x,n) ((((unsigned int) x) >> n) | (((unsigned int) x) << (32 - n)))
typedef struct {unsigned int state[8];unsigned int length;unsigned int curlen;unsigned char buf[64];
} SM3_STATE;
void BiToWj(unsigned int Bi[], unsigned int Wj[]);
void WjToWj1(unsigned int Wj[], unsigned int Wj1[]);
void CF(unsigned int Wj[], unsigned int Wj1[], unsigned int V[]);
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]);
void SM3_init(SM3_STATE *md);
void SM3_compress(SM3_STATE * md);
void SM3_process(SM3_STATE * md, unsigned char buf[], int len);
void SM3_done(SM3_STATE *md, unsigned char *hash);
void SM3_256(unsigned char buf[], int len, unsigned char hash[]);
int SM3_SelfTest();
#endif //EXP2_SM3_H
sm3.c
//
// Created by He-Zh on 2024/10/27.
//#include "sm3.h"
#include <stdio.h>
void BiToW(unsigned int Bi[], unsigned int W[])
{int i;unsigned int tmp;for(i=0;i<=15;i++){W[i]=Bi[i];}for(i=16;i<=67;i++){tmp=W[i-16]^ W[i-9]^ SM3_rotl32(W[i-3],15);W[i]=SM3_p1(tmp)^ (SM3_rotl32(W[i-13],7))^ W[i-6];}
}
void WToW1(unsigned int W[], unsigned int W1[])
{int i;for(i=0;i<=63;i++){W1[i]=W[i]^W[i+4];}
}
void CF(unsigned int W[], unsigned int W1[], unsigned int V[])
{unsigned int SS1;unsigned int SS2;unsigned int TT1;unsigned int TT2;unsigned int A,B,C,D,E,F,G,H;unsigned int T=SM3_T1;unsigned int FF;unsigned int GG;int j;
//reg init,set ABCDEFGH=V0A=V[0];B=V[1];C=V[2];D=V[3];E=V[4];F=V[5];G=V[6];H=V[7];for(j=0;j<=63;j++){//SS1if(j==0){T=SM3_T1;}else if(j==16){T=SM3_rotl32(SM3_T2,16);}else{T=SM3_rotl32(T,1);}SS1=SM3_rotl32((SM3_rotl32(A,12)+E+T),7);//SS2SS2=SS1^SM3_rotl32(A,12);//TT1if(j<=15){FF=SM3_ff0(A,B,C);}else{FF=SM3_ff1(A,B,C);}TT1=FF+D+SS2+*W1;W1++;//TT2if(j<=15){GG=SM3_gg0(E,F,G);}else{GG=SM3_gg1(E,F,G);}TT2=GG+H+SS1+*W;W++;//DD=C;//CC=SM3_rotl32(B,9);//BB=A;//AA=TT1;//HH=G;//GG=SM3_rotl32(F,19);//FF=E;//EE=SM3_p0(TT2);}//update VV[0]=A^V[0];V[1]=B^V[1];V[2]=C^V[2];V[3]=D^V[3];V[4]=E^V[4];V[5]=F^V[5];V[6]=G^V[6];V[7]=H^V[7];
}
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[])
{unsigned char tmp = 0;unsigned int i = 0;for(i=0; i<bytelen/4; i++){tmp = des[4*i];des[4*i] = src[4*i+3];src[4*i+3] = tmp;tmp = des[4*i+1];des[4*i+1] = src[4*i+2];des[4*i+2] = tmp;}
}
void SM3_init(SM3_STATE *md)
{md->curlen = md->length = 0;md->state[0] = SM3_IVA;md->state[1] = SM3_IVB;md->state[2] = SM3_IVC;md->state[3] = SM3_IVD;md->state[4] = SM3_IVE;md->state[5] = SM3_IVF;md->state[6] = SM3_IVG;md->state[7] = SM3_IVH;
}
void SM3_compress(SM3_STATE * md)
{unsigned int W[68];unsigned int W1[64];//if CPU uses little-endian, BigEndian function is a necessary callBigEndian(md->buf, 64, md->buf);BiToW((unsigned int *)md->buf,W);WToW1(W,W1);CF(W, W1, md->state);
}
void SM3_process(SM3_STATE * md, unsigned char *buf, int len)
{while (len--){/* copy byte */md->buf[md->curlen] = *buf++;md->curlen++;/* is 64 bytes full? */if (md->curlen == 64){SM3_compress(md);md->length += 512;md->curlen = 0;}}
}
void SM3_done(SM3_STATE *md, unsigned char hash[])
{int i;unsigned char tmp = 0;/* increase the bit length of the message */md->length += md->curlen <<3;/* append the '1' bit */md->buf[md->curlen] = 0x80;md->curlen++;/* if the length is currently above 56 bytes, appends zeros tillit reaches 64 bytes, compress the current block, creat a newblock by appending zeros and length,and then compress it*/if (md->curlen >56){for (; md->curlen < 64;){md->buf[md->curlen] = 0;md->curlen++;}SM3_compress(md);md->curlen = 0;}/* if the length is less than 56 bytes, pad upto 56 bytes of zeroes */for (; md->curlen < 56;){md->buf[md->curlen] = 0;md->curlen++;}/* since all messages are under 2^32 bits we mark the top bits zero */for (i = 56; i < 60; i++){md->buf[i] = 0;}/* append length */md->buf[63] = md->length & 0xff;md->buf[62] = (md->length >> 8) & 0xff;md->buf[61] = (md->length >> 16) & 0xff;md->buf[60] = (md->length >> 24) & 0xff;SM3_compress(md);/* copy output */memcpy(hash,md->state,SM3_len/8);BigEndian(hash,SM3_len/8,hash);//if CPU uses little-endian, BigEndian function is a necessary call
}
void SM3_256(unsigned char buf[], int len, unsigned char hash[])
{SM3_STATE md;SM3_init(&md);SM3_process(&md, buf, len);SM3_done(&md, hash);
}
int SM3_SelfTest()
{unsigned int i=0,a=1,b=1;// 测试用例1:字符串 "20231302邱之钊"unsigned char Msg1[] = "20231302邱之钊";int MsgLen1 = strlen((char*)Msg1);unsigned char MsgHash1[32] = {0};// 测试用例2:原来的长字符串测试(可选保留)unsigned char Msg2[64] = {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};int MsgLen2 = 64;unsigned char MsgHash2[32] = {0};unsigned char StdHash2[32] = {0xde,0xbe,0x9f,0xf9,0x22,0x75,0xb8,0xa1,0x38,0x60,0x48,0x89,0xc1,0x8e,0x5a,0x4d,0x6f,0xdb,0x70,0xe5,0x38,0x7e,0x57,0x65,0x29,0x3d,0xcb,0xa3,0x9c,0x0c,0x57,0x32};// 计算 "20231302邱之钊" 的哈希值SM3_256(Msg1, MsgLen1, MsgHash1);printf("SM3 hash of '20231302邱之钊': ");for(int i = 0; i < 32; i++){printf("%02x", MsgHash1[i]);}printf("\n");// 可选:计算第二个测试用例SM3_256(Msg2, MsgLen2, MsgHash2);// 由于我们没有 "20231302邱之钊" 的标准哈希值,这里只验证第二个测试用例b = memcmp(MsgHash2, StdHash2, SM3_len/8);// 如果第二个测试用例通过,就返回0(成功)if (b == 0){return 0;}else{return 1;}
}
int main(){printf("%d\n",SM3_SelfTest());return 0;
}
我的命令:
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ vi sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ vi sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ gcc -o sm3 sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ ./sm3
SM3 hash of '20231302邱之钊': ab3b4e68cfc076f2c08df9a44f32077d618014aafafffe650f2bbc9c970b51fe
0qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.h
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gcc -o sm4 sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check successqzz@qzz-virtual-machine:~/Desktop/sy2/sm4$
使用GmSSL命令验证代码正确性。和SM3代码运行结果完全一致:
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ echo -n "20231302邱之钊" | gmssl sm3
ab3b4e68cfc076f2c08df9a44f32077d618014aafafffe650f2bbc9c970b51fe

(三)SM4的实践
sm4.h
#include<stdio.h> //rotate n bits to the left in a 32bit buffer
#define SM4_Rotl32(buf, n) (((buf)<<n)|((buf)>>(32-n))) unsigned int SM4_CK[32] ={0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279}; unsigned char SM4_Sbox[256] = {0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}; unsigned int SM4_FK[4] = {0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC}; /************************************************************
Function: void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]);
Description: Generate round keys
Calls:
Called By: SM4_Encrypt; SM4_Decrypt;
Input: MK[]: Master key
Output: rk[]: round keys
Return:null Others:
************************************************************/
void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]); /************************************************************
Function: void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char
CipherText[]);
Description: Encryption function
Calls: SM4_KeySchedule
Called By:
Input: MK[]: Master key PlainText[]: input text
Output: CipherText[]: output text
Return:null
Others:
************************************************************/
void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char CipherText[]); /************************************************************
Function: void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[], unsigned char PlainText[]);
Description: Decryption function
Calls: SM4_KeySchedule
Called By:
Input: MK[]: Master key CipherText[]: input text
Output: PlainText[]: output text
Return:null
Others:
************************************************************/
void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[], unsigned char PlainText[]); /************************************************************
Function: int SM4_SelfCheck()
Description: Self-check with standard data
Calls: SM4_Encrypt; SM4_Decrypt;
Called By:
Input:
Output:
Return: 1 fail ; 0 success
Others:
************************************************************/
int SM4_SelfCheck();
sm4.c
//
// Created by He-Zh on 2024/10/27.
//#include "sm4.h"
void SM4_KeySchedule(unsigned char MK[],unsigned int rk[])
{unsigned int tmp,buf,K[36];int i;for(i=0;i<4;i++){K[i]=SM4_FK[i]^( (MK[4*i]<<24) | (MK[4*i+1]<<16)|(MK[4*i+2]<<8) | (MK[4*i+3]) );}for(i=0;i<32;i++){tmp =K[i+1]^K[i+2]^K[i+3]^ SM4_CK[i];//nonlinear operationbuf= (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);
//linear operationK[i+4]=K[i]^((buf)^(SM4_Rotl32((buf),13))^(SM4_Rotl32((buf),23)));rk[i]=K[i+4];}
}
void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char CipherText[])
{unsigned int rk[32],X[36],tmp,buf;int i,j;SM4_KeySchedule(MK,rk);for(j=0;j<4;j++){X[j]=(PlainText[j*4]<<24) |(PlainText[j*4+1]<<16)|(PlainText[j*4+2]<<8)|(PlainText[j*4+3]);}for(i=0;i<32;i++){tmp = X[i+1]^X[i+2]^X[i+3]^rk[i];//nonlinear operationbuf= ( SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);//linear operationX[i+4]=X[i]^(buf^SM4_Rotl32((buf),2)^ SM4_Rotl32((buf),10)^ SM4_Rotl32((buf),18)^ SM4_Rotl32((buf),24));}for(j=0;j<4;j++){CipherText[4*j]=(X[35-j]>> 24)& 0xFF;CipherText[4*j+1]=(X[35-j]>> 16)& 0xFF;CipherText[4*j+2]=(X[35-j]>> 8)& 0xFF;CipherText[4*j+3]=(X[35-j])& 0xFF;}
}
void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[],unsigned char PlainText[])
{unsigned int rk[32],X[36],tmp,buf;int i,j;SM4_KeySchedule(MK,rk);for(j=0;j<4;j++){X[j]=(CipherText[j*4]<<24) |(CipherText[j*4+1]<<16)|(CipherText[j*4+2]<<8)|(CipherText[j*4+3]);}for(i=0;i<32;i++){tmp = X[i+1]^X[i+2]^X[i+3]^rk[31-i];//nonlinear operationbuf= (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);//linear operationX[i+4]=X[i]^(buf^SM4_Rotl32((buf),2)^ SM4_Rotl32((buf),10)^ SM4_Rotl32((buf),18)^ SM4_Rotl32((buf),24));}for(j=0;j<4;j++){PlainText[4*j]=(X[35-j]>> 24)& 0xFF;PlainText[4*j+1]=(X[35-j]>>16)& 0xFF;PlainText[4*j+2]=(X[35-j]>> 8)& 0xFF;PlainText[4*j+3]=(X[35-j])& 0xFF;}
}
int SM4_SelfCheck()
{int i;//Standard dataunsigned char key[16] ={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};unsigned char plain[16]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};unsigned charcipher[16]={0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46};unsigned char En_output[16];unsigned char De_output[16];SM4_Encrypt(key,plain,En_output);SM4_Decrypt(key,cipher,De_output);for(i=0;i<16;i++){if ( (En_output[i]!=cipher[i]) | (De_output[i]!=plain[i]) ){printf("Self-check error");return 1;}}printf("Self-check success");return 0;
}
int main(){SM4_SelfCheck();return 0;
}
我的运行:
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.h
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gcc -o sm4 sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check successqzz@qzz-virtual-machine:~/Desktop/sy2/sm4$
使用GmSSL命令验证代码正确性。使用相同明文和密钥进行加密所得到的结果和SM4代码中的运行结果完全一致:
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ echo -ne "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10" > key.binx32\x10" > key.bin
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ echo -ne "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10" > plain.txt
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gmssl sm4_ecb -encrypt -in plain.txt -key $(xxd -p -c 32 key.bin) -out enc.bin
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ od -tc -tx1 enc.bin
0000000 h 036 337 4 322 006 226 ^ 206 263 351 O S n B F68 1e df 34 d2 06 96 5e 86 b3 e9 4f 53 6e 42 46
0000020
gmssl命令得出的结果是681edf34d206965e86b3e94f536e4246:

在 SM4_SelfCheck() 函数中,预期结果为681edf34d206965e86b3e94f536e4246,又因为运行函数结果显示运行结果与预期一致,故gmssl命令结果验证得到sm4代码结果正确:

在密标委⽹站http://www.gmbz.org.cn/main/bzlb.html查找SM2,SM3,SM4相关标准,分析代码实现与标准的对应关系。(6分)
SM2加解密
| 标准 | 函数实现 | 备注 |
|---|---|---|
| 常数与符号 | 一一对应 | |
| 辅助函数 | KDF | |
| 加密算法 | SM2_Encrypt 函数 | |
| 解密算法 | SM2_Decrypt 函数 | |
| 椭圆曲线系统参数 | SM2_Init 函数 | |
| 用户密钥对 | Test_PubKey 函数,SM2_KeyGeneration 函数 | SM2_KeyGeneration 函数作用:该函数用于从给定的私钥生成相应的公钥。在椭圆曲线密码学中,公钥是通过对基点(G)进行私钥的标量乘法得到的。即公钥 pubKey = [priKey]G,其中 priKey 是私钥,G 是椭圆曲线上的基点,[priKey]G 表示将基点G进行私钥对应的标量乘法操作。输入:私钥 priKey,这是一个大整数,通常在 [1, n-2] 范围内,其中n是椭圆曲线的基点G的阶。输出:公钥 pubKey,这是一个椭圆曲线上的点,表示为 (x, y) 坐标。返回:函数返回0表示成功生成公钥,返回1表示生成公钥过程中出现错误,比如私钥不在有效范围内或者公钥点不在椭圆曲线上。Test_PubKey 函数作用:该函数用于验证给定的公钥是否有效。有效性检查包括:公钥点是否在无穷远点(点在椭圆曲线上的定义之外),公钥点的坐标是否在有限域内,以及公钥点是否在椭圆曲线上,最后还要检查公钥点的阶是否等于n。输入:公钥点 pubKey,这是一个椭圆曲线上的点。输出:无。返回:函数返回0表示公钥有效,返回1表示公钥点是无穷远点,返回2表示公钥点的X或Y坐标超出了有限域的范围,返回3表示公钥点不在椭圆曲线上,返回4表示公钥点的阶不等于n。 |
SM2密钥协商
| 标准 | 函数实现 | 备注 |
|---|---|---|
| 常数与符号 | 一一对应 | |
| 辅助函数 | KDF | |
| 用户密钥对 | SM2_KeyGeneration 函数 | |
| 密钥交换协议 | SM2_KeyEx_Init_I 函数,SM2_KeyEx_Re_I 函数,SM2_KeyEx_Init_II 函数,SM2_KeyEx_Re_II 函数 | SM2_KeyEx_Init_I 函数:作用:密钥交换的初始化步骤,由发起方(例如Alice)生成一个随机数rA并计算点RA,这是密钥交换的第一步。SM2_KeyEx_Re_I 函数:作用:密钥交换的响应步骤,由响应方(例如Bob)生成RB,并计算一个共享的秘密密钥。Bob将RB发送给Alice。SM2_KeyEx_Init_II 函数:作用:密钥交换的完成步骤,由发起方Alice计算共享的秘密密钥,并计算一个哈希值供响应方Bob验证。SM2_KeyEx_Re_II 函数: 作用:(可选)响应方Bob验证从发起方Alice接收到的哈希值,以确保密钥交换的完整性和安全性 |
SM2签名验签
| 标准 | 函数实现 | 备注 |
|---|---|---|
| 常数与符号 | 一一对应 | |
| 辅助函数 | KDF | |
| 用户密钥对 | SM2_KeyGeneration | |
| 数字签名生成算法 | SM2_Sign | |
| 数字签名验证算法 | SM2_Verify | |
| 其他 | SM2_Init、Test_Point、Test_PubKey、Test_Zero、Test_n、Test_Range和SM3_256 | 持上述签名生成和验证过程中的辅助函数。它们用于初始化曲线参数、验证点是否在曲线上、验证公钥的有效性、检查大整数是否为零或等于n、以及计算哈希值 |
SM3
| 标准 | 函数实现 | 详细解释 |
|---|---|---|
| 常数 | 一一对应 | |
| 消息扩展 | BiToW 函数,WToW1 函数 | BiToW 函数:这个函数将输入的512位消息块(分割成16个32位字)扩展到一个512位的W数组,分成68个32位字。这个过程涉及到位操作和与SM3算法的固定参数相结合。WToW1 函数:这个函数进一步扩展消息,通过将W数组的每个元素与其后第四个元素进行异或操作,生成新的W1数组。这个数组将用于后续的压缩函数。 |
| 压缩函数 | CF 函数,SM3_compress 函数 | CF 函数:这个函数执行SM3算法的核心压缩操作,它使用W和W1数组以及一系列非线性和线性变换来更新哈希值。这个过程涉及到多轮迭代,每轮使用不同的参数和操作。SM3_compress 函数:这个函数执行实际的压缩操作,它调用BigEndian函数进行字节序转换,然后调用BiToW和WToW1函数进行消息扩展,最后调用CF函数执行压缩操作。 |
| 迭代过程 | CF 函数,SM3_compress 函数 | 在CF函数中:这个函数通过64轮迭代,使用W和W1数组以及一系列非线性和线性变换来更新哈希值。每轮迭代都涉及到消息的加权、压缩和哈希状态的更新。在SM3_process函数中:这个函数处理输入的消息,将其分割成512位的块,并重复调用SM3_compress函数来压缩每个块,直到所有消息都被处理。 |
SM4
| 标准 | 函数实现 |
|---|---|
| 轮函数F | SM4_KeySchedule 函数 |
| 加密算法 | SM4_Encrypt 函数 |
| 解密算法 | SM4_Decrypt 函数 |
| 密钥扩展算法 | SM4_KeySchedule 函数 |
3.使用Rust完成SM2,SM3,SM4算法的实现(选做,10分)
(一)SM3
sm3.rs
use std::mem::transmute;const SM3_LEN: usize = 256;
const SM3_T1: u32 = 0x79CC4519;
const SM3_T2: u32 = 0x7A879D8A;
const SM3_IVA: u32 = 0x7380166f;
const SM3_IVB: u32 = 0x4914b2b9;
const SM3_IVC: u32 = 0x172442d7;
const SM3_IVD: u32 = 0xda8a0600;
const SM3_IVE: u32 = 0xa96f30bc;
const SM3_IVF: u32 = 0x163138aa;
const SM3_IVG: u32 = 0xe38dee4d;
const SM3_IVH: u32 = 0xb0fb0e4e;#[derive(Clone)]
struct Sm3State {state: [u32; 8],length: u64,curlen: usize,buf: [u8; 64],
}impl Sm3State {fn new() -> Self {Self {state: [SM3_IVA, SM3_IVB, SM3_IVC, SM3_IVD, SM3_IVE, SM3_IVF, SM3_IVG, SM3_IVH],length: 0,curlen: 0,buf: [0u8; 64],}}fn p1(x: u32) -> u32 {x ^ Sm3State::rotl(x, 15) ^ Sm3State::rotl(x, 23)}fn p0(x: u32) -> u32 {x ^ Sm3State::rotl(x, 9) ^ Sm3State::rotl(x, 17)}fn ff0(a: u32, b: u32, c: u32) -> u32 {a ^ b ^ c}fn ff1(a: u32, b: u32, c: u32) -> u32 {(a & b) | (a & c) | (b & c)}fn gg0(e: u32, f: u32, g: u32) -> u32 {e ^ f ^ g}fn gg1(e: u32, f: u32, g: u32) -> u32 {(e & f) | (!e & g)}fn rotl(x: u32, n: u32) -> u32 {(x << n) | (x >> (32 - n))}fn big_endian(src: &[u8], bytelen: usize, des: &mut [u8]) {for i in 0..(bytelen / 4) {des[4 * i] = src[4 * i + 3];des[4 * i + 1] = src[4 * i + 2];des[4 * i + 2] = src[4 * i + 1];des[4 * i + 3] = src[4 * i];}}fn bi_to_w(bi: &[u32; 16], w: &mut [u32; 68]) {w[0..16].copy_from_slice(bi);for i in 16..68 {let tmp = w[i - 16] ^ w[i - 9] ^ Sm3State::rotl(w[i - 3], 15);w[i] = Sm3State::p1(tmp) ^ Sm3State::rotl(w[i - 13], 7) ^ w[i - 6];}}fn w_to_w1(w: &[u32; 68], w1: &mut [u32; 64]) {for i in 0..64 {w1[i] = w[i] ^ w[i + 4];}}fn cf(w: &[u32; 68], w1: &[u32; 64], v: &mut [u32; 8]) {let mut a = v[0];let mut b = v[1];let mut c = v[2];let mut d = v[3];let mut e = v[4];let mut f = v[5];let mut g = v[6];let mut h = v[7];let mut t = SM3_T1;for j in 0..64 {if j == 16 {t = Sm3State::rotl(SM3_T2, 16);} else if j > 0 {t = Sm3State::rotl(t, 1);}let ss1 = Sm3State::rotl(Sm3State::rotl(a, 12).wrapping_add(e).wrapping_add(t), 7);let ss2 = ss1 ^ Sm3State::rotl(a, 12);let tt1 = if j <= 15 {Sm3State::ff0(a, b, c)} else {Sm3State::ff1(a, b, c)}.wrapping_add(d).wrapping_add(ss2).wrapping_add(w1[j]);let tt2 = if j <= 15 {Sm3State::gg0(e, f, g)} else {Sm3State::gg1(e, f, g)}.wrapping_add(h).wrapping_add(ss1).wrapping_add(w[j]);d = c;c = Sm3State::rotl(b, 9);b = a;a = tt1;h = g;g = Sm3State::rotl(f, 19);f = e;e = Sm3State::p0(tt2);}v[0] ^= a;v[1] ^= b;v[2] ^= c;v[3] ^= d;v[4] ^= e;v[5] ^= f;v[6] ^= g;v[7] ^= h;}fn compress(&mut self) {let mut w = [0u32; 68];let mut w1 = [0u32; 64];let mut buf = [0u32; 16];for i in 0..16 {buf[i] = u32::from_be_bytes([self.buf[4 * i], self.buf[4 * i + 1], self.buf[4 * i + 2], self.buf[4 * i + 3]]);}Sm3State::bi_to_w(&buf, &mut w);Sm3State::w_to_w1(&w, &mut w1);Sm3State::cf(&w, &w1, &mut self.state);}fn process(&mut self, buf: &[u8]) {for &b in buf {self.buf[self.curlen] = b;self.curlen += 1;if self.curlen == 64 {self.compress();self.length += 512;self.curlen = 0;}}}fn done(&mut self, hash: &mut [u8; 32]) {self.length += (self.curlen as u64) << 3;self.buf[self.curlen] = 0x80;self.curlen += 1;if self.curlen > 56 {self.buf[self.curlen..64].fill(0);self.compress();self.curlen = 0;}self.buf[self.curlen..56].fill(0);self.buf[56..64].copy_from_slice(&self.length.to_be_bytes());self.compress();for (i, &s) in self.state.iter().enumerate() {hash[i * 4..i * 4 + 4].copy_from_slice(&s.to_be_bytes());}}
}fn sm3_256(buf: &[u8], hash: &mut [u8; 32]) {let mut state = Sm3State::new();state.process(buf);state.done(hash);
}fn main() {let mut hash = [0u8; 32];sm3_256(b"abc", &mut hash);for byte in &hash {print!("{:02x}", byte);}println!();
}
运行结果:
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ rustc sm3.rs
warning: unused import: `std::mem::transmute`--> sm3.rs:1:5|
1 | use std::mem::transmute;| ^^^^^^^^^^^^^^^^^^^|= note: `#[warn(unused_imports)]` on by defaultwarning: constant `SM3_LEN` is never used--> sm3.rs:3:7|
3 | const SM3_LEN: usize = 256;| ^^^^^^^|= note: `#[warn(dead_code)]` on by defaultwarning: associated function `big_endian` is never used--> sm3.rs:61:8|
23 | impl Sm3State {| ------------- associated function in this implementation
...
61 | fn big_endian(src: &[u8], bytelen: usize, des: &mut [u8]) {| ^^^^^^^^^^warning: 3 warnings emittedqzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ ./sm3
66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$

(二)SM4
sm4.rs
const SM4_CK: [u32; 32] = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
];const SM4_SBOX: [u8; 256] = [0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
];const SM4_FK: [u32; 4] = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];fn sm4_rotl32(buf: u32, n: u32) -> u32 {(buf << n) | (buf >> (32 - n))
}fn sm4_key_schedule(mk: &[u8], rk: &mut [u32; 32]) {let mut k = [0u32; 36];for i in 0..4 {k[i] = SM4_FK[i]^ ((mk[4 * i] as u32) << 24| (mk[4 * i + 1] as u32) << 16| (mk[4 * i + 2] as u32) << 8| (mk[4 * i + 3] as u32));}for i in 0..32 {let tmp = k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ SM4_CK[i];let buf = (SM4_SBOX[(tmp >> 24) as usize & 0xFF] as u32) << 24| (SM4_SBOX[(tmp >> 16) as usize & 0xFF] as u32) << 16| (SM4_SBOX[(tmp >> 8) as usize & 0xFF] as u32) << 8| SM4_SBOX[tmp as usize & 0xFF] as u32;k[i + 4] = k[i] ^ (buf ^ sm4_rotl32(buf, 13) ^ sm4_rotl32(buf, 23));rk[i] = k[i + 4];}
}
fn sm4_substitute(input: u32) -> u32 {// 使用S盒来替代输入字节let mut buf = 0u32;buf |= (SM4_SBOX[(input >> 24) as usize & 0xFF] as u32) << 24;buf |= (SM4_SBOX[(input >> 16) as usize & 0xFF] as u32) << 16;buf |= (SM4_SBOX[(input >> 8) as usize & 0xFF] as u32) << 8;buf |= SM4_SBOX[input as usize & 0xFF] as u32;buf
}fn sm4_round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {let tmp = x1 ^ x2 ^ x3 ^ rk;let buf = sm4_substitute(tmp);x0 ^ buf ^ sm4_rotl32(buf, 2) ^ sm4_rotl32(buf, 10) ^ sm4_rotl32(buf, 18) ^ sm4_rotl32(buf, 24)
}fn sm4_encrypt(input: &[u8], output: &mut [u8], rk: &[u32; 32]) {let mut x = [0u32; 36];for i in 0..4 {x[i] = (input[4 * i] as u32) << 24| (input[4 * i + 1] as u32) << 16| (input[4 * i + 2] as u32) << 8| input[4 * i + 3] as u32;}for i in 0..32 {x[i + 4] = sm4_round_function(x[i], x[i + 1], x[i + 2], x[i + 3], rk[i]);}for i in 0..4 {output[4 * i] = (x[35 - i] >> 24) as u8;output[4 * i + 1] = (x[35 - i] >> 16) as u8;output[4 * i + 2] = (x[35 - i] >> 8) as u8;output[4 * i + 3] = x[35 - i] as u8;}
}fn sm4_decrypt(input: &[u8], output: &mut [u8], rk: &[u32; 32]) {let mut x = [0u32; 36];for i in 0..4 {x[i] = (input[4 * i] as u32) << 24| (input[4 * i + 1] as u32) << 16| (input[4 * i + 2] as u32) << 8| input[4 * i + 3] as u32;}for i in 0..32 {x[i + 4] = sm4_round_function(x[i], x[i + 1], x[i + 2], x[i + 3], rk[31 - i]);}for i in 0..4 {output[4 * i] = (x[35 - i] >> 24) as u8;output[4 * i + 1] = (x[35 - i] >> 16) as u8;output[4 * i + 2] = (x[35 - i] >> 8) as u8;output[4 * i + 3] = x[35 - i] as u8;}
}
fn sm4_self_check() -> bool {// 标准测试数据let key: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,];let plain: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,];let expected_cipher: [u8; 16] = [0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e,0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46,];// 结果缓冲区let mut rk = [0u32; 32];let mut cipher = [0u8; 16];let mut decrypted = [0u8; 16];// 生成轮密钥sm4_key_schedule(&key, &mut rk);// 加密sm4_encrypt(&plain, &mut cipher, &rk);// 检查加密结果是否与期望值相同if cipher != expected_cipher {println!("Self-check error: encryption failed.");return false;}// 解密sm4_decrypt(&cipher, &mut decrypted, &rk);// 检查解密结果是否恢复为原始明文if decrypted != plain {println!("Self-check error: decryption failed.");return false;}println!("Self-check success.");true
}fn main() {if sm4_self_check() {println!("SM4 encryption and decryption passed the self-check.");} else {println!("SM4 encryption and decryption failed the self-check.");}
}
运行结果
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.rs
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ rustc sm4.rs
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check success.
SM4 encryption and decryption passed the self-check.
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$

代码,文档托管到gitee或github等,推荐gitclone
https://gitee.com/q9z2z2/922.git