精华内容
下载资源
问答
  • 2021-12-23 23:03:39

    SM4算法分析与实现

    目录

    加密流程图点这里


    SM4算法简介

    SM4密码算法是一个分组算法。数据分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮迭代结构。SM4密码算法以字节(8位)和字(32位)为单位进行数据处理。SM4密码算法是对合运算,因此解密算法与加密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。


    SM4算法原理

    基本运算
    SM4密码算法使用模2加和循环移位作为基本运算。
    - 模2加:⊕,32位异或运算
    - 循环移位:<<< i,把32位字循环左移i位。

    基本密码部件

    • S盒

      SM4的S盒是一种以字节为单位的非线性代替变换,其密码学的作用起混淆作用。S盒的输入和输出都是8位的字节,它本质上是8位的非线性置换。设输入字节为a,输出字节为b,则S盒的运算可表示为:
      b = S b o x ( a ) b=Sbox(a) b=Sbox(a)
      S盒的代替规则如下表所示。例如,设S盒的输入为EF,则5盒的输出为表中第E行与第F列交点处的值84,即Sbox(EF)= 84
      在这里插入图片描述

    • 非线性变换τ

      SM4的非线性变换τ是一种以字为单位的非线性代替变换。它由4个S盒并置构成。本质上它是S盒的一种并行应用。

      设输入字为A=(a0,a1,a2,a3),输出字为B=(b0,b1,b2,b3),则
      B = τ ( A ) = ( S b o x ( a 0 ) , S b o x ( a 1 ) , S b o x ( a 2 ) , S b o x ( a 3 ) ) B=τ(A)=(Sbox(a_0),Sbox(a_1),Sbox(a_2),Sbox(a_3)) B=τ(A)=(Sbox(a0)Sbox(a1)Sbox(a2)Sbox(a3))

    • 线性变换部件L

      线性变换部件L是以字为处理单位的线性变换部件,其输入输出都是32位的字。其密码学的作用是起扩散的作用。
      设L的输入为字B,输出为字C,则
      C = L ( B ) = B ⊕ ( B < < < 2 ) ⊕ ( B < < < 10 ) ⊕ ( B < < < 18 ) ⊕ ( B < < < 24 ) C=L(B)=B⊕(B<<<2)⊕(B<<<10)⊕(B<<<18)⊕(B<<<24) C=L(B)=B(B<<<2)(B<<<10)(B<<<18)(B<<<24)

    • 合成变换T

      合成变换T由非线性变换τ和线性变换L复合而成,数据处理的单位是字。设输入为字,则先对X进行非线性τ变换,再进行线性L变换。记为
      T ( X ) = L ( τ ( X ) ) T(X) = L(τ(X)) T(X)=L(τ(X))
      由于合成变换T是非线性变换τ和线性变换L的复合,所以它综合起到混淆和扩散的作用,从而可提高密码的安全性。

    轮函数
    SM4密码算法采用对基本轮函数进行迭代的结构。利用上述基本密码部件,便可构成轮函数。SM4密码算法的轮函数是一种以字为处理单位的密码函数。
    设轮函数F的输入为(X0,X1,X2,X3),四个32位字,共128位。轮密钥为RK,RK也是一个32位的字。轮函数F的输出也是一个32位的字。轮函数F的运算如下:
    F ( X 0 , X 1 , X 2 , X 3 , R K ) = X 0 ⊕ T ( X 1 ⊕ X 2 ⊕ X 3 ⊕ R K ) F(X_0,X_1,X_2,X_3,RK)= X_0 ⊕ T(X_1 ⊕ X_2 ⊕ X_3 ⊕ RK) F(X0X1X2X3RK)=X0T(X1X2X3RK)

    加密算法

    SM4密码算法是一个分组算法。数据分组长度为128比特,密钥长度为128比特。加密算法采用32轮迭代结构,每轮使用一个轮密钥。
    设输入明文为(X0,X1,X2,X3),四个字,共128位。输入轮密钥为RKi,i=0,1,…,31,共32个字。输出密文为(Y0,Y1,Y2,Y3),四个字,128位。则加密算法可描述如下:
    X i + 4 = F ( X 1 , X i + 1 , X i + 2 , X i + 3 , R K i ) = X i ⊕ T ( X i + 1 ⊕ X i + 2 ⊕ X i + 3 ⊕ R K i ) ,   i = 0 , 1 , . . . , 31 X_{i+4}=F(X_1,X_{i+1},X_{i+2},X_{i+3},RKi)\\=X_i⊕T(X_{i+1}⊕X_{i+2}⊕X_{i+3}⊕RK_i),~i=0,1,...,31 Xi+4=F(X1Xi+1Xi+2Xi+3RKi)=XiT(Xi+1Xi+2Xi+3RKi), i=0,1,...,31
    为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序处理R:
    R ( Y 0 , Y 1 , Y 2 , Y 3 ) = ( X 35 , X 34 , X 33 , X 32 ) R(Y_0,Y_1,Y_2,Y_3) = (X_{35},X_{34},X_{33},X_{32}) R(Y0Y1Y2Y3)=(X35X34X33X32)

    加密算法的框图如图所示。

    在这里插入图片描述

    解密算法

    SM4密码算法是对合运算,因此解密算法与加密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
    设输入密文为(Y0,Y1,Y2,Y3),输入轮密钥为RKi,i=31,30,…1, 0,输出明文为(M0,M1,M2,M3),根据加密算法的R(Y0,Y1,Y2,Y3) = (X35,X34,X33,X32),为了方便与加密算法对照,在解密算法中仍然采用Xi表示密文。于是可得到如下的解密算法:
    X = F ( X i + 4 , X i + 3 , X i + 2 , X i + 1 , R K i ) = X i + 4 ⊕ T ( X i + 3 ⊕ X i + 2 ⊕ X i + 1 ⊕ R K i ) , i = 31 , 30 , . . . , 1 , 0 X = F(X_{i+4},X_{i+3},X_{i+2},X_{i+1},RK_i)\\ =X_{i+4} ⊕ T(X_{i+3} ⊕ X_{i+2} ⊕ X_{i+1} ⊕ RK_i), i=31,30,...,1,0 X=F(Xi+4Xi+3Xi+2Xi+1RKi)=Xi+4T(Xi+3Xi+2Xi+1RKi),i=31,30,...,1,0
    与加密算法之后需要一个反序处理同样的道理,在解密算法之后也需要一个反序处理R:
    R ( M 0 , M 1 , M 2 , M 3 ) = ( X 3 , X 2 , X 1 , X 0 ) R(M_0,M_1,M_2,M_3) = (X_3,X_2,X_1,X_0) R(M0M1M2M3)=(X3X2X1X0)

    密钥扩展算法
    SM4 密码算法使用128位的加密密钥,并采用32轮迭代加密结构,每一轮加密使用一个32位的轮密钥,共使用32个轮密钥。因此需要使用密钥扩展算法,从加密密钥产生出32个轮密钥。
    常数FK
    在密钥扩展中使用如下的常数:
    FK0 = (A3B1BAC6),FK1 = (56AA3350),FK2 = (677D9197),FK3 = (B27022DC)
    固定参数CK
    共使用32个固定参数如下(16进制):

    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 
    

    密钥扩展算法
    设输入加密密钥为MK(MK0,MK1,MK2,MK3),输出轮密钥为RKi, i=0,1,…,30,31,中间数据为Ki,i = 0,1,…,34,35,则密钥扩展算法可描述如下:
    ① ( K 0 , K 1 , K 2 , K 3 ) = ( M K 0 ⊕ F K 0 , M K 1 ⊕ F K 1 , M K 2 ⊕ F K 2 , M K 3 ⊕ F K 3 ) ② F o r   i = 0 , 1 , . . . , 30 , 31   D o   R K = K i ⊕ T ’ ( K i + 1 , K i + 2 , K i + 3 , C K i ) ①(K_0,K_1,K_2,K_3) = (MK_0 ⊕ FK_0, MK_1 ⊕ FK_1,MK_2 ⊕ FK_2,MK_3 ⊕ FK_3) \\ ②For~i = 0,1,...,30,31~Do~RK = Ki ⊕ T’(K_{i+1},K_{i+2},K_{i+3},CK_i) (K0K1K2K3)=(MK0FK0,MK1FK1MK2FK2MK3FK3)For i=0,1,...,30,31 Do RK=KiT(Ki+1Ki+2Ki+3CKi)
    说明:其中的T’变换与加密算法轮函数中的T基本相同,只将其中的线性变换L修改为以下的L’:
    L ’ ( B ) = B ⊕ ( B < < < 13 ) ⊕ ( B < < < 23 ) L’(B) = B ⊕ (B<<<13) ⊕ (B<<<23) L(B)=B(B<<<13)(B<<<23)


    SM4代码实现和测试
    1. 编程语言

      采用C语言,只使用了C语言库的stdio.h。

    2. 运行环境

      Windows10平台下的Dev-CPP5.11。

    3. 主要函数

      u32 functionB(u32 b); // 查S盒的函数B 
      u32 loopLeft(u32 a, short length); // 循环左移函数 
      u32 functionL1(u32 a); // 线性变换L
      u32 functionL2(u32 a); // 线性变换L'
      u32 functionT(u32 a, short mode); // 合成变换T
      void extendFirst(u32 MK[], u32 K[]); // 密钥扩展算法第一步
      void extendSecond(u32 RK[], u32 K[]); // 密钥扩展算法第二步
      void getRK(u32 MK[], u32 K[], u32 RK[]); // 轮密钥获取算法
      void iterate32(u32 X[], u32 RK[]); // 迭代算法
      void reverse(u32 X[], u32 Y[]); // 反转函数 
      void encryptSM4(u32 X[], u32 RK[], u32 Y[]); // 加密算法
      void decryptSM4(u32 X[], u32 RK[], u32 Y[]); // 解密算法
      

      3.1 查询S盒的函数B

      /*
        查S盒的函数B 
        参数: u32 b
        返回值:  查S盒的结果u32 b
      */ 
      u32 functionB(u32 b) {
        u8 a[4];
        short i;
        a[0] = b / 0x1000000;
        a[1] = b / 0x10000;
        a[2] = b / 0x100;
        a[3] = b;
        b = Sbox[a[0]] * 0x1000000 + Sbox[a[1]] * 0x10000 + Sbox[a[2]] * 0x100 + Sbox[a[3]];
        return b;
      }
      

      3.2 循环左移算法

      /*
        循环左移算法
        参数: u32 a  length:循环左移位数
        返回值:u32 b
      */
      u32 loopLeft(u32 a, short length) {
        short i;
        for(i = 0; i < length; i++) {
         	a = a * 2 + a / 0x80000000;
        }
        return a;
      }
      

      3.3 密钥线性变换函数L

      /* 
        密钥线性变换函数L
        参数: u32 a
        返回值:线性变换后的u32 a 
      */
      u32 functionL1(u32 a) {
        return a ^ loopLeft(a, 2) ^ loopLeft(a, 10) ^ loopLeft(a, 18) ^ loopLeft(a, 24);
      }
      

      3.4 密钥线性变换函数L’

      /* 
        密钥线性变换函数L'
        参数: u32 a
        返回值:移位操作后的u32 a 
      */
      u32 functionL2(u32 a) {
        return a ^ loopLeft(a, 13) ^ loopLeft(a, 23);
      }
      

      3.5 合成变换T

      /*
        合成变换T
        参数: u32 a  short mode:1表示明文的T,调用L;2表示密钥的T,调用L' 
        返回值:合成变换后的u32 a 
      */
      u32 functionT(u32 a, short mode) {
        return mode == 1 ? functionL1(functionB(a)) : functionL2(functionB(a));
      }
      

      3.6 密钥扩展算法第一步

      /* 
        密钥扩展算法第一步
        参数: MK[4]:密钥 K[4]:中间数据,保存结果  (FK[4]:常数) 
        返回值:无 
      */ 
      void extendFirst(u32 MK[], u32 K[]) {
        int i;
        for(i = 0; i < 4; i++) {
           K[i] = MK[i] ^ FK[i]; 
        } 
      }
      

      3.7 密钥扩展算法第二步

      /* 
        密钥扩展算法第二步
        参数: RK[32]:轮密钥,保存结果  K[4]:中间数据 (CK[32]:固定参数) 
        返回值:无
      */ 
      void extendSecond(u32 RK[], u32 K[]) {
        short i;
        for(i = 0; i <32; i++) {
           K[(i+4)%4] = K[i%4] ^ functionT(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i], 2);
           RK[i] = K[(i+4)%4];
        } 
      }
      

      3.8 密钥扩展算法

      /*
        密钥扩展算法 
        参数: MK[4]:密钥   K[4]:中间数据  RK[32]:轮密钥,保存结果 
        返回值:无 
      */ 
      void getRK(u32 MK[], u32 K[], u32 RK[]) {
        extendFirst(MK, K);
        extendSecond(RK, K);
      }
      

      3.9 迭代算法

      /*
        迭代32次
        参数: u32 X[4]:迭代对象,保存结果  u32 RK[32]:轮密钥
        返回值:无   
      */
      void iterate32(u32 X[], u32 RK[]) {
        short i;
        for(i = 0; i < 32; i++) {
           X[(i+4)%4] = X[i%4] ^ functionT(X[(i+1)%4] ^ X[(i+2)%4] ^ X[(i+3)%4] ^ RK[i], 1);
        }
      }
      

      3.10 反转函数

      /*
        反转函数 
        参数; u32 X[4]:反转对象  u32 Y[4]:反转结果
        返回值:无 
      */
      void reverse(u32 X[], u32 Y[]) {
         short i;
         for(i = 0; i < 4; i++){
          Y[i] = X[4 - 1 - i];
         } 
      } 
      

      3.11 加密算法

      /*
        加密算法
        参数: u32 X[4]:明文  u32 RK[32]:轮密钥  u32 Y[4]:密文,保存结果 
        返回值:无 
      */
      void encryptSM4(u32 X[], u32 RK[], u32 Y[]) {
        iterate32(X, RK);
        reverse(X, Y);
      } 
      

      3.12 解密算法

      /*
        解密算法
        参数:   u32 X[4]:密文  u32 RK[32]:轮密钥  u32 Y[4]:明文,保存结果
        返回值:无 
      */
      void decryptSM4(u32 X[], u32 RK[], u32 Y[]) {
        short i;
        u32 reverseRK[32];
        for(i = 0; i < 32; i++) {
           reverseRK[i] = RK[32-1-i];
        }
        iterate32(X, reverseRK);
        reverse(X, Y);
      }
      
    4. 测试数据

      数据来自《密码学引论》第三版武汉大学出版社中关于SM4算法的描述。

      明文:	01234567 89abcdef fedcba98 76543210
      密钥:	01234567 89abcdef fedcba98 76543210
      密文:	681edf34 d206965e 86b3e94f 536e4246
      
    5. 测试结果

    在这里插入图片描述


    完整代码
    #include<stdio.h>
    #define u8 unsigned char
    #define u32 unsigned long
    
    // S盒
    const u8 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
    };
    	
    // 密钥扩展算法的常数FK 
    const u32 FK[4] = {
    	0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
    };
    
    // 密钥扩展算法的固定参数CK 
    const u32 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
    };
    
    u32 functionB(u32 b); // 查S盒的函数B 
    u32 loopLeft(u32 a, short length); // 循环左移函数 
    u32 functionL1(u32 a); // 线性变换L
    u32 functionL2(u32 a); // 线性变换L'
    u32 functionT(u32 a, short mode); // 合成变换T
    void extendFirst(u32 MK[], u32 K[]); // 密钥扩展算法第一步
    void extendSecond(u32 RK[], u32 K[]); // 密钥扩展算法第二步
    void getRK(u32 MK[], u32 K[], u32 RK[]); // 轮密钥获取算法
    void iterate32(u32 X[], u32 RK[]); // 迭代算法
    void reverse(u32 X[], u32 Y[]); // 反转函数 
    void encryptSM4(u32 X[], u32 RK[], u32 Y[]); // 加密算法
    void decryptSM4(u32 X[], u32 RK[], u32 Y[]); // 解密算法
     
    /*
    	查S盒的函数B 
    	参数:	u32 b
    	返回值:	查S盒的结果u32 b
    */ 
    u32 functionB(u32 b) {
    	u8 a[4];
    	short i;
    	a[0] = b / 0x1000000;
    	a[1] = b / 0x10000;
    	a[2] = b / 0x100;
    	a[3] = b;
    	b = Sbox[a[0]] * 0x1000000 + Sbox[a[1]] * 0x10000 + Sbox[a[2]] * 0x100 + Sbox[a[3]];
    	return b;
    }
    
    /*
    	循环左移算法
    	参数:	u32 a    length:循环左移位数
    	返回值:u32 b 
    */
    u32 loopLeft(u32 a, short length) {
    	short i;
    	for(i = 0; i < length; i++) {
    		a = a * 2 + a / 0x80000000;
    	}
    	return a;
    }
    
    /* 
    	密钥线性变换函数L
    	参数:	u32 a
    	返回值:线性变换后的u32 a	
    */
    u32 functionL1(u32 a) {
    	return a ^ loopLeft(a, 2) ^ loopLeft(a, 10) ^ loopLeft(a, 18) ^ loopLeft(a, 24);
    }
    
    /* 
    	密钥线性变换函数L'
    	参数:	u32 a
    	返回值:移位操作后的u32 a	
    */
    u32 functionL2(u32 a) {
    	return a ^ loopLeft(a, 13) ^ loopLeft(a, 23);
    }
    
    /*
    	合成变换T
    	参数:	u32 a    short mode:1表示明文的T,调用L;2表示密钥的T,调用L' 
    	返回值:合成变换后的u32 a 
    */
    u32 functionT(u32 a, short mode) {
    	return mode == 1 ? functionL1(functionB(a)) : functionL2(functionB(a));
    }
     
    /* 
    	密钥扩展算法第一步
    	参数:	MK[4]:密钥  K[4]:中间数据,保存结果	(FK[4]:常数) 
    	返回值:无 
    */ 
    void extendFirst(u32 MK[], u32 K[]) {
    	int i;
    	for(i = 0; i < 4; i++) {
    		K[i] = MK[i] ^ FK[i]; 
    	} 
    }
    
    /* 
    	密钥扩展算法第二步
    	参数:	RK[32]:轮密钥,保存结果    K[4]:中间数据 (CK[32]:固定参数) 
    	返回值:无
    */ 
    void extendSecond(u32 RK[], u32 K[]) {
    	short i;
    	for(i = 0; i <32; i++) {
    		K[(i+4)%4] = K[i%4] ^ functionT(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i], 2);
    		RK[i] = K[(i+4)%4];
    	} 
    }
    
    /*
    	密钥扩展算法 
    	参数:	MK[4]:密钥     K[4]:中间数据    RK[32]:轮密钥,保存结果 
    	返回值:无 
    */ 
    void getRK(u32 MK[], u32 K[], u32 RK[]) {
    	extendFirst(MK, K);
    	extendSecond(RK, K);
    }
    
    /*
    	迭代32次
    	参数:	u32 X[4]:迭代对象,保存结果    u32 RK[32]:轮密钥
    	返回值:无	  
    */
    void iterate32(u32 X[], u32 RK[]) {
    	short i;
    	for(i = 0; i < 32; i++) {
    		X[(i+4)%4] = X[i%4] ^ functionT(X[(i+1)%4] ^ X[(i+2)%4] ^ X[(i+3)%4] ^ RK[i], 1);
    	}
    }
    
    /*
    	反转函数 
    	参数;	u32 X[4]:反转对象    u32 Y[4]:反转结果
    	返回值:无 
    */
    void reverse(u32 X[], u32 Y[]) {
    	 short i;
    	 for(i = 0; i < 4; i++){
    	 	Y[i] = X[4 - 1 - i];
    	 } 
    } 
    
    /*
    	加密算法
    	参数:	u32 X[4]:明文    u32 RK[32]:轮密钥    u32 Y[4]:密文,保存结果 
    	返回值:无 
    */
    void encryptSM4(u32 X[], u32 RK[], u32 Y[]) {
    	iterate32(X, RK);
    	reverse(X, Y);
    } 
    
    /*
    	解密算法
    	参数: 	u32 X[4]:密文    u32 RK[32]:轮密钥    u32 Y[4]:明文,保存结果
    	返回值:无 
    */
    void decryptSM4(u32 X[], u32 RK[], u32 Y[]) {
    	short i;
    	u32 reverseRK[32];
    	for(i = 0; i < 32; i++) {
    		reverseRK[i] = RK[32-1-i];
    	}
    	iterate32(X, reverseRK);
    	reverse(X, Y);
    }
     
    /*
    	测试数据:
    	明文:	01234567 89abcdef fedcba98 76543210
    	密钥:	01234567 89abcdef fedcba98 76543210
    	密文:	681edf34 d206965e 86b3e94f 536e4246 
    */
    int main(void) {
    	u32 X[4]; // 明文 
    	u32 MK[4]; // 密钥 
    	u32 RK[32]; // 轮密钥  
    	u32 K[4]; // 中间数据 
    	u32 Y[4]; // 密文 
    	short i; // 临时变量 
    	printf("明文:"); 
    	scanf("%8x%8x%8x%8x", &X[0], &X[1], &X[2], &X[3]);
    	printf("密钥:"); 
    	scanf("%8x%8x%8x%8x", &MK[0], &MK[1], &MK[2], &MK[3]);
    	printf("**************生成轮密钥*****************\n"); 
    	getRK(MK, K, RK);
    	for(i = 0; i < 32; i++) {
    		printf("[%2d]:%08x    ", i, RK[i]);
    		if(i%4 == 3)	printf("\n"); 
    	}
    	printf("************** 生成密文 *****************\n"); 
    	encryptSM4(X, RK, Y);
    	printf("%08x %08x %08x %08x\n", Y[0], Y[1], Y[2], Y[3]);
    	printf("************** 生成明文 *****************\n");  
    	decryptSM4(Y, RK, X);
    	printf("%08x %08x %08x %08x\n", X[0], X[1], X[2], X[3]);
    	return 0;	
    } 
    
    更多相关内容
  • SM4算法 C语言 (从OpenSSL库中分离算法:七) OpenSSL简介: OpenSSL 是用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的一个强大、商业级和功能齐全的工具包,它也是一个通用的密码学库。包含有RSA、SM4、DES、...

    SM4算法 C语言 (从OpenSSL库中分离算法:七)

    OpenSSL简介:

    OpenSSL 是用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的一个强大、商业级和功能齐全的工具包,它也是一个通用的密码学库。包含有RSA、SM4、DES、AES等诸多加密算法。

    OpenSSL GitHub地址如下:

    GitHub - openssl/openssl: TLS/SSL and crypto library

    在日常的开发工作中,有时只想用OpenSSL库中的一种算法,此时调用整个OpenSSL库,往往是没必要的;再或者在嵌入式平台使用某一算法,那我们只移植这个算法,没有必要移植整个OpenSSL库。

    SM4简介

    SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。

    移植过程

    一、下载代码

    从OpenSSL的Github仓库下载代码,可以下载master分支,也可以下载最新的release版本。将下载的文件解压,得到代码。

    重点关注红框目录:

    • crypto目录内是各种加密算法
    • include目录内是各加密算法对外接口的头文件

    在这里插入图片描述

    二、准备环境

    新建Visual Studio C++ 控制台项目"sm4test",编译选项是:x86\Debug

    在这里插入图片描述

    在这里插入图片描述

    三、准备文件

    1. 复制OpenSSL源码中:/crypto/sm4文件夹到VS工程代码目录下
    2. 复制OpenSSL源码中:/include/crypto/sm4.h文件到VS工程代码目录中sm4文件夹内
    3. 复制完成后,VS工程代码目录sm4文件夹内文件如下:

    在这里插入图片描述

    删除目录内的如下本项目中无用文件:

    • build.info

    四、修改代码

    修改调用文件

    在VS工程中含有main函数的主文件:sm4test.cpp中,增加包含sm4.h头文件

    #include "sm4/sm4.h"
    

    在main函数中添加如下代码

    const char* Sm4Key = "12345678";
    SM4_KEY key;
    ossl_sm4_set_key((const unsigned char* )Sm4Key, & key);
    
    const char* indata = "0123456789ABCDEF";
    unsigned char Encrydata[256] = { 0 };
    
    //该函数每次加密128bit分组,即16字节,需自行补齐、分组
    ossl_sm4_encrypt((unsigned char*)indata, Encrydata, &key);
    
    unsigned char Decrydata[256] = { 0 };
    SM4_KEY key2;
    ossl_sm4_set_key((const unsigned char*)Sm4Key, &key2);
    ossl_sm4_decrypt((unsigned char*)Encrydata, Decrydata, &key2);
    
    

    修改后的sm4test.cpp代码如下:

    #include <iostream>
    #include "sm4/sm4.h"
    int main()
    {
        const char* Sm4Key = "12345678";
        SM4_KEY key;
        ossl_sm4_set_key((const unsigned char* )Sm4Key, & key);
    
        const char* indata = "0123456789ABCDEF";
        unsigned char Encrydata[256] = { 0 };
    
        //该函数每次加密128bit分组,即16字节,需自行补齐、分组
        ossl_sm4_encrypt((unsigned char*)indata, Encrydata, &key);
    
        unsigned char Decrydata[256] = { 0 };
        SM4_KEY key2;
        ossl_sm4_set_key((const unsigned char*)Sm4Key, &key2);
        ossl_sm4_decrypt((unsigned char*)Encrydata, Decrydata, &key2);
    }
    

    修改sm4.h

    删除条件编译 OSSL_CRYPTO_SM4_H

    删除头文件# include <openssl/opensslconf.h>

    删除头文件# include <openssl/e_os2.h>

    删除条件编译 OPENSSL_NO_SM4

    添加头文件#include <stdint.h>

    添加C++调用时的宏

    修改或删除后的文件如下:

    # pragma once
    #  ifdef  __cplusplus
    extern "C" {
    #  endif
    
    #include <stdint.h>
    
    # define SM4_DIGEST_LENGTH 32
    # define SM4_WORD unsigned int
    
    # define SM4_CBLOCK      64
    # define SM4_LBLOCK      (SM4_CBLOCK/4)
    
    typedef struct SM4state_st {
    	SM4_WORD A, B, C, D, E, F, G, H;
    	SM4_WORD Nl, Nh;
    	SM4_WORD data[SM4_LBLOCK];
    	unsigned int num;
    } SM4_CTX;
    
    int ossl_SM4_init(SM4_CTX* c);
    int ossl_SM4_update(SM4_CTX* c, const void* data, size_t len);
    int ossl_SM4_final(unsigned char* md, SM4_CTX* c);
    
    #  ifdef  __cplusplus
    }
    #  endif
    

    修改sm4.c

    删除头文件#include <openssl/e_os2.h>

    修改头文件# include "crypto/sm4.h"改为#include "sm4.h"

    添加宏定义 #define ossl_inline inline

    修改或删除后的文件如下:

    #include "sm4.h"
    
    #define ossl_inline inline
    
    static const uint8_t SM4_S[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
    };
    
    /*
     * SM4_SBOX_T[j] == L(SM4_SBOX[j]).
     */
    static const uint32_t SM4_SBOX_T[256] = {
        0x8ED55B5B, 0xD0924242, 0x4DEAA7A7, 0x06FDFBFB, 0xFCCF3333, 0x65E28787,
        0xC93DF4F4, 0x6BB5DEDE, 0x4E165858, 0x6EB4DADA, 0x44145050, 0xCAC10B0B,
        0x8828A0A0, 0x17F8EFEF, 0x9C2CB0B0, 0x11051414, 0x872BACAC, 0xFB669D9D,
        0xF2986A6A, 0xAE77D9D9, 0x822AA8A8, 0x46BCFAFA, 0x14041010, 0xCFC00F0F,
        0x02A8AAAA, 0x54451111, 0x5F134C4C, 0xBE269898, 0x6D482525, 0x9E841A1A,
        0x1E061818, 0xFD9B6666, 0xEC9E7272, 0x4A430909, 0x10514141, 0x24F7D3D3,
        0xD5934646, 0x53ECBFBF, 0xF89A6262, 0x927BE9E9, 0xFF33CCCC, 0x04555151,
        0x270B2C2C, 0x4F420D0D, 0x59EEB7B7, 0xF3CC3F3F, 0x1CAEB2B2, 0xEA638989,
        0x74E79393, 0x7FB1CECE, 0x6C1C7070, 0x0DABA6A6, 0xEDCA2727, 0x28082020,
        0x48EBA3A3, 0xC1975656, 0x80820202, 0xA3DC7F7F, 0xC4965252, 0x12F9EBEB,
        0xA174D5D5, 0xB38D3E3E, 0xC33FFCFC, 0x3EA49A9A, 0x5B461D1D, 0x1B071C1C,
        0x3BA59E9E, 0x0CFFF3F3, 0x3FF0CFCF, 0xBF72CDCD, 0x4B175C5C, 0x52B8EAEA,
        0x8F810E0E, 0x3D586565, 0xCC3CF0F0, 0x7D196464, 0x7EE59B9B, 0x91871616,
        0x734E3D3D, 0x08AAA2A2, 0xC869A1A1, 0xC76AADAD, 0x85830606, 0x7AB0CACA,
        0xB570C5C5, 0xF4659191, 0xB2D96B6B, 0xA7892E2E, 0x18FBE3E3, 0x47E8AFAF,
        0x330F3C3C, 0x674A2D2D, 0xB071C1C1, 0x0E575959, 0xE99F7676, 0xE135D4D4,
        0x661E7878, 0xB4249090, 0x360E3838, 0x265F7979, 0xEF628D8D, 0x38596161,
        0x95D24747, 0x2AA08A8A, 0xB1259494, 0xAA228888, 0x8C7DF1F1, 0xD73BECEC,
        0x05010404, 0xA5218484, 0x9879E1E1, 0x9B851E1E, 0x84D75353, 0x00000000,
        0x5E471919, 0x0B565D5D, 0xE39D7E7E, 0x9FD04F4F, 0xBB279C9C, 0x1A534949,
        0x7C4D3131, 0xEE36D8D8, 0x0A020808, 0x7BE49F9F, 0x20A28282, 0xD4C71313,
        0xE8CB2323, 0xE69C7A7A, 0x42E9ABAB, 0x43BDFEFE, 0xA2882A2A, 0x9AD14B4B,
        0x40410101, 0xDBC41F1F, 0xD838E0E0, 0x61B7D6D6, 0x2FA18E8E, 0x2BF4DFDF,
        0x3AF1CBCB, 0xF6CD3B3B, 0x1DFAE7E7, 0xE5608585, 0x41155454, 0x25A38686,
        0x60E38383, 0x16ACBABA, 0x295C7575, 0x34A69292, 0xF7996E6E, 0xE434D0D0,
        0x721A6868, 0x01545555, 0x19AFB6B6, 0xDF914E4E, 0xFA32C8C8, 0xF030C0C0,
        0x21F6D7D7, 0xBC8E3232, 0x75B3C6C6, 0x6FE08F8F, 0x691D7474, 0x2EF5DBDB,
        0x6AE18B8B, 0x962EB8B8, 0x8A800A0A, 0xFE679999, 0xE2C92B2B, 0xE0618181,
        0xC0C30303, 0x8D29A4A4, 0xAF238C8C, 0x07A9AEAE, 0x390D3434, 0x1F524D4D,
        0x764F3939, 0xD36EBDBD, 0x81D65757, 0xB7D86F6F, 0xEB37DCDC, 0x51441515,
        0xA6DD7B7B, 0x09FEF7F7, 0xB68C3A3A, 0x932FBCBC, 0x0F030C0C, 0x03FCFFFF,
        0xC26BA9A9, 0xBA73C9C9, 0xD96CB5B5, 0xDC6DB1B1, 0x375A6D6D, 0x15504545,
        0xB98F3636, 0x771B6C6C, 0x13ADBEBE, 0xDA904A4A, 0x57B9EEEE, 0xA9DE7777,
        0x4CBEF2F2, 0x837EFDFD, 0x55114444, 0xBDDA6767, 0x2C5D7171, 0x45400505,
        0x631F7C7C, 0x50104040, 0x325B6969, 0xB8DB6363, 0x220A2828, 0xC5C20707,
        0xF531C4C4, 0xA88A2222, 0x31A79696, 0xF9CE3737, 0x977AEDED, 0x49BFF6F6,
        0x992DB4B4, 0xA475D1D1, 0x90D34343, 0x5A124848, 0x58BAE2E2, 0x71E69797,
        0x64B6D2D2, 0x70B2C2C2, 0xAD8B2626, 0xCD68A5A5, 0xCB955E5E, 0x624B2929,
        0x3C0C3030, 0xCE945A5A, 0xAB76DDDD, 0x867FF9F9, 0xF1649595, 0x5DBBE6E6,
        0x35F2C7C7, 0x2D092424, 0xD1C61717, 0xD66FB9B9, 0xDEC51B1B, 0x94861212,
        0x78186060, 0x30F3C3C3, 0x897CF5F5, 0x5CEFB3B3, 0xD23AE8E8, 0xACDF7373,
        0x794C3535, 0xA0208080, 0x9D78E5E5, 0x56EDBBBB, 0x235E7D7D, 0xC63EF8F8,
        0x8BD45F5F, 0xE7C82F2F, 0xDD39E4E4, 0x68492121 };
    
    static ossl_inline uint32_t rotl(uint32_t a, uint8_t n)
    {
        return (a << n) | (a >> (32 - n));
    }
    
    static ossl_inline uint32_t load_u32_be(const uint8_t *b, uint32_t n)
    {
        return ((uint32_t)b[4 * n] << 24) |
               ((uint32_t)b[4 * n + 1] << 16) |
               ((uint32_t)b[4 * n + 2] << 8) |
               ((uint32_t)b[4 * n + 3]);
    }
    
    static ossl_inline void store_u32_be(uint32_t v, uint8_t *b)
    {
        b[0] = (uint8_t)(v >> 24);
        b[1] = (uint8_t)(v >> 16);
        b[2] = (uint8_t)(v >> 8);
        b[3] = (uint8_t)(v);
    }
    
    static ossl_inline uint32_t SM4_T_slow(uint32_t X)
    {
        uint32_t t = 0;
    
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 24)]) << 24;
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 16)]) << 16;
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 8)]) << 8;
        t |= SM4_S[(uint8_t)X];
    
        /*
         * L linear transform
         */
        return t ^ rotl(t, 2) ^ rotl(t, 10) ^ rotl(t, 18) ^ rotl(t, 24);
    }
    
    static ossl_inline uint32_t SM4_T(uint32_t X)
    {
        return SM4_SBOX_T[(uint8_t)(X >> 24)] ^
               rotl(SM4_SBOX_T[(uint8_t)(X >> 16)], 24) ^
               rotl(SM4_SBOX_T[(uint8_t)(X >> 8)], 16) ^
               rotl(SM4_SBOX_T[(uint8_t)X], 8);
    }
    
    int ossl_sm4_set_key(const uint8_t *key, SM4_KEY *ks)
    {
        /*
         * Family Key
         */
        static const uint32_t FK[4] =
            { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };
    
        /*
         * Constant Key
         */
        static const uint32_t 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
        };
    
        uint32_t K[4];
        int i;
    
        K[0] = load_u32_be(key, 0) ^ FK[0];
        K[1] = load_u32_be(key, 1) ^ FK[1];
        K[2] = load_u32_be(key, 2) ^ FK[2];
        K[3] = load_u32_be(key, 3) ^ FK[3];
    
        for (i = 0; i != SM4_KEY_SCHEDULE; ++i) {
            uint32_t X = K[(i + 1) % 4] ^ K[(i + 2) % 4] ^ K[(i + 3) % 4] ^ CK[i];
            uint32_t t = 0;
    
            t |= ((uint32_t)SM4_S[(uint8_t)(X >> 24)]) << 24;
            t |= ((uint32_t)SM4_S[(uint8_t)(X >> 16)]) << 16;
            t |= ((uint32_t)SM4_S[(uint8_t)(X >> 8)]) << 8;
            t |= SM4_S[(uint8_t)X];
    
            t = t ^ rotl(t, 13) ^ rotl(t, 23);
            K[i % 4] ^= t;
            ks->rk[i] = K[i % 4];
        }
    
        return 1;
    }
    
    #define SM4_RNDS(k0, k1, k2, k3, F)          \
          do {                                   \
             B0 ^= F(B1 ^ B2 ^ B3 ^ ks->rk[k0]); \
             B1 ^= F(B0 ^ B2 ^ B3 ^ ks->rk[k1]); \
             B2 ^= F(B0 ^ B1 ^ B3 ^ ks->rk[k2]); \
             B3 ^= F(B0 ^ B1 ^ B2 ^ ks->rk[k3]); \
          } while(0)
    
    void ossl_sm4_encrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
    {
        uint32_t B0 = load_u32_be(in, 0);
        uint32_t B1 = load_u32_be(in, 1);
        uint32_t B2 = load_u32_be(in, 2);
        uint32_t B3 = load_u32_be(in, 3);
    
        /*
         * Uses byte-wise sbox in the first and last rounds to provide some
         * protection from cache based side channels.
         */
        SM4_RNDS( 0,  1,  2,  3, SM4_T_slow);
        SM4_RNDS( 4,  5,  6,  7, SM4_T);
        SM4_RNDS( 8,  9, 10, 11, SM4_T);
        SM4_RNDS(12, 13, 14, 15, SM4_T);
        SM4_RNDS(16, 17, 18, 19, SM4_T);
        SM4_RNDS(20, 21, 22, 23, SM4_T);
        SM4_RNDS(24, 25, 26, 27, SM4_T);
        SM4_RNDS(28, 29, 30, 31, SM4_T_slow);
    
        store_u32_be(B3, out);
        store_u32_be(B2, out + 4);
        store_u32_be(B1, out + 8);
        store_u32_be(B0, out + 12);
    }
    
    void ossl_sm4_decrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
    {
        uint32_t B0 = load_u32_be(in, 0);
        uint32_t B1 = load_u32_be(in, 1);
        uint32_t B2 = load_u32_be(in, 2);
        uint32_t B3 = load_u32_be(in, 3);
    
        SM4_RNDS(31, 30, 29, 28, SM4_T_slow);
        SM4_RNDS(27, 26, 25, 24, SM4_T);
        SM4_RNDS(23, 22, 21, 20, SM4_T);
        SM4_RNDS(19, 18, 17, 16, SM4_T);
        SM4_RNDS(15, 14, 13, 12, SM4_T);
        SM4_RNDS(11, 10,  9,  8, SM4_T);
        SM4_RNDS( 7,  6,  5,  4, SM4_T);
        SM4_RNDS( 3,  2,  1,  0, SM4_T_slow);
    
        store_u32_be(B3, out);
        store_u32_be(B2, out + 4);
        store_u32_be(B1, out + 8);
        store_u32_be(B0, out + 12);
    }
    
    

    五、编译运行

    将sm4.h,sm4.c文件,配置添加到VS工程中。

    编译运行,通过内存观察加解密情况

    Encrydata: 内存是密文

    Decrydata:内存是明文,值等于indata

    上述算法,适用于对算字符串、缓冲区进行加解密,但要求数据分组大小为16字节的整数倍,当数据大小符合16字节整数倍时,能做到加密前后数据长度不变。

    对于如何支持动态长度(非16字节整数倍)的情况,可在当前工程基础上进行扩展,使其支持任意长度的加解密,具体方案可参考后续博客。

    欢迎大家关注、留言讨论、可分享源码

    展开全文
  • SM4 C语言实现

    2018-11-20 16:23:54
    SM4C语言实现,简单明了,有例子,可在Linux 下编译运行。
  • 实现了商密SM4算法,包括加密解密功能。符合GM/T 0002-2012《SM4分组密码算法》要求。替代DES、AES等国际算法
  • C语言实现国密SM4对称加解密算法。编译环境:VS2010。请参考我的博客https://blog.csdn.net/u013073067/article/details/86578753 分析代码
  • 基于Miracl大数运算库实现SM2算法,包含加密和签名算法,纯C语言实现,包含Miracl库手册。提供了Linux平台下的Makefile文件,可直接运行。Windows平台需要重新建立项目工程。
  • SM2SM3SM4国密算法C语言实现VS2015 还包含以下文本档可以学习 SM2椭圆曲线公钥密码算法 SM2椭圆曲线公钥密码算法推荐曲线参数 SM3密码杂凑算法 SM4分组密码算法
  • SM3算法及HMAC<SM3>算法C语言实现。内附详细测试例程。 SM3测试数据取自 GMT 0004-2012 HMAC测试数据来自Crypto++ 源文件列表: test.cpp sm3.cpp sm3.h 包含测试工程: VC++6.0, VC++2008, VC++2013, CentOS7-x64+...
  • SM2/SM3算法C语言实现

    2018-06-06 20:07:24
    1、完整的SM2/SM3算法C语言实现,可用于扫码POS安全认证; 2、SM2加密/解密、SM2签名/验签 3、内含测试程序,在Linux环境下进入目录后make即可编译,已经在ubuntu16.04环境下编译测试OK; 4、已经在银行卡检测中心...
  • SM3算法 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

    在这里插入图片描述
    在这里插入图片描述

    三、准备文件

    1. 复制OpenSSL源码中:/crypto/sm3文件夹到VS工程代码目录下
    2. 复制OpenSSL源码中:/include/internal/sm3.h文件到VS工程代码目录中sm3文件夹内
    3. 复制OpenSSL源码中:/include/crypto/md32_common.h文件到VS工程代码目录中sm3文件夹内
    4. 复制完成后,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非常相似。

    小文件MD5计算

    大文件MD5计算

    欢迎大家关注、留言讨论、可分享源码

    展开全文
  • SM4国密加密算法C语言实现 包括 Spec,C代码,测试用例和分组密码有五种工作体制:1.电码本模式(Electronic Codebook Book (ECB));2.密码分组链接模式(Cipher Block Chaining (CBC));3.计算器模式(Counter ...
  • SM4.0 (原名SMS4.0)是 中华人民共和国政府 采用的一种 分组密码 标准,SM4主要用于 数据加密 ,其算法公开,分组长度与密钥长度均为128bit, 加密算法 与密钥扩展算法都采用32轮非线性迭代结构, S盒 为固定的8...

    按照剧本来说,应该更新pwm的,但是调频率那里出现了问题,再加上马上有个比赛要调GSM,所以我决定把pwm再鸽亿鸽,下一篇更新GSM。

    PS:不是像其他博主一样从官网例程上扒下来的啊,这是自己写完自己讲,官方例程用的指针对小白太不友好了


    前言

    SM4.0 (原名SMS4.0)是 中华人民共和国政府 采用的一种 分组密码 标准,SM4主要用于 数据加密 ,其算法公开,分组长度与密钥长度均为128bit, 加密算法 与密钥扩展算法都采用32轮非线性迭代结构, S盒 为固定的8比特输入8比特输出。

    吧啦吧啦一大段,其实就是一个小小的加密算法罢了。我们只需要知道它是一个分组算法,分组长度为128比特,秘钥长度为128比特。加密算法与扩展秘钥算法都采用32轮非线性迭代结构。


    一、术语解析

    1.S盒

    S盒为固定的8比特输入8比特输出的置换,记为Sbox(.)。

    2.基本运算

    在本算法中采用了以下基本运算:
    ⊕ 32比特异或
    <<<i 32比特循环左移i位

    3.密钥及密钥参量

    加密密钥长度为128比特,表示为MK=(MK0, MK1, MK2, MK3),其中MKi(i=0,1,2,3)为字。
    轮密钥表示为(rk0, rk1, …, rk31),其中rki(i=0,…,31)为字。轮密钥由加密密钥生成。
    FK=(FK0, FK1, FK2, FK3)为系统参数,CK=(CK0, CK1,…, CK31)为固定参数,用于密钥扩展算法,其中FKi(i=0,…,3)、CKi(i=0,…,31)为字。

    4.太多了不想写了,自己在网上搜索吧

    http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A

    二、实现SM4

    相信大家看完pdf后都有点自己的想法,可以先自己尝试着写写,最后再来看看我的写法

    先用静态变量引入系统参数(S盒,CK,FK):

    static const unsigned char Sbox[16][16] = 
    {
    {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}
    };
    
    static const unsigned long 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
    };
    
    
    static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};
    
    

    因为我们不用指针和结构体,那么我们直接生成连个全局变量记录轮秘钥rk和plain明文来调用

    long rk[32];
    long plain[4];
    

    我们先来写这个32比特循环左移i位,区分<<
    在这里插入图片描述

    unsigned long Change_Place(unsigned long In,int Num)
    {
    	long temp;
    	temp = (In << Num) | (In >> (32-Num));
    	return temp;	
    }
    

    简单明了,入口参数就是需要循环异或的数我用了long正好是32位,注意了,这里一定要加上unsigned,证明它是无符号的。否则就会出现这样的状况:当最高位是1的时候,系统就会认为是负数,这样就会出大问题。

    根据SM算法的意思,我们应该把明文分成4组合成4个32位的秘钥MK
    在这里插入图片描述
    那么我们再写一个生成MK的函数

    unsigned long chang_place1(unsigned long in1,unsigned long in2,unsigned long in3,unsigned long in4)
    {
    	long temp = 0;
    	temp =(in1 << 24) | (in2 << 16) | (in3 << 8) | in4 ;
    	return temp;
    }
    
    

    简单得都不知道该怎样解释了。。。我们核心步骤是要求出rk轮秘钥。
    在这里插入图片描述
    那么我们就得先生成4个k

    	for(i=0;i<4;i++)
    	{
    		k[i] = MK[i] ^ (FK[i]);
    	}
    

    我们看到,生成rk需要T’变换,而T’变换需要L’变换,而L’变换的入口参数是t返回值,那我们先写一个t变换,也就是查S盒:

    unsigned int TransSbox(unsigned int temp)
    {
    	return Sbox[temp>>4][temp&0xf];
    }
    

    问题又出现了啊,这里查s盒用的是int,也就是高4位和低四位代表了行和列。可是我们MK秘钥是long型的,怎样才能输入进去呢?
    所以我们再写一个转换的函数:

    unsigned long TransSboxl(unsigned long In)
    {
    	long temp = 0;
    	temp |= (unsigned long)TransSbox((unsigned int)(In >> 24) & 0xff);
    	temp <<= 8;
    	temp |= (unsigned long)TransSbox((unsigned int)(In >> 16) & 0xff);
    	temp <<= 8;
    	temp |= (unsigned long)TransSbox((unsigned int)(In >> 8) & 0xff);
    	temp <<= 8;
    	temp |= (unsigned long)TransSbox((unsigned int)In & 0xff);
    	return temp;
    }
    

    我们把输入的32位先向右移24位,然后强制转换成int类型,取低八位,这样就能从S盒中找到转换出来的数了,接着再把int转换成long型,向左移8位,位下一次的找S盒留出位置。总共进行4次,这样我们就把一个32位MK的4个S盒找完了。

    看到这里我建议大家先停一停,仔细思考思考这一步。

    好了,接下来就可以写L’变换了
    在这里插入图片描述

    unsigned long TransL_1 (unsigned long temp)
    {
    	return temp ^ Change_Place(temp, 13) ^ Change_Place(temp, 23);
    }
    

    接下来就能直接写T’变换了

    unsigned long TransT_1(unsigned long temp)
    {
    	return TransL_1(TransSboxl(temp));
    }
    

    简简单单,那么我后文就直接吧T变换拿出来了,因为T变换和T’变换原理是差不多的。

    写到这里,我们核心步骤rk就能求出来了:

    unsigned long KeyExp(unsigned long MK[4])
    {
    	int i=0;
    	long k[4];
    	
    	for(i=0;i<4;i++)
    	{
    		k[i] = MK[i] ^ (FK[i]);
    	}
    	
    	rk[0] = k[0]^TransT_1(k[1] ^ k[2] ^ k[3] ^ CK[0]);
    	rk[1] = k[1]^TransT_1(k[2] ^ k[3] ^ rk[0] ^ CK[1]);
    	rk[2] = k[2]^TransT_1(k[3] ^ rk[0] ^ rk[1] ^ CK[2]);
    	rk[3] = k[3]^TransT_1(rk[0] ^ rk[1] ^ rk[2] ^ CK[3]);
    	
    	for(i=4;i<32;i++)
    	{
    	rk[i] = rk[i-4]^TransT_1(rk[i-3] ^ rk[i-2] ^ rk[i-1] ^ CK[i]);		
    	}
    	
    }
    

    接下来就可以进行加密运算(解密我就不写了,只需要把轮秘钥顺序换一下就行了,大家可以当做练习)
    在这里插入图片描述
    我们是不是轮函数还没写?得到轮函数的入口参数需要一次T变换,那我们直接拿出T变换:

    unsigned long TransT(unsigned long temp)
    {
    	return TransL(TransSboxl(temp));
    }
    
    unsigned long TransL (unsigned long temp)
    {
    	return temp ^ Change_Place(temp, 2) ^ Change_Place(temp, 10) ^ Change_Place(temp, 18) ^ Change_Place(temp, 24) ;
    }
    

    好了这样我们就拥有F轮函数的入口参数了,直接写轮函数:

    unsigned long F(unsigned long X0,unsigned long X1,unsigned long X2,unsigned long X3,unsigned long rk)
    {
    	return X0 ^ TransT(X1^X2^X3^rk);
    }
    

    接下来的工作就是进行32轮运算,得出最后四个,然后换位置。

    	for(i=0;i<32;i++)
    	{
    		temp = F(plain[0],plain[1],plain[2],plain[3],rk[i]);
    		plain[0]=plain[1];
    		plain[1]=plain[2];
    		plain[2]=plain[3];
    		plain[3]=temp;
    		printf("X%d=%x\n",i,temp);
    	}
    	
    	temp = plain[0];
    	plain[0] = plain[3];
    	plain[3] = temp;
    	temp = plain[1];
    	plain[1] = plain[2];
    	plain[2] = temp;
    

    所以加密的算法就写出来了:

    unsigned long get_sm4(unsigned long x[4],unsigned long MK[4])
    {
    	long temp;
    	int i;
    	KeyExp(MK);
    	
    	printf("rk:\n");
    	for(i=0;i<32;i++)
    	{
    		printf("rk%d = %x\n",i,rk[i]);
    	}
    	
    	for(i=0;i<4;i++)
    	{
    		plain[i] = x[i];
    	}
    	
    	for(i=0;i<32;i++)
    	{
    		temp = F(plain[0],plain[1],plain[2],plain[3],rk[i]);
    		plain[0]=plain[1];
    		plain[1]=plain[2];
    		plain[2]=plain[3];
    		plain[3]=temp;
    		printf("X%d=%x\n",i,temp);
    	}
    	
    	temp = plain[0];
    	plain[0] = plain[3];
    	plain[3] = temp;
    	temp = plain[1];
    	plain[1] = plain[2];
    	plain[2] = temp;
    	
    }
    
    

    写我们的主函数

    int main() 
    {
    	int i;
    	long stringkey[]={0x01,0x23,0x45,0x67,
    					  0x89,0xab,0xcd,0xef,
    					  0xfe,0xdc,0xba,0x98,
    					  0x76,0x54,0x32,0x10};
    	long MK[4];
    	long Pln[4];
    	long temp[4];
    	
    	MK[0]=chang_place1(stringkey[0],stringkey[1],stringkey[2],stringkey[3]);
    	MK[1]=chang_place1(stringkey[4],stringkey[5],stringkey[6],stringkey[7]);
    	MK[2]=chang_place1(stringkey[8],stringkey[9],stringkey[10],stringkey[11]);
    	MK[3]=chang_place1(stringkey[12],stringkey[13],stringkey[14],stringkey[15]);
    	
    	printf("明文为\n");
    	for(i=0;i<4;i++)
    	{
    		Pln[i]=MK[i];
    		printf("%x\n",MK[i]);
    	}
    	 get_sm4(Pln,MK);
    	
    	printf("密文为\n%x\n%x\n%x\n%x",plain[0],plain[1],plain[2],plain[3]);
    }
    

    总结

    网上大多例程都是运用指针,而指针对于学习来说就太离谱了,可读性极低。刚好我们实验室考核就是SM4国密算法,那么我就将我这比较容易懂的写法分享给大家。这个思维就像是我直接奔着目标加密去,过程中需要什么,我就补上什么,比如想要T变换就得L变换,而L变换的入口参数是t变换的返回值,所以我就明白了,我需要先补上t变换,然后写出L变换,就能得到我想要的T变换了。
    这种思维对于写程序来说,我认为是很好的,但是缺点也显而易见——读程序的人就不好懂了,因为他不明白写T转换为什么一下子就跳到了t转换。所以写完之后得再整理整理,才能够算是完成了这个工程。

    展开全文
  • SM3密码算法c语言实现

    2019-03-17 14:27:30
    本文件内含sm3国家密码算法设计总则,对sm3进行C语言实现,在Windows环境下可编程实现,包括源代码,内容详细,简单易懂。
  • 按照国密文档通过C语言实现SM2密码算法加密/解密、签名/验签,SM3密码杂凑算法SM4分组密码算法ECB、CBC模式加密/解密。 经过国密标准中数据验证无误。若有问题请及时反馈,期待和大家进行交流学习。 附带国密规范...
  • C语言实现了SM4的加密、解密。支持 ECB、CBC、CFB、OFB、CTR 模式。 其中,sm4.c 是算法,test.c是测试程序。使用时两个C文件统一编译,然后运行,即可看到SM4的测试结果
  • 国密SM2密码算法C语言实现

    千次阅读 2021-05-24 07:48:26
    SM2椭圆曲线密码算法是国家密码管理局批准的...本文介绍了SM2椭圆曲线公钥密码算法和加密解密算法中一部分过程的C语言实现。【关键词】 椭圆曲线 SM2 密码算法 公钥 加密解密Implementation of Public Key Cryptogr...
  • SM3算法C语言源码

    2017-01-09 11:52:55
    国家密码管理局的SM3算法标准的C语言源码,此代码的计算结果经过国家密码管理局商用密码检测中心的测试,代码简洁,易用性强。
  • 终于搞定了sm2算法在smt32单片机上的移植。 之前的动态内存分配,在上面总是莫名其妙的崩。不知道堆和栈空间该改多大合适。且总共64K的内存,太受限了。 几次想放弃,最后还是坚持了一下,终于搞定啦! 看miracl...
  • VC6.0,对sm4文档例子的C语言实现,加解密功能正常
  • 按照国密文档通过C语言实现SM2密码算法加密/解密、签名/验签,SM3密码杂凑算法SM4分组密码算法ECB、CBC模式加密/解密。 经过详尽的测试目前未发现问题,并附有国密标准中数据检测结果。若有问题请及时反馈,期待和...
  • 国密算法SM2算法 C语言源码 签名验签 加解密, 密钥交换
  • 当前位置:我的异常网» C++»求 国密sm2 算法 第四部分 公钥加密算法 c语言实现求 国密sm2 算法 第四部分 公钥加密算法 c语言实现代码,该怎么解决www.myexceptions.net网友分享于:2014-07-26浏览:0次求 国密sm2 ...
  • SM4分组密码算法采用非平衡Feistel结构,分组长度为128b密钥长度为128b。加密算法与密钥扩展算法均采用非线性迭代结构。加密运算和解密运算的算法结构相同,解密运算的轮密钥的使用顺序与加密运算相反。
  • 1、完整的SM4算法,包括ECB、CBC、CTR、CFB、OFB,C语言实现; 2、内含测试程序,在Linux环境下进入目录后make即可编译,已经在ubuntu16.04环境下编译测试OK; 3、参考GMSSL源码移植而成,做了部分修改; 4、已经在...
  • C语言实现SM4加解密算法

    千次阅读 2021-11-19 19:45:17
    C语言实现SM4加解密算法SM4加解密 SM4加解密 #include <string.h> #include <stdio.h> #include <time.h> /*---------------------------------------------------------------------------------...
  • SM2算法C语言实现

    热门讨论 2014-06-10 10:36:06
    SM2加解密的C语言实现,有兴趣的可以下载试试看。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,932
精华内容 772
关键字:

sm4算法c语言