sm4加密算法C/C++源码

本文介绍sm4加密算法C/C++代码实现,支持cbc和ecb加密方式,可用于本地文件的加密使用。

两种模式  1、对整个文件进行加密解密

	/**********************************************************************************************
	* @brief 加密文件
	* @param SrcPath (传入) 加密源文件名
	* @param DestPath (传出) 加密后的密文文件名
	**********************************************************************************************/
	void Encrypt(std::string DestPath, std::string SrcPath);

	/**********************************************************************************************
	* @brief 解密文件
	* @param SrcPath (传入) 解密源文件名
	* @param DestPath (传出) 解密后的明文文件名
	**********************************************************************************************/
	void Decrypt(std::string DestPath, std::string SrcPath);


	/**********************************************************************************************
	* @brief 加密文件
	* @param SrcPath (传入传出) 加密源文件名
	**********************************************************************************************/
	void Encrypt(std::string SrcPath);

	/**********************************************************************************************
	* @brief 解密文件
	* @param SrcPath (传入传出) 解密源文件名
	**********************************************************************************************/
	void Decrypt(std::string SrcPath);

2、对字符串加密解密,本人使用的场景是将字符串先加密,然后将密文写入到文件保存,读取时,先读取再解密使用。

由于sm4加密时一次为128bit即16个字节,分组加密时可能会补字节,所以文件保存时宜记录加密前后数据长度。

以下为源码,亲测可用,vs2015,Linux下编译报错可将<string>换<string.h>

#ifndef SM4_H
#define SM4_H

/**
* \file sm4.h
*/
#define SM4_ENCRYPT     1
#define SM4_DECRYPT     0

/**
* \brief          SM4 context structure 上下文结构
*/
typedef struct
{
    int mode;                   /*!<  encrypt/decrypt 控制加密还是解密 */
    unsigned long sk[32];       /*!<  SM4 subkeys  存放每次迭代的轮密钥     */
}sm4_context;


#ifdef __cplusplus
extern "C" {
#endif
//
    /**
    * \brief          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]);

    /**
    * \brief          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]);

    /**
    * \brief          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
    */
    int sm4_crypt_ecb(sm4_context *ctx,
        int mode,
        int length,
        unsigned char *input,
        unsigned char *output);

    /**
    * \brief          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
    */
    int sm4_crypt_cbc(sm4_context *ctx,
        int mode,
        int length,
        unsigned char iv[16],
        unsigned char *input,
        unsigned char *output);

#ifdef __cplusplus
}
#endif
#include <iostream>
class Sm4EncDec
{
public:
    /**********************************************************************************************
    * @brief 构造函数 密钥赋值
    **********************************************************************************************/
    Sm4EncDec(int _mode = 0);

    /**********************************************************************************************
    * @brief 构造函数 密钥赋值
    * @param SrcPath (传入) 需要赋值的密钥
    **********************************************************************************************/
    Sm4EncDec(unsigned char key[], int _mode = 0);

    /**********************************************************************************************
    * @brief 加密文件
    * @param SrcPath (传入) 加密源文件名
    * @param DestPath (传出) 加密后的密文文件名
    **********************************************************************************************/
    void Encrypt(std::string DestPath, std::string SrcPath);

    /**********************************************************************************************
    * @brief 解密文件
    * @param SrcPath (传入) 解密源文件名
    * @param DestPath (传出) 解密后的明文文件名
    **********************************************************************************************/
    void Decrypt(std::string DestPath, std::string SrcPath);


    /**********************************************************************************************
    * @brief 加密文件
    * @param SrcPath (传入传出) 加密源文件名
    **********************************************************************************************/
    void Encrypt(std::string SrcPath);

    /**********************************************************************************************
    * @brief 解密文件
    * @param SrcPath (传入传出) 解密源文件名
    **********************************************************************************************/
    void Decrypt(std::string SrcPath);


