使用C++实现SM4软加密算法,对文件、字符串加解密

c++ c++ 1707 人阅读 | 0 人回复

发表于 2023-4-19 18:18:28 | 显示全部楼层 |阅读模式

本文介绍SM4软加密算法算法C/C++代码实现,可用于本地文件的加密使用。

两种模式  

1、对整个文件进行加密解密

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

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

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

Sm4.h头文件如下:

  1. //sm4.h
  2. #pragma once
  3. /**
  4. * \file sm4.h
  5. */
  6. #define SM4_ENCRYPT     1
  7. #define SM4_DECRYPT     0

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


  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. //
  20.         /**
  21.         * \brief          SM4 key schedule (128-bit, encryption)设置加密秘钥
  22.         *
  23.         * \param ctx      SM4 context to be initialized
  24.         * \param key      16-byte secret key
  25.         */
  26.         void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16]);

  27.         /**
  28.         * \brief          SM4 key schedule (128-bit, decryption)
  29.         *
  30.         * \param ctx      SM4 context to be initialized
  31.         * \param key      16-byte secret key
  32.         */
  33.         void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16]);

  34.         /**
  35.         * \brief          SM4-ECB block encryption/decryption
  36.         * \param ctx      SM4 context
  37.         * \param mode     SM4_ENCRYPT or SM4_DECRYPT
  38.         * \param length   length of the input data
  39.         * \param input    input block
  40.         * \param output   output block
  41.         */
  42.         int sm4_crypt_ecb(sm4_context *ctx,
  43.                 int mode,
  44.                 int length,
  45.                 unsigned char *input,
  46.                 unsigned char *output);

  47.         /**
  48.         * \brief          SM4-CBC buffer encryption/decryption
  49.         * \param ctx      SM4 context
  50.         * \param mode     SM4_ENCRYPT or SM4_DECRYPT
  51.         * \param length   length of the input data
  52.         * \param iv       initialization vector (updated after use)
  53.         * \param input    buffer holding the input data
  54.         * \param output   buffer holding the output data
  55.         */
  56.         void sm4_crypt_cbc(sm4_context *ctx,
  57.                 int mode,
  58.                 int length,
  59.                 unsigned char iv[16],
  60.                 unsigned char *input,
  61.                 unsigned char *output);

  62. #ifdef __cplusplus
  63. }
  64. #endif
  65. #include <iostream>
  66. class Sm4EncDec
  67. {
  68. public:
  69.         /**********************************************************************************************
  70.         * @brief 构造函数 密钥赋值
  71.         **********************************************************************************************/
  72.         Sm4EncDec();

  73.         /**********************************************************************************************
  74.         * @brief 构造函数 密钥赋值
  75.         * @param SrcPath (传入) 需要赋值的密钥
  76.         **********************************************************************************************/
  77.         Sm4EncDec(unsigned char key[]);

  78.         /**********************************************************************************************
  79.         * @brief 加密文件
  80.         * @param SrcPath (传入) 加密源文件名
  81.         * @param DestPath (传出) 加密后的密文文件名
  82.         **********************************************************************************************/
  83.         void Encrypt(std::string DestPath, std::string SrcPath);

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


  90.         /**********************************************************************************************
  91.         * @brief 加密文件
  92.         * @param SrcPath (传入传出) 加密源文件名
  93.         **********************************************************************************************/
  94.         void Encrypt(std::string SrcPath);

  95.         /**********************************************************************************************
  96.         * @brief 解密文件
  97.         * @param SrcPath (传入传出) 解密源文件名
  98.         **********************************************************************************************/
  99.         void Decrypt(std::string SrcPath);


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

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

  112. private:
  113.         //密钥
  114.         unsigned char key[16];
  115. };
复制代码

