• sm4


    SM4加密算法属于对称加密算法,2012年3月,国家密码管理局正式公布了包含SM4分组密码算法在内的《祖冲之序列密码算法》等6项密码行业标准。与DES和AES算法类似,SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。

    SMhttps://n0va-scy.github.io/2020/03/14/sm4%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/

    4算法结构图:(图片来源网上)

     

     

    https://n0va-scy.github.io/2020/03/14/sm4%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/

    参数介绍

    ​ 1、字节:由8位2进制数表示 ,字:由32位2进制数表示;

    ​ 2、S盒:固定的8bit输入、输出转换数组;

    ​ 3、加密密钥长度为128bit,表示为MK=(MK0,MK1,MK2,MK3),其中MKi为字。轮密钥表示为rki(i=0,1,2,3……31)为字。FK = (FK0,FK1,FK2,FK3)为系统 参数,CK = (CK0,CK1,CK2,……,CK31)为固定参数,都为字。

    加密

    加密原理这里就不讲了,网上有不少详细的文章,下面直接开始算法的实现。

    在开始加密算法之前,先介绍几个宏定义:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
    #define GET_ULONG_BE(n,b,i)
    {
    (n) = ( (unsigned long) (b)[(i) ] << 24 )
    | ( (unsigned long) (b)[(i) + 1] << 16 )
    | ( (unsigned long) (b)[(i) + 2] << 8 )
    | ( (unsigned long) (b)[(i) + 3] );
    }
    #endif
    //将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
    #ifndef PUT_ULONG_BE
    #define PUT_ULONG_BE(n,b,i)
    {
    (b)[(i) ] = (unsigned char) ( (n) >> 24 );
    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );
    (b)[(i) + 2] = (unsigned char) ( (n) >> 8 );
    (b)[(i) + 3] = (unsigned char) ( (n) );
    }
    #endif
    //循环左移 的巧妙实现(SHL(x,n)可以得到左移n位之后的结果,然后与右移的结果((x) >> (32 - n))逐位或来将右边空缺的n位补齐,效率比较高。)
    #define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
    #define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))
    //交换
    #define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }

    密钥调试算法

    先建立一个结构体来保存上下文信息,即加密模式和各轮子密钥:(这个结构体我是定义在sm4.h头文件中)

    1
    2
    3
    4
    5
    6
    typedef struct
    {
    int mode; /*!< encrypt/decrypt */
    unsigned long sk[32]; /*!< SM4 subkeys */
    }
    sm4_context;

    首先需要设置密钥,调用sm4_setkey_enc(&ctx,key);函数,这个函数会设置mode为加密,并调用sm4_setkey(ctx->sk,key);函数来完成密钥的操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void sm4_setkey_enc(sm4_context *ctx,unsigned char key[16]){
    ctx->mode = SM4_ENCRYPT;
    sm4_setkey(ctx->sk,key);
    }
    static void sm4_setkey(unsigned long SK[32],unsigned char key[16]){
    unsigned long MK[4];
    unsigned long k[36];
    unsigned long i = 0;
    //先通过宏将初始的密钥转换为4个32位bit的整数,并为计算各轮密钥预先准备好初始值
    GET_ULONG_BE(MK[0],key,0);
    GET_ULONG_BE(MK[1],key,4);
    GET_ULONG_BE(MK[2],key,8);
    GET_ULONG_BE(MK[3],key,12);
    k[0] = MK[0]^FK[0];
    k[1] = MK[1]^FK[1];
    k[2] = MK[2]^FK[2];
    k[3] = MK[3]^FK[3];
    for(;i<32;i++){
    k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);
    SK[i] = k[i+4];
    }
    }

    对于第i轮的密钥SK[i],其是由k[i]和对k[i+1]^k[i+2]^k[i+3]^CK[i]的复合变换T‘异或得到的:

    SK[i] = k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);函数sm4CaliRk就是变换T’,先进行Sbox的非线性替换,然后进行线性变换,线性变换L为:rk = bb^(ROTL(bb, 13))^(ROTL(bb, 23));

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    static unsigned long sm4CaliRk(unsigned long ka){ //复合变换T
    unsigned long bb = 0; //unsigned long 4字节( 32bit )
    unsigned long rk = 0;
    unsigned char a[4];
    unsigned char b[4];
    PUT_ULONG_BE(ka,a,0) //换转成8bit一个字符
    b[0] = sm4Sbox(a[0]);
    b[1] = sm4Sbox(a[1]);
    b[2] = sm4Sbox(a[2]);
    b[3] = sm4Sbox(a[3]);
    GET_ULONG_BE(bb,b,0) //将变换结果转换为32bit的整数
    //对得到的32位整数bb进行线性变换
    rk = bb^ROTL(bb,13)^ROTL(bb,23);
    return rk;
    }

    至此,密钥就已经生成了

    加密过程

    调用函数void sm4_crypt_ecb( sm4_context *ctx, int mode, int length, unsigned char *input, unsigned char *output)对密文input进行电码本模式加密(ECB),加密的核心是调用了static void sm4_one_round( unsigned long sk[32], unsigned char input[16], unsigned char output[16] )函数对第一块密文进行加密

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    void sm4_crypt_ecb( sm4_context *ctx,
    int mode,
    int length,
    unsigned char *input,
    unsigned char *output)
    {
    while( length > 0 )
    {
    sm4_one_round( ctx->sk, input, output );
    input += 16;
    output += 16;
    length -= 16;
    }

    }

    static void sm4_one_round( unsigned long sk[32],
    unsigned char input[16],
    unsigned char output[16] )
    {
    unsigned long i = 0;
    unsigned long ulbuf[36];

    memset(ulbuf, 0, sizeof(ulbuf));
    GET_ULONG_BE( ulbuf[0], input, 0 )
    GET_ULONG_BE( ulbuf[1], input, 4 )
    GET_ULONG_BE( ulbuf[2], input, 8 )
    GET_ULONG_BE( ulbuf[3], input, 12 )
    while(i<32)
    {
    ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
    // #ifdef _DEBUG
    // printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x ",i,sk[i], i, ulbuf[i+4] );
    // #endif
    i++;
    }
    PUT_ULONG_BE(ulbuf[35],output,0);
    PUT_ULONG_BE(ulbuf[34],output,4);
    PUT_ULONG_BE(ulbuf[33],output,8);
    PUT_ULONG_BE(ulbuf[32],output,12);
    }

    sm4_one_round()函数中,先将128位的输入input转为四个32位的整数,放入ulbuf[4]中,然后迭代地调用函数static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)进行32轮加密,第一轮加密都需要使用之前的128位的结果ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3]和该轮的密钥 sk[i],产生出该轮的密文ulbuf[i+4],最后的密文存储在ulbuf[35]~ulbuf[32]中,转换为字符数组形式放入output 中。

    1
    2
    3
    4
    5
    //一轮加密 
    static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
    {
    return (x0^sm4Lt(x1^x2^x3^rk));
    }

    sm4Lt()是一个合成变换,由非线性变换t和线性变换L复合而成:首先将输入的整数 ka 转换为8比特一个的字符,然后使用S盒进行线性变换,再将变换结果转为32比特的整数,最后对得到的32位整数bb进行线性变换:c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static unsigned long sm4Lt(unsigned long ka)
    {
    unsigned long bb = 0;
    unsigned long c = 0;
    unsigned char a[4];
    unsigned char b[4];
    PUT_ULONG_BE(ka,a,0)
    // b[0] = sm4Sbox(a[0]);
    // b[1] = sm4Sbox(a[1]);
    // b[2] = sm4Sbox(a[2]);
    // b[3] = sm4Sbox(a[3]);
    b[0] = Sbox[a[0]];
    b[1] = Sbox[a[1]];
    b[2] = Sbox[a[2]];
    b[3] = Sbox[a[3]];
    GET_ULONG_BE(bb,b,0)
    c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
    return c;
    }

    整个加密过程就结束了,不过上面提到的是ECB的加密模式:又称电子密码本模式:Electronic codebook,是最简单的块密码加密模式,加密前根据加密块大小(如AES为128位)分成若干块,之后将每块使用相同的密钥单独加密,解密同理。这种加密不能很好地隐藏数据模式。

    SM4常见的也有另一种加密模式:CBC:密码分组链接(CBC,Cipher-block chaining)模式,由IBM于1976年发明,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量IV。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    //CBC模式加解密 
    void sm4_crypt_cbc( sm4_context *ctx,
    int mode,
    int length,
    unsigned char iv[16],
    unsigned char *input,
    unsigned char *output )
    {
    int i;
    unsigned char temp[16];

    if( mode == SM4_ENCRYPT )
    {
    while( length > 0 )
    {
    for( i = 0; i < 16; i++ )
    output[i] = (unsigned char)( input[i] ^ iv[i] );

    sm4_one_round( ctx->sk, output, output );
    memcpy( iv, output, 16 );

    input += 16;
    output += 16;
    length -= 16;
    }
    }
    else /* SM4_DECRYPT */
    {
    while( length > 0 )
    {
    memcpy( temp, input, 16 );
    sm4_one_round( ctx->sk, input, output );

    for( i = 0; i < 16; i++ )
    output[i] = (unsigned char)( output[i] ^ iv[i] );

    memcpy( iv, temp, 16 );

    input += 16;
    output += 16;
    length -= 16;
    }
    }
    }

    解密过程

    解密前,首先要通过void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )函数设定解密时使用的key,这个函数还会将密钥的顺序倒置,然后调用sm4_crypt_ecb()即可解密。

    实际上,SM4的解密变换与加密变换结构相同,不同的仅仅是轮密钥的使用顺序相反。

    完整的代码

    sm4.h文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    /**
    * file sm4.h
    */
    #ifndef XYSSL_SM4_H
    #define XYSSL_SM4_H

    #define SM4_ENCRYPT 1
    #define SM4_DECRYPT 0
    #ifndef GET_ULONG_BE
    //将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
    #define GET_ULONG_BE(n,b,i)
    {
    (n) = ( (unsigned long) (b)[(i) ] << 24 )
    | ( (unsigned long) (b)[(i) + 1] << 16 )
    | ( (unsigned long) (b)[(i) + 2] << 8 )
    | ( (unsigned long) (b)[(i) + 3] );
    }
    #endif
    //将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
    #ifndef PUT_ULONG_BE
    #define PUT_ULONG_BE(n,b,i)
    {
    (b)[(i) ] = (unsigned char) ( (n) >> 24 );
    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );
    (b)[(i) + 2] = (unsigned char) ( (n) >> 8 );
    (b)[(i) + 3] = (unsigned char) ( (n) );
    }
    #endif
    //循环左移 的巧妙实现(SHL(x,n)可以得到左移n位之后的结果,然后与右移的结果((x) >> (32 - n))逐位或来将右边空缺的n位补齐,效率比较高。)
    #define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
    #define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))

    #define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }

    /**
    * rief SM4 context structure
    */
    typedef struct
    {
    int mode; /*!< encrypt/decrypt */
    unsigned long sk[32]; /*!< SM4 subkeys */
    }
    sm4_context;


    #ifdef __cplusplus
    extern "C" {
    #endif

    /**
    * rief SM4 key schedule (128-bit, encryption)
    *
    * param ctx SM4 context to be initialized
    * param key 16-byte secret key
    */
    void sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] );

    /**
    * rief SM4 key schedule (128-bit, decryption)
    *
    * param ctx SM4 context to be initialized
    * param key 16-byte secret key
    */
    void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] );

    /**
    * rief SM4-ECB block encryption/decryption
    * param ctx SM4 context
    * param mode SM4_ENCRYPT or SM4_DECRYPT
    * param length length of the input data
    * param input input block
    * param output output block
    */
    void sm4_crypt_ecb( sm4_context *ctx,
    int mode,
    int length,
    unsigned char *input,
    unsigned char *output);

    /**
    * rief SM4-CBC buffer encryption/decryption
    * param ctx SM4 context
    * param mode SM4_ENCRYPT or SM4_DECRYPT
    * param length length of the input data
    * param iv initialization vector (updated after use)
    * param input buffer holding the input data
    * param output buffer holding the output data
    */
    void sm4_crypt_cbc( sm4_context *ctx,
    int mode,
    int length,
    unsigned char iv[16],
    unsigned char *input,
    unsigned char *output );

    #ifdef __cplusplus
    }
    #endif

    #endif /* sm4.h */

    sm4.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    #include <iostream>
    #include <string.h>
    #include "sm4.h"

    using namespace std;


    //S盒
    const unsigned char 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
    };
    //CK为固定参数
    const unsigned int 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 };
    //FK为系统参数
    static const unsigned long FK[4] = {0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc};

    static unsigned char sm4Sbox(unsigned char inch)
    {
    unsigned char *pTable = (unsigned char *)Sbox;
    unsigned char retVal = (unsigned char)(pTable[inch]);
    return retVal;
    }
    //已知加密密钥MK,求轮转密钥rk
    static unsigned long sm4CaliRk(unsigned long ka){ //复合变换T
    unsigned long bb = 0; //unsigned long 4字节( 32bit )
    unsigned long rk = 0;
    unsigned char a[4];
    unsigned char b[4];
    PUT_ULONG_BE(ka,a,0) //换转成8bit一个字符
    b[0] = sm4Sbox(a[0]);
    b[1] = sm4Sbox(a[1]);
    b[2] = sm4Sbox(a[2]);
    b[3] = sm4Sbox(a[3]);
    GET_ULONG_BE(bb,b,0) //将变换结果转换为32bit的整数
    //对得到的32位整数bb进行线性变换
    rk = bb^ROTL(bb,13)^ROTL(bb,23);
    return rk;
    }
    static void sm4_setkey(unsigned long SK[32],unsigned char key[16]){
    unsigned long MK[4];
    unsigned long k[36];
    unsigned long i = 0;
    GET_ULONG_BE(MK[0],key,0);
    GET_ULONG_BE(MK[1],key,4);
    GET_ULONG_BE(MK[2],key,8);
    GET_ULONG_BE(MK[3],key,12);
    k[0] = MK[0]^FK[0];
    k[1] = MK[1]^FK[1];
    k[2] = MK[2]^FK[2];
    k[3] = MK[3]^FK[3];
    for(;i<32;i++){
    k[i+4] = k[i]^sm4CaliRk(k[i+1]^k[i+2]^k[i+3]^CK[i]);
    SK[i] = k[i+4];
    }
    }
    void sm4_setkey_enc(sm4_context *ctx,unsigned char key[16]){
    ctx->mode = SM4_ENCRYPT;
    sm4_setkey(ctx->sk,key);
    }

    static unsigned long sm4Lt(unsigned long ka)
    {
    unsigned long bb = 0;
    unsigned long c = 0;
    unsigned char a[4];
    unsigned char b[4];
    PUT_ULONG_BE(ka,a,0)
    // b[0] = sm4Sbox(a[0]);
    // b[1] = sm4Sbox(a[1]);
    // b[2] = sm4Sbox(a[2]);
    // b[3] = sm4Sbox(a[3]);
    b[0] = Sbox[a[0]];
    b[1] = Sbox[a[1]];
    b[2] = Sbox[a[2]];
    b[3] = Sbox[a[3]];
    GET_ULONG_BE(bb,b,0)
    c =bb^(ROTL(bb, 2))^(ROTL(bb, 10))^(ROTL(bb, 18))^(ROTL(bb, 24));
    return c;
    }
    //一轮加密
    static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
    {
    return (x0^sm4Lt(x1^x2^x3^rk));
    }
    static void sm4_one_round( unsigned long sk[32],
    unsigned char input[16],
    unsigned char output[16] )
    {
    unsigned long i = 0;
    unsigned long ulbuf[36];

    memset(ulbuf, 0, sizeof(ulbuf));
    GET_ULONG_BE( ulbuf[0], input, 0 )
    GET_ULONG_BE( ulbuf[1], input, 4 )
    GET_ULONG_BE( ulbuf[2], input, 8 )
    GET_ULONG_BE( ulbuf[3], input, 12 )
    while(i<32)
    {
    ulbuf[i+4] = sm4F(ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3], sk[i]);
    // #ifdef _DEBUG
    // printf("rk(%02d) = 0x%08x, X(%02d) = 0x%08x ",i,sk[i], i, ulbuf[i+4] );
    // #endif
    i++;
    }
    PUT_ULONG_BE(ulbuf[35],output,0);
    PUT_ULONG_BE(ulbuf[34],output,4);
    PUT_ULONG_BE(ulbuf[33],output,8);
    PUT_ULONG_BE(ulbuf[32],output,12);
    }
    //ECB模式
    void sm4_crypt_ecb( sm4_context *ctx,
    int mode,
    int length,
    unsigned char *input,
    unsigned char *output)
    {
    while( length > 0 )
    {
    sm4_one_round( ctx->sk, input, output );
    input += 16;
    output += 16;
    length -= 16;
    }

    }
    //ECB模式解密密钥
    void sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )
    {
    int i;
    ctx->mode = SM4_ENCRYPT;
    sm4_setkey( ctx->sk, key );
    for( i = 0; i < 16; i ++ )
    {
    SWAP( ctx->sk[ i ], ctx->sk[ 31-i] );
    }
    }
    //CBC模式加解密
    void sm4_crypt_cbc( sm4_context *ctx,
    int mode,
    int length,
    unsigned char iv[16],
    unsigned char *input,
    unsigned char *output )
    {
    int i;
    unsigned char temp[16];

    if( mode == SM4_ENCRYPT )
    {
    while( length > 0 )
    {
    for( i = 0; i < 16; i++ )
    output[i] = (unsigned char)( input[i] ^ iv[i] );

    sm4_one_round( ctx->sk, output, output );
    memcpy( iv, output, 16 );

    input += 16;
    output += 16;
    length -= 16;
    }
    }
    else /* SM4_DECRYPT */
    {
    while( length > 0 )
    {
    memcpy( temp, input, 16 );
    sm4_one_round( ctx->sk, input, output );

    for( i = 0; i < 16; i++ )
    output[i] = (unsigned char)( output[i] ^ iv[i] );

    memcpy( iv, temp, 16 );

    input += 16;
    output += 16;
    length -= 16;
    }
    }
    }
    int main()
    {
    unsigned char key[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
    unsigned char input[16] = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
    unsigned char output[16];
    sm4_context ctx;
    unsigned long i;
    //encrypt
    sm4_setkey_enc(&ctx,key);
    sm4_crypt_ecb(&ctx,1,16,input,output);
    //加密结果
    printf("加密结果: ");
    for(i = 0;i< 16;i ++){
    printf("%02x ",output[i]);
    }
    printf(" ");
    sm4_setkey_dec(&ctx,key);
    sm4_crypt_ecb(&ctx,0,16,output,output);
    //解密结果
    printf("解密结果: ");
    for(i = 0;i< 16;i ++){
    printf("%02x ",output[i]);
    }
    printf(" ");
    return 0;
    }

    参数文章:https://blog.csdn.net/cg129054036/article/details/83012721

    https://blog.csdn.net/cg129054036/article/details/83016958

    https://blog.csdn.net/archimekai/article/details/53095993

  • 相关阅读:
    打开控制面板中的程序
    内存使用情况监控
    监视剪切板内容
    检测系统启动模式
    启动Windows服务
    开机启动项管理
    docker部署war+tomcat8
    docker安装mysql5.6和redis3.2
    nginx命令和配置
    nginx安装
  • 原文地址:https://www.cnblogs.com/zheli/p/13230393.html
Copyright © 2020-2023  润新知