    /**********************************************************************************************
    * @brief 加密字符串
    * @param SrcPath (传入) 需要加密的字符串
    * @param DestPath (传出) 加密后的密文字符串
    **********************************************************************************************/
    int Encrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen);

    /**********************************************************************************************
    * @brief 解密字符串
    * @param SrcPath (传入) 需要解密的字符串
    * @param DestPath (传出) 解密后的明文字符串
    **********************************************************************************************/
    int Decrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen);

    /**********************************************************************************************
    * @brief 设置加密模式
    * @param _mode (传入) 加密模式
    *   _mode  = 0  --> ebc
    *   _mode  > 0  --> cbc
    **********************************************************************************************/
    void SetMode(int _mode);

private:
    //密钥
    unsigned char key[16];
    int mode;               //加密模式 ebc or cbc
};

#endif // SM4_H

#pragma pack(4)
#include "sm4.h"
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>

/*
* 32-bit integer manipulation macros (big endian)
* //将字符型数组b的第i到第i+3位的二进制拼接成一个4*8=32bit的整数,存入n中
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i)                             \
{                                                       \
    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
    | ( (unsigned long) (b)[(i) + 1] << 16 )        \
    | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
    | ( (unsigned long) (b)[(i) + 3]       );       \
    }
#endif

//将整数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

/*
*rotate shift left marco definition
* 循环移位
*/
#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; }

/*
* Expanded SM4 S-boxes  S盒
* Sbox table: 8bits input convert to 8 bits output
*/

static const unsigned char SboxTable[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 }
};

/* System parameter 系统参数FK */
static const unsigned long FK[4] = { 0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc };

/* fixed parameter 固定参数 */
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
};


/*
* private function:
* look up in SboxTable and get the related value.
* args:    [in] inch: 0x00~0xFF (8 bits unsigned value).
*/
static unsigned char sm4Sbox(unsigned char inch)
{
    unsigned char *pTable = (unsigned char *)SboxTable;
    unsigned char retVal = (unsigned char)(pTable[inch]);
    return retVal;
}

/*
* private F(Lt) function:
* "T algorithm" == "L algorithm" + "t algorithm".
* args:    [in] a: a is a 32 bits unsigned value;
* return: c: c is calculated with line algorithm "L" and nonline algorithm "t"
*/
/*
合成置换T ,由非线性变换t和线性变换L复合而成
将输入的整数ka转换为8比特一个的字符PUT_ULONG_BE(ka,a,0),
然后使用S盒进行非线性变换,再将变换结果转换为32比特的整数
GET_ULONG_BE(bb,b,0),最后对得到的32位整数bb进行线性变换:
c = bb异或(bb << <2)异或(bb << <10)异或(bb << <18)异或(bb << <24)。
从而得到复合变换的结果c。
*/

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);

    //函数T与密钥扩展中的函数T相同
    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);

    //L处理变为B与左移2位及左移10位及左移18位及左移24位的B进行异或处理
    c = bb ^ (ROTL(bb, 2)) ^ (ROTL(bb, 10)) ^ (ROTL(bb, 18)) ^ (ROTL(bb, 24));
    return c;
}

/*
* private F function:
* Calculating and getting encryption/decryption contents.
* args:    [in] x0: original contents;
* args:    [in] x1: original contents;
* args:    [in] x2: original contents;
* args:    [in] x3: original contents;
* args:    [in] rk: encryption/decryption key;
* return the contents of encryption/decryption contents.
*/
/*
轮函数F 每一轮加密中,输入为(x0, x1, x2, x3),xi为32位比特,
共计128比特。通过x0^sm4Lt(x1^x2^x3^rk)得到该轮加密的结果。
*/
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
    //明文拆分后的4个字的后3个字与该轮的子密钥进行异或处理
    //经过一个函数T得到C,之后再将明文拆分后的第一个字与C进行异或。
    return (x0^sm4Lt(x1^x2^x3^rk));
}


/*
* 变换T’ 先进行Sbox的非线性替换,然后进行线性变换,
* 线性变换L改为了: rk = bb ^ (ROTL(bb, 13)) ^ (ROTL(bb, 23));
*/