Sm4.cpp

  1. //sm4.cpp
  2. #pragma pack(4)
  3. #include "sm4.h"
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <iostream>
  7. #include <algorithm>

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

  21. //将整数n的32位的二进制表示转换为4个char的数组,存入数组b的第i到第i+3位
  22. #ifndef PUT_ULONG_BE
  23. #define PUT_ULONG_BE(n,b,i)                             \
  24. {                                                       \
  25.     (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
  26.     (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
  27.     (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
  28.     (b)[(i) + 3] = (unsigned char) ( (n)       );       \
  29. }
  30. #endif

  31. /*
  32. *rotate shift left marco definition
  33. * 循环移位
  34. */
  35. #define  SHL(x,n) (((x) & 0xFFFFFFFF) << n)
  36. #define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))

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

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

  41. static const unsigned char SboxTable[16][16] =
  42. {
  43.         { 0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05 },
  44.         { 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99 },
  45.         { 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62 },
  46.         { 0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6 },
  47.         { 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8 },
  48.         { 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35 },
  49.         { 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87 },
  50.         { 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e },
  51.         { 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1 },
  52.         { 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3 },
  53.         { 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f },
  54.         { 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51 },
  55.         { 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8 },
  56.         { 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0 },
  57.         { 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84 },
  58.         { 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48 }
  59. };

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

  62. /* fixed parameter 固定参数 */
  63. static const unsigned long CK[32] =
  64. {
  65.         0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
  66.         0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
  67.         0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
  68.         0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
  69.         0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
  70.         0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
  71.         0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
  72.         0x10171e25,0x2c333a41,0x484f565d,0x646b7279
  73. };


  74. /*
  75. * private function:
  76. * look up in SboxTable and get the related value.
  77. * args:    [in] inch: 0x00~0xFF (8 bits unsigned value).
  78. */
  79. static unsigned char sm4Sbox(unsigned char inch)
  80. {
  81.         unsigned char *pTable = (unsigned char *)SboxTable;
  82.         unsigned char retVal = (unsigned char)(pTable[inch]);
  83.         return retVal;
  84. }

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

  99. static unsigned long sm4Lt(unsigned long ka)
  100. {
  101.         unsigned long bb = 0;
  102.         unsigned long c = 0;
  103.         unsigned char a[4];
  104.         unsigned char b[4];

  105.         PUT_ULONG_BE(ka, a, 0);

  106.         //函数T与密钥扩展中的函数T相同
  107.         b[0] = sm4Sbox(a[0]);
  108.         b[1] = sm4Sbox(a[1]);
  109.         b[2] = sm4Sbox(a[2]);
  110.         b[3] = sm4Sbox(a[3]);

  111.         GET_ULONG_BE(bb, b, 0);

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

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


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

  140. static unsigned long sm4CalciRK(unsigned long ka)
  141. {
  142.         unsigned long bb = 0;
  143.         unsigned long rk = 0;
  144.         unsigned char a[4];
  145.         unsigned char b[4];
  146.         //将A拆分为4个8bit的字节
  147.         PUT_ULONG_BE(ka, a, 0)
  148.                 //S盒变换
  149.                 b[0] = sm4Sbox(a[0]);
  150.         b[1] = sm4Sbox(a[1]);
  151.         b[2] = sm4Sbox(a[2]);
  152.         b[3] = sm4Sbox(a[3]);

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

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

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

  170.         //将密钥拆分为4字
  171.         GET_ULONG_BE(MK[0], key, 0);
  172.         GET_ULONG_BE(MK[1], key, 4);
  173.         GET_ULONG_BE(MK[2], key, 8);
  174.         GET_ULONG_BE(MK[3], key, 12);

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

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

  188. /*
  189. * SM4 standard one round processing
  190. *
  191. */

  192. /*
  193. * 轮加密
  194. * 先将明文输入input的整数,放入ulbuf[4]中,
  195. * 然后迭代地调用函数static unsigned long sm4F() 进行32轮加密
  196. * 每一轮加密都需要使用之前的结果 ulbuf[i], ulbuf[i+1], ulbuf[i+2], ulbuf[i+3]
  197. * 和该轮的密钥 sk[i],产生出该轮的密文 ulbuf[i+4],
  198. * 最后的密文存储在ulbuf[35]~ulbuf[32]中,转换为字符数组的形式放入output中。
  199. */
  200. static void sm4_one_round(unsigned long sk[32],
  201.         unsigned char input[16],
  202.         unsigned char output[16])
  203. {
  204.         unsigned long i = 0;
  205.         unsigned long ulbuf[36];

  206.         //将128bit的明文分成4个32bit的字X1,X2,X3,X4
  207.         memset(ulbuf, 0, sizeof(ulbuf));
  208.         GET_ULONG_BE(ulbuf[0], input, 0);
  209.         GET_ULONG_BE(ulbuf[1], input, 4);
  210.         GET_ULONG_BE(ulbuf[2], input, 8);
  211.         GET_ULONG_BE(ulbuf[3], input, 12);

  212.         //进行32轮的轮操作
  213.         while (i < 32)
  214.         {
  215.                 ulbuf[i + 4] = sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
  216.                 i++;
  217.         }

  218.         PUT_ULONG_BE(ulbuf[35], output, 0);
  219.         PUT_ULONG_BE(ulbuf[34], output, 4);
  220.         PUT_ULONG_BE(ulbuf[33], output, 8);
  221.         PUT_ULONG_BE(ulbuf[32], output, 12);
  222. }

  223. /*
  224. * SM4 key schedule (128-bit, encryption) 设置加密秘钥
  225. */
  226. void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16])
  227. {
  228.         ctx->mode = SM4_ENCRYPT;   /*!< SM4_ENCRYPT 加密  SM4_DECRYPT解密 */
  229.         sm4_setkey(ctx->sk, key);
  230. }

  231. /*
  232. * SM4 key schedule (128-bit, decryption)
  233. */
  234. 设置解密秘钥 轮密钥的使用顺序相反
  235. void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16])
  236. {
  237.         int i;
  238.         ctx->mode = SM4_ENCRYPT;
  239.         sm4_setkey(ctx->sk, key);
  240.         for (i = 0; i < 16; i++)
  241.         {
  242.                 SWAP(ctx->sk[i], ctx->sk[31 - i]);
  243.         }
  244. }


  245. /*
  246. * SM4-ECB block encryption/decryption  
  247. * ECB模式密文被分割成分组长度相等的块(不足补齐),
  248. * 然后单独一个个加密,一个个输出组成密文。
  249. */
  250. int sm4_crypt_ecb(sm4_context *ctx,
  251.         int mode,
  252.         int length,
  253.         unsigned char *input,
  254.         unsigned char *output)
  255. {
  256.         int retlen = 0;
  257.         while (length > 0 )
  258.         {
  259.                 sm4_one_round(ctx->sk, input, output);
  260.                 input += 16;
  261.                 output += 16;
  262.                 length -= 16;
  263.                 retlen += 16;
  264.         }
  265.         return retlen;
  266. }

  267. /*
  268. * SM4-CBC buffer encryption/decryption
  269. * 循环模式(链式),前一个分组的密文和当前分组的明文操作后再加密,
  270. * 增强破解难度。(不容易主动攻击,安全性好于ECB,是SSL、IPSec的标准)
  271. */
  272. void sm4_crypt_cbc(sm4_context *ctx,
  273.         int mode,
  274.         int length,
  275.         unsigned char iv[16],
  276.         unsigned char *input,
  277.         unsigned char *output)
  278. {
  279.         int i;
  280.         unsigned char temp[16];

  281.         if (mode == SM4_ENCRYPT)
  282.         {
  283.                 while (length > 0)
  284.                 {
  285.                         for (i = 0; i < 16; i++)
  286.                                 output[i] = (unsigned char)(input[i] ^ iv[i]);

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

  289.                         input += 16;
  290.                         output += 16;
  291.                         length -= 16;
  292.                 }
  293.         }
  294.         else /* SM4_DECRYPT */
  295.         {
  296.                 while (length > 0)
  297.                 {
  298.                         memcpy(temp, input, 16);
  299.                         sm4_one_round(ctx->sk, input, output);

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

  302.                         memcpy(iv, temp, 16);

  303.                         input += 16;
  304.                         output += 16;
  305.                         length -= 16;
  306.                 }
  307.         }
  308. }


  309. //初始化密钥赋值 默认unsigned char key1[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
  310. Sm4EncDec::Sm4EncDec()
  311. {
  312.         memset(key, 0, 16);
  313.         unsigned char key1[16] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
  314.         memcpy(key, key1,16);
  315. }

  316. Sm4EncDec::Sm4EncDec(unsigned char _key[])
  317. {
  318.         memset(key,0,16);
  319.         if (_key == NULL)
  320.                 Sm4EncDec();
  321.         memcpy(key, _key, 16);
  322. }

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

  328.         FILE* InFile = fopen(SrcPath.c_str(), "rb");
  329.         if (InFile == NULL)
  330.         {
  331.                 return;
  332.         }

  333.         FILE* OutFile = fopen(DestPath.c_str(), "wb");
  334.         if (OutFile == NULL)
  335.         {
  336.                 fclose(InFile);
  337.                 return;
  338.         }

  339.         fseek(InFile, 0, SEEK_END);
  340.         long filelen = ftell(InFile);
  341.         fseek(InFile, 0, SEEK_SET);

  342.         long last = filelen;
  343.         long offset = 1024;

  344.         unsigned char* SrcBuffer = new unsigned char[offset];
  345.         unsigned char*  DestBuffer = new  unsigned char[offset];
  346.         sm4_context ctx;

  347.         while (last > 0)
  348.         {
  349.                 memset(SrcBuffer, 0, offset);
  350.                 memset(DestBuffer, 0, offset);
  351.                 offset = std::min(offset, last);

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

  354.                 //设置秘钥
  355.                 sm4_setkey_enc(&ctx, key);
  356.                 //加密
  357.                 int elen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  358.                 fwrite(DestBuffer, elen, 1, OutFile);
  359.         }
  360.         delete[]SrcBuffer;
  361.         delete[]DestBuffer;
  362.         fclose(InFile);
  363.         fclose(OutFile);

  364.         return;
  365. }

  366. //解密
  367. void Sm4EncDec::Decrypt(std::string DestPath, std::string SrcPath)
  368. {
  369.         if (SrcPath.empty())
  370.                 return;
  371.        
  372.         FILE* InFile = fopen(SrcPath.c_str(), "rb");
  373.         if (InFile == NULL)
  374.         {
  375.                 return;
  376.         }

  377.         FILE* OutFile = fopen(DestPath.c_str(), "wb");
  378.         if (OutFile == NULL)
  379.         {
  380.                 fclose(InFile);
  381.                 return;
  382.         }

  383.         fseek(InFile, 0, SEEK_END);
  384.         long filelen = ftell(InFile);
  385.         fseek(InFile, 0, SEEK_SET);

  386.         long last = filelen;
  387.         long offset = 1024;
  388.         sm4_context ctx;
  389.         unsigned char* SrcBuffer = new unsigned char[offset];
  390.         unsigned char*  DestBuffer = new  unsigned char[offset];
  391.         while (last > 0)
  392.         {
  393.                 memset(SrcBuffer, 0, offset);
  394.                 memset(DestBuffer, 0, offset);

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

  396.                 fread(SrcBuffer, offset, 1, InFile);

  397.                 sm4_setkey_dec(&ctx, key);
  398.                 int dlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  399.                 fwrite(DestBuffer, dlen, 1, OutFile);
  400.                 last -= offset;
  401.         }
  402.         delete[]SrcBuffer;
  403.         delete[]DestBuffer;
  404.         fclose(InFile);
  405.         fclose(OutFile);
  406.         return;
  407. }

  408. //加密
  409. void Sm4EncDec::Encrypt(std::string SrcPath)
  410. {
  411.         FILE* InFile = fopen(SrcPath.c_str(), "rb+");
  412.         if (InFile == NULL)
  413.         {
  414.                 return;
  415.         }
  416.         fseek(InFile, 0, SEEK_END);
  417.         int filelen = ftell(InFile);
  418.         fseek(InFile, 0, SEEK_SET);
  419.        
  420.         int last = filelen;
  421.         int offset = 1024;

  422.         unsigned char* SrcBuffer = new unsigned char[offset];
  423.         unsigned char* DestBuffer = new unsigned char[offset];

  424.         sm4_context ctx;

  425.         int fileindex = 0;
  426.        
  427.         while (last > 0)
  428.         {
  429.                 memset(SrcBuffer, 0, offset);
  430.                 memset(DestBuffer, 0, offset);

  431.                 offset = std::min(offset, last);
  432.                
  433.                 fseek(InFile, fileindex,SEEK_SET);

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

  435.                 fileindex = ftell(InFile);  //读位置
  436.        
  437.                 //设置秘钥
  438.                 sm4_setkey_enc(&ctx, key);
  439.                 //加密
  440.                 int retlen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  441.                 fseek(InFile, fileindex - offset, SEEK_SET);
  442.                
  443.                 int wn = fwrite(DestBuffer, retlen,1, InFile);
  444.                 fseek(InFile, fileindex, SEEK_SET);

  445.                 last -= offset;
  446.         }
  447.         fclose(InFile);
  448.         return;
  449. }

  450. //解密
  451. void Sm4EncDec::Decrypt( std::string SrcPath)
  452. {
  453.         FILE* InFile = fopen(SrcPath.c_str(), "rb+");
  454.        
  455.         if (InFile == NULL)
  456.         {
  457.                 return;
  458.         }
  459.         sm4_context ctx;

  460.         fseek(InFile, 0, SEEK_END);
  461.         int filelen = ftell(InFile);
  462.         fseek(InFile, 0, SEEK_SET);
  463.        
  464.         int last = filelen;
  465.         int offset = 1024;

  466.         unsigned char* SrcBuffer = new unsigned char[offset];
  467.         unsigned char* DestBuffer = new unsigned char[offset];

  468.         int fileindex =0;
  469.        
  470.         while (last > 0)
  471.         {
  472.                 memset(SrcBuffer, 0, offset);
  473.                 memset(DestBuffer, 0, offset);

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

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

  478.                 sm4_setkey_dec(&ctx, key);
  479.                 int retlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, SrcBuffer, DestBuffer); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  480.                 fseek(InFile, fileindex - offset,SEEK_SET);
  481.                 int wn = fwrite(DestBuffer, retlen,1, InFile);
  482.                 fseek(InFile, fileindex, SEEK_SET);

  483.                 last -= offset;
  484.         }
  485.        
  486.         fclose(InFile);
  487.         return;
  488. }


  489. //加密字符串
  490. int Sm4EncDec::Encrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen)
  491. {
  492.         if (srcStr == NULL)
  493.                 return 0;
  494.         int last = srcLen;
  495.         int offset = 128;
  496.         unsigned char* dest = destBuf;
  497.         unsigned char* src = srcStr;
  498.         sm4_context ctx;
  499.         int retlen = 0;
  500.         while (last > 0)
  501.         {
  502.                 offset = std::min(offset, last);

  503.                 last -= offset;
  504.                 //设置秘钥
  505.                 sm4_setkey_enc(&ctx, key);
  506.                 //加密
  507.                 int elen = sm4_crypt_ecb(&ctx, SM4_ENCRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  508.                 src += offset;
  509.                 dest += offset;
  510.                 retlen += elen;
  511.         }
  512.         return retlen;
  513. }

  514. //解密字符串
  515. int Sm4EncDec::Decrypt(unsigned char *destBuf, unsigned char *srcStr, int srcLen)
  516. {
  517.         if (srcStr == NULL)
  518.                 return 0;
  519.         int last = srcLen;
  520.         int offset = 128;
  521.         int retlen = 0;

  522.         unsigned char*  dest = destBuf;
  523.         unsigned char*  src = srcStr;
  524.         sm4_context ctx;

  525.         while (last > 0)
  526.         {
  527.                 offset = std::min(offset, last);

  528.                 last -= offset;
  529.                 sm4_setkey_dec(&ctx, key);
  530.                 int dlen = sm4_crypt_ecb(&ctx, SM4_DECRYPT, offset, src, dest); //SM4_ENCRYPT为加密 SM4_DECRYPT为解密

  531.                 src += offset;
  532.                 dest += offset;
  533.                 retlen += dlen;
  534.         }
  535.         return retlen;
  536. }

  537. #pragma pack()
复制代码

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

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



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则