利用国密SM4算法构造hash函数——C++实现

一,基础

SM4算法输入128bit,输出128bit

构造的hash函数以512bit分组,每个分组分为4个128bit进行4次SM4操作,将每次的输出异或

明文填充长度为64bit,填充方法同MD5,输出消息长度为128bit

 

详细国密SM4算法参见如下:

https://blog.csdn.net/cg129054036/article/details/83012721?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

二,结构

利用国密SM4算法构造hash函数——C++实现

EHi-1(Mi) xor Mi=Hi

即将Mi加密后的结果与Mi异或得到下一轮使用的密钥

三,代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 unsigned long sk[32];       //子密钥or轮密钥
  5 vector<unsigned char>X;
  6 int Turn;//加密分组数量
  7 
  8 #ifndef GET_ULONG_BE
  9 #define GET_ULONG_BE(n,b,i)                             
 10 {                                                       
 11     (n) = ( (unsigned long) (b)[(i)    ] << 24 )        
 12         | ( (unsigned long) (b)[(i) + 1] << 16 )        
 13         | ( (unsigned long) (b)[(i) + 2] <<  8 )        
 14         | ( (unsigned long) (b)[(i) + 3]       );       
 15 }
 16 #endif
 17 
 18 #ifndef PUT_ULONG_BE
 19 #define PUT_ULONG_BE(n,b,i)                             
 20 {                                                       
 21     (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       
 22     (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       
 23     (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       
 24     (b)[(i) + 3] = (unsigned char) ( (n)       );       
 25 }
 26 #endif
 27 
 28 #define  SHL(x,n) (((x) & 0xFFFFFFFF) << n)
 29 #define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))  //循环左移
 30 
 31 #define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }
 32 
 33 static unsigned char SboxTable[256] = {
 34     0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
 35     0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
 36     0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
 37     0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
 38     0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
 39     0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
 40     0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
 41     0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
 42     0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
 43     0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
 44     0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
 45     0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
 46     0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
 47     0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
 48     0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
 49     0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
 50 };
 51 
 52 static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};
 53 
 54 static const unsigned long CK[32] =
 55 {
 56 0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
 57 0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
 58 0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
 59 0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
 60 0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
 61 0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
 62 0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
 63 0x10171e25,0x2c333a41,0x484f565d,0x646b7279
 64 };
 65 
 66 //文本的填充处理
 67 void append(string m) {
 68     Turn = (m.size() + 8) / 64 + 1;//8*8=64为填充长度的预留位
 69     X.resize(Turn * 64);  //Turn为分组数 一组512bit 为64个十六进制
 70     int i = 0;
 71     for (; i < m.size(); i++) {
 72         X[i] = m[i];
 73     }
 74     X[i++] = 0x80;
 75     while (i < X.size() - 8) {
 76         X[i] = 0;
 77         i++;
 78     }
 79     long long int a = m.size() * 8;  //明文长度
 80     for (i = X.size() - 1; i >= X.size() - 8; i--) {
 81         X[i] = a % 256;
 82         a /= 256;
 83     }
 84 }
 85 
 86 //输出填充后的文本
 87 void printX() {
 88     printf("n明文填充后为:n");
 89     for (int i = 0; i < X.size(); i++) {
 90         printf("%02x", X[i]);
 91         if ((i + 1) % 4 == 0)
 92             printf(" ");
 93         if ((i + 1) % 16 == 0)
 94             printf("n");
 95     }
 96 }
 97 
 98 //S盒转换
 99 static unsigned char sm4Sbox(unsigned char inch)
100 {
101     return (unsigned char)(SboxTable[inch]);
102 }
103 
104 //T变换
105 static unsigned long sm4Lt(unsigned long ka)
106 {
107     unsigned long bb = 0;
108     unsigned long c = 0;
109     unsigned char a[4];
110     unsigned char b[4];
111     PUT_ULONG_BE(ka,a,0)    //将8位分在一起
112     b[0] = sm4Sbox(a[0]);
113     b[1] = sm4Sbox(a[1]);
114     b[2] = sm4Sbox(a[2]);
115     b[3] = sm4Sbox(a[3]);
116     GET_ULONG_BE(bb,b,0)    //合并为32位
117     c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));  //线性变换L
118     return c;
119 }
120 
121 //轮函数
122 static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
123 {
124     return (x0^sm4Lt(x1^x2^x3^rk));
125 }
126 
127 //密钥扩展 变换T*,基本同T
128 static unsigned long sm4CalciRK(unsigned long ka)
129 {
130     unsigned long bb = 0;
131     unsigned long rk = 0;
132     unsigned char a[4];
133     unsigned char b[4];
134     PUT_ULONG_BE(ka,a,0)
135     b[0] = sm4Sbox(a[0]);
136     b[1] = sm4Sbox(a[1]);
137     b[2] = sm4Sbox(a[2]);
138     b[3] = sm4Sbox(a[3]);
139     GET_ULONG_BE(bb,b,0)
140     rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));
141     return rk;
142 }
143 
144 //密钥扩展算法
145 static void sm4_setkey( unsigned long SK[32], unsigned char key[16] )
146 {
147     unsigned long MK[4];
148     unsigned long k[36];
149     unsigned long i = 0;
150 
151     GET_ULONG_BE( MK[0], key, 0 );
152     GET_ULONG_BE( MK[1], key, 4 );
153     GET_ULONG_BE( MK[2], key, 8 );
154     GET_ULONG_BE( MK[3], key, 12 );
155     k[0] = MK[0]^FK[0];
156     k[1] = MK[1]^FK[1];
157     k[2] = MK[2]^FK[2];
158     k[3] = MK[3]^FK[3];
159     for(; i<32; i++)
160     {
161         k[i+4] = k[i] ^ (sm4CalciRK(k[i+1]^k[i+2]^k[i+3]^CK[i]));
162         SK[i] = k[i+4];   //轮密钥
163     }
164 
165 }
166 
167 //输出
168 void sm4_print(unsigned char output[16]){
169     for(int i=0;i<16;i++) printf("%02x", output[i]);
170     printf("n");
171 }
172 
173 //32轮次轮函数的集成
174 static void sm4_one_round( unsigned long sk[32],unsigned char input[16],unsigned char output[16] )
175 {
176     unsigned long i = 0;
177     unsigned long ulbuf[36];
178 
179     memset(ulbuf, 0, sizeof(ulbuf));
180     GET_ULONG_BE( ulbuf[0], input, 0 )
181     GET_ULONG_BE( ulbuf[1], input, 4 )
182     GET_ULONG_BE( ulbuf[2], input, 8 )
183     GET_ULONG_BE( ulbuf[3], input, 12 )
184     while(i<32)
185     {
186         ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
187         PUT_ULONG_BE(ulbuf[i+1],output,0);
188         PUT_ULONG_BE(ulbuf[i+2],output,4);
189         PUT_ULONG_BE(ulbuf[i+3],output,8);
190         PUT_ULONG_BE(ulbuf[i+4],output,12);
191         i++;
192     }
193     PUT_ULONG_BE(ulbuf[35],output,0);
194     PUT_ULONG_BE(ulbuf[34],output,4);
195     PUT_ULONG_BE(ulbuf[33],output,8);
196     PUT_ULONG_BE(ulbuf[32],output,12);
197 }
198 
199 //设置加密密钥
200 void sm4_setkey_enc(unsigned long Sk[32], unsigned char key[16] )
201 {
202     sm4_setkey(Sk,key);  //计算出32子密钥
203 }
204 
205 //进行一轮128bit
206 void sm4_crypt_hash(unsigned long sk[32],unsigned char input[16],unsigned char output[16],unsigned char key[16])
207 {
208     unsigned char tmp[16];
209     memcpy(tmp,input,sizeof(unsigned char)*16);  //将input赋值给tmp
210     sm4_setkey_enc(sk,key); //得到子密钥
211     sm4_one_round(sk,tmp,output);  //对tmp进行SM4
212     for(int i=0;i<16;i++) key[i]=(unsigned char)(output[i]^input[i]);  //将加密后的数据与输入异或作为下一轮的密钥
213 }
214 
215 int main()
216 {
217     unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
218     unsigned char input[16],output[16],Ciph[16];
219     unsigned long sk[32];
220     string str;
221     cout<<"请输入明文:";
222     cin>>str;
223     append(str);
224     printX();
225     for(int j=0;j<16;j++) Ciph[j]=0x00;  //初始化为全零
226     for(int i=0;i<Turn*4;i++){
227         for(int j=0;j<16;j++) input[j]=X[16*i+j]; //从一组中选取128bit
228         sm4_crypt_hash(sk,input,output,key);
229         for(int j=0;j<16;j++) Ciph[j]=Ciph[j]^output[j];  //得到的结果与之前的输出异或
230     }
231 
232     cout<<"输出密文为:"<<endl;
233     sm4_print(Ciph);
234 
235     return 0;
236 }

四,实现截图

利用国密SM4算法构造hash函数——C++实现

 

原文链接: https://www.cnblogs.com/priester-three/p/12693193.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    利用国密SM4算法构造hash函数——C++实现

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/341946

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午1:20
下一篇 2023年3月2日 上午1:20

相关推荐