static unsigned long sm4CalciRK(unsigned long ka)
{
    unsigned long bb = 0;
    unsigned long rk = 0;
    unsigned char a[4];
    unsigned char b[4];
    //将A拆分为4个8bit的字节
    PUT_ULONG_BE(ka, a, 0)
            //S盒变换
            b[0] = sm4Sbox(a[0]);
    b[1] = sm4Sbox(a[1]);
    b[2] = sm4Sbox(a[2]);
    b[3] = sm4Sbox(a[3]);

    //4个S盒的输出组成32位的值B
    GET_ULONG_BE(bb, b, 0)

            //B与左移13位及左移23位的B进行异或处理作为函数T的输出C
            rk = bb ^ (ROTL(bb, 13)) ^ (ROTL(bb, 23));
    return rk;
}

/*
* 密钥扩展算法,对当前传入的主密钥进行32轮的迭代,
* 每次迭代的轮密钥都被存放到ctx结构中的sk数组中
* 类似于加密中的操作,首先通过宏将初始的密钥拆分为4个32位bit的字,
* MK0,MK1,MK2,MK3,并为计算各轮密钥预先准备好初始值
*/
static void sm4_setkey(unsigned long SK[32], unsigned char key[16])
{
    unsigned long MK[4]; //拆分后的4个32bit秘钥
    unsigned long k[36]; //存放MK与系统参数FK异或运算得到的K
    unsigned long i = 0;

    //将密钥拆分为4字
    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);

    //线性变换 L 位移异或,与系统参数的每个字做异或运算得到(K0, K1, K2, K3)
    k[0] = MK[0] ^ FK[0];
    k[1] = MK[1] ^ FK[1];
    k[2] = MK[2] ^ FK[2];
    k[3] = MK[3] ^ FK[3];

    //对于第i轮的密钥SK[i] ,其是由k[i]
    //和对k[i+1]^k[i+2]^k[i+3]^CK[i]的复合变换T’异或得到的:
    for (; i < 32; i++)
    {
        k[i + 4] = k[i] ^ (sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]));
        SK[i] = k[i + 4];
    }
}

/*
* SM4 standard one round processing
*
*/

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

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];

    //将128bit的明文分成4个32bit的字X1,X2,X3,X4
    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);

    //进行32轮的轮操作
    while (i < 32)
    {
        ulbuf[i + 4] = sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
        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 key schedule (128-bit, encryption) 设置加密秘钥
*/
void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16])
{
    ctx->mode = SM4_ENCRYPT;   /*!< SM4_ENCRYPT 加密  SM4_DECRYPT解密 */
    sm4_setkey(ctx->sk, key);
}

/*
* SM4 key schedule (128-bit, decryption)
*/
设置解密秘钥 轮密钥的使用顺序相反
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]);
    }
}


/*
* SM4-ECB block encryption/decryption
* ECB模式密文被分割成分组长度相等的块(不足补齐),
* 然后单独一个个加密,一个个输出组成密文。
*/
int sm4_crypt_ecb(sm4_context *ctx,
                  int mode,
                  int length,
                  unsigned char *input,
                  unsigned char *output)
{
    int retlen = 0;
    while (length > 0 )
    {
        sm4_one_round(ctx->sk, input, output);
        input += 16;
        output += 16;
        length -= 16;
        retlen += 16;
    }
    return retlen;
}

/*
* SM4-CBC buffer encryption/decryption
* 循环模式(链式),前一个分组的密文和当前分组的明文操作后再加密,
* 增强破解难度。(不容易主动攻击,安全性好于ECB,是SSL、IPSec的标准)
*/
int 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)
    {
        int retlen = 0;
        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);
            //iv = output;
            input += 16;
            output += 16;
            length -= 16;
            retlen += 16;
        }
        return retlen;
    }
    else /* SM4_DECRYPT */
    {
        int retlen = 0;
        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);

            //iv = temp;
            input += 16;
            output += 16;
            length -= 16;
            retlen += 16;
        }
        return retlen;
    }

}


//初始化密钥赋值 默认unsigned char key1[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
Sm4EncDec::Sm4EncDec(int _mode)
{
    if(_mode)
        mode = 1;
    else
        mode = 0;
    memset(key, 0, 16);
    unsigned char key1[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
    memcpy(key, key1,16);
}

Sm4EncDec::Sm4EncDec(unsigned char _key[],int _mode)
{
    if(!_key)
        return;
    memset(key,0,16);
    SetMode(_mode);
    memcpy(key, _key, 16);
}

void Sm4EncDec::SetMode(int _mode)
{
    if(_mode)
        mode = 1;
    else
        _mode = 0;
}

//加密
void Sm4EncDec::Encrypt(std::string DestPath,std::string SrcPath)
{
    if (SrcPath.empty())
        return;

    FILE* InFile = fopen(SrcPath.c_str(), "rb");
    if (InFile == NULL)
    {
        return;
    }

    FILE* OutFile = fopen(DestPath.c_str(), "wb");
    if (OutFile == NULL)
    {
        fclose(InFile);
        return;
    }

    fseek(InFile, 0, SEEK_END);
    long filelen = ftell(InFile);
    fseek(InFile, 0, SEEK_SET);

    long last = filelen;
    long offset = 1024;

    unsigned char SrcBuffer[1024]={0};
    unsigned char DestBuffer[1024] = {0};
    sm4_context ctx;

    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;
    while (last > 0)
    {
        unsigned char* dest = DestBuffer;
        unsigned char* src = SrcBuffer;
        memset(SrcBuffer, 0, offset);
        memset(DestBuffer, 0, offset);
        offset = std::min(offset, last);

        fread(SrcBuffer, offset, 1, InFile);
        last -= offset;

        //设置秘钥
        sm4_setkey_enc(&ctx, key);
        //加密
        int elen = 0;
        if(!mode)
        {
            elen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            elen = sm4_crypt_cbc(&ctx, SM4_ENCRYPT, offset, iv,src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }
        fwrite(DestBuffer, elen, 1, OutFile);
    }

    fclose(InFile);
    fclose(OutFile);

    return;
}

//解密
void Sm4EncDec::Decrypt(std::string DestPath, std::string SrcPath)
{
    if (SrcPath.empty())
        return;

    FILE* InFile = fopen(SrcPath.c_str(), "rb");
    if (InFile == NULL)
    {
        return;
    }

    FILE* OutFile = fopen(DestPath.c_str(), "wb");
    if (OutFile == NULL)
    {
        fclose(InFile);
        return;
    }

    fseek(InFile, 0, SEEK_END);
    long filelen = ftell(InFile);
    fseek(InFile, 0, SEEK_SET);

    long last = filelen;
    long offset = 1024;
    sm4_context ctx;
    unsigned char SrcBuffer[1024]={0};
    unsigned char DestBuffer[1024] = {0};
    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;
    while (last > 0)
    {
        unsigned char* dest = DestBuffer;
        unsigned char* src = SrcBuffer;
        memset(SrcBuffer, 0, offset);
        memset(DestBuffer, 0, offset);

        offset = std::min(offset, last);

        fread(SrcBuffer, offset, 1, InFile);

        sm4_setkey_dec(&ctx, key);
        int dlen = 0;
        if(!mode)
        {
            dlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            dlen = sm4_crypt_cbc(&ctx, SM4_DECRYPT, offset, iv,SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }
        fwrite(DestBuffer, dlen, 1, OutFile);
        last -= offset;
    }

    fclose(InFile);
    fclose(OutFile);
    return;
}

//加密
void Sm4EncDec::Encrypt(std::string SrcPath)
{
    FILE* InFile = fopen(SrcPath.c_str(), "rb+");
    if (InFile == NULL)
    {
        return;
    }
    fseek(InFile, 0, SEEK_END);
    int filelen = ftell(InFile);
    fseek(InFile, 0, SEEK_SET);

    int last = filelen;
    int offset = 1024;

    unsigned char SrcBuffer[1024]={0};
    unsigned char DestBuffer[1024]={0};

    sm4_context ctx;

    int fileindex = 0;
    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;

    while (last > 0)
    {
        unsigned char* dest = DestBuffer;
        unsigned char* src = SrcBuffer;
        memset(src, '\0', offset);
        memset(dest, '\0', offset);

        offset = std::min(offset, last);

        fseek(InFile, fileindex,SEEK_SET);

        int rn = fread(SrcBuffer,offset,1, InFile);

        fileindex = ftell(InFile);  //读位置

        //设置秘钥
        sm4_setkey_enc(&ctx, key);
        //加密
        int retlen = 0;
        if(!mode)
        {
            retlen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            retlen = sm4_crypt_cbc(&ctx, SM4_ENCRYPT, offset, iv, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }

        fseek(InFile, fileindex - offset, SEEK_SET);

        int wn = fwrite(DestBuffer, retlen,1, InFile);
        fseek(InFile, fileindex, SEEK_SET);

        last -= offset;
    }

    fclose(InFile);
    return;
}

//解密
void Sm4EncDec::Decrypt( std::string SrcPath)
{
    FILE* InFile = fopen(SrcPath.c_str(), "rb+");

    if (InFile == NULL)
    {
        return;
    }
    sm4_context ctx;

    fseek(InFile, 0, SEEK_END);
    int filelen = ftell(InFile);
    fseek(InFile, 0, SEEK_SET);

    int last = filelen;
    int offset = 1024;

    unsigned char SrcBuffer[1024]={0};
    unsigned char DestBuffer[1024] = {0};

    int fileindex =0;
    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;
    while (last > 0)
    {
        unsigned char* dest = DestBuffer;
        unsigned char* src = SrcBuffer;
        memset(src, 0, offset);
        memset(dest, 0, offset);

        offset = std::min(offset, last);

        fseek(InFile, fileindex, SEEK_SET);
        int tn = fread(SrcBuffer,offset,1, InFile);
        fileindex = ftell(InFile);   //记录读的位置

        sm4_setkey_dec(&ctx, key);

        int retlen = 0;
        if(!mode)
        {
            retlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            retlen = sm4_crypt_cbc(&ctx, SM4_DECRYPT, offset, iv, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }
        fseek(InFile, fileindex - offset,SEEK_SET);
        int wn = fwrite(DestBuffer, retlen,1, InFile);
        fseek(InFile, fileindex, SEEK_SET);

        last -= offset;
    }

    fclose(InFile);
    return;
}

//加密字符串
int Sm4EncDec::Encrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen)
{
    if (srcStr == NULL)
        return 0;
    int last = srcLen;
    int offset = 128;
    unsigned char* dest = destBuf;
    unsigned char* src = srcStr;
    sm4_context ctx;
    int retlen = 0;
    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;
    while (last > 0)
    {
        offset = std::min(offset, last);

        last -= offset;
        //设置秘钥
        sm4_setkey_enc(&ctx, key);
        //加密
        int elen = 0;
        if(!mode)
        {
            elen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            elen = sm4_crypt_cbc(&ctx, SM4_ENCRYPT, offset,iv, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }
        src += offset;
        dest += offset;

        retlen += elen;
    }
    return retlen;
}

//解密字符串
int Sm4EncDec::Decrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen)
{
    if (srcStr == NULL)
        return 0;
    int last = srcLen;
    int offset = 128;
    int retlen = 0;

    unsigned char*  dest = destBuf;
    unsigned char*  src = srcStr;
    sm4_context ctx;
    unsigned char iv1[16]={0};
    unsigned char* iv = iv1;
    while (last > 0)
    {
        offset = std::min(offset, last);

        last -= offset;
        sm4_setkey_dec(&ctx, key);

        int dlen = 0;
        if(!mode)
        {
            dlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
        }
        else
        {
            dlen = sm4_crypt_cbc(&ctx, SM4_ENCRYPT, offset,iv, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密
            memcpy(iv,dest - 15,16);
        }
        src += offset;
        dest += offset;

        retlen += dlen;
    }
    return retlen;
}

#pragma pack()

key为16字节,支持特殊字符,自测中文可用,加密文件或字符串支持中文特殊字符 

调用Sm4EncDec类成员Encrypt和Decrypt可实现加密解密

源码链接https://download.csdn.net/download/qq_45688637/86744590没有积分可联系我免费取源码

参考SM4算法过程_不是小白才怪的博客-CSDN博客_sm4

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
sm4加密算法是一种对称加密算法,其加密和解密使用相同的密钥。以下是使用C语言实现sm4加密算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> typedef unsigned char byte; typedef unsigned int word; #define GET_UINT32_BE(n,b,i) \ { \ (n) = ( (word) (b)[(i) ] << 24 ) \ | ( (word) (b)[(i) + 1] << 16 ) \ | ( (word) (b)[(i) + 2] << 8 ) \ | ( (word) (b)[(i) + 3] ); \ } #define PUT_UINT32_BE(n,b,i) \ { \ (b)[(i) ] = (byte) ( (n) >> 24 ); \ (b)[(i) + 1] = (byte) ( (n) >> 16 ); \ (b)[(i) + 2] = (byte) ( (n) >> 8 ); \ (b)[(i) + 3] = (byte) ( (n) ); \ } #define SBOX_TABLE_SIZE 256 #define SBOX_SIZE 16 #define SBOX_ROW_SIZE 4 #define SBOX_COL_SIZE 4 static const byte SboxTable[SBOX_TABLE_SIZE] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /*0*/ 0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, /*1*/ 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, /*2*/ 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62, /*3*/ 0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, /*4*/ 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, /*5*/ 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, /*6*/ 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, /*7*/ 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, /*8*/ 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, /*9*/ 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, /*A*/ 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, /*B*/ 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, /*C*/ 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, /*D*/ 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, /*E*/ 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, /*F*/ 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48 }; static const word FK[4] = { 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC }; static const word 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 }; #define ROTL(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) #define L1(x) (x ^ ROTL(x, 2) ^ ROTL(x,10) ^ ROTL(x,18) ^ ROTL(x,24)) #define L2(x) (x ^ ROTL(x,13) ^ ROTL(x,23)) #define ROUND(x0,x1,x2,x3,x4,rk) \ { \ x4 = x1 ^ x2 ^ x3 ^ rk; \ x4 = L1(x4); \ x0 = x0 ^ x4; \ x4 = L2(x4); \ x1 = x1 ^ x4; \ x2 = x2 ^ x4; \ x3 = x3 ^ x4; \ } void sm4_setkey_enc(word SK[32], const byte key[16]) { word MK[4]; word k[36]; int i; GET_UINT32_BE(MK[0], key, 0); GET_UINT32_BE(MK[1], key, 4); GET_UINT32_BE(MK[2], key, 8); GET_UINT32_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=0; i<32; i++) { ROUND(k[i], k[i+1], k[i+2], k[i+3], k[i+4], CK[i]); SK[i] = k[i+4]; } } void sm4_crypt_ecb(const word SK[32], int mode, int length, const byte input[], byte output[]) { word i; word ulbuf[36]; while(length > 0) { GET_UINT32_BE(ulbuf[0], input, 0); GET_UINT32_BE(ulbuf[1], input, 4); GET_UINT32_BE(ulbuf[2], input, 8); GET_UINT32_BE(ulbuf[3], input, 12); for(i=0; i<32; i++) { ROUND(ulbuf[0], ulbuf[1], ulbuf[2], ulbuf[3], ulbuf[4], SK[i]); } PUT_UINT32_BE(ulbuf[0], output, 0); PUT_UINT32_BE(ulbuf[1], output, 4); PUT_UINT32_BE(ulbuf[2], output, 8); PUT_UINT32_BE(ulbuf[3], output, 12); input += 16; output += 16; length -= 16; } } int main() { byte key[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; byte input[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; byte output[16]; word SK[32]; sm4_setkey_enc(SK, key); sm4_crypt_ecb(SK, 1, 16, input, output); printf("Input: "); for(int i=0; i<16; i++) { printf("%02x ", input[i]); } printf("\n"); printf("Output: "); for(int i=0; i<16; i++) { printf("%02x ", output[i]); } printf("\n"); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值