【现代密码学】实验二 SM4分组密码算法(含java代码实现)

本人一直想找时间系统整理一下之前做过的一些实验,便于后续用到的时候可以尽快的使用,po出来也便于大家交流学习,有问题欢迎交流指正,与诸君共勉!

【现代密码学】实验二 SM4分组密码算法

实验目的

(1)掌握SM4分组密码算法的扩散和混淆原理;

(2)熟悉分组密码算法的4种工作模式;

(3)了解SM4分组密码算法的雪崩效应。

实验原理

SM4算法:

SM4算法是用于WAPI的分组密码算法,是2006年我国国家密码管理局公布的国内第一个商用密码算法。

SM4是分组密码算法,其中,数据分组长度为128比特,密钥分组长度也为128比特。加密算法与密钥扩展算法都采用32轮迭代结构,以字节(8位)和字(32位)为单位进行数据处理。

1.基本运算

SM4密码算法的基本运算有模2加和循环移位。  

(1)模二加:记为,为32位逐比特异或运算。

(2)循环移位:<<<i,把32位字循环左移i位。

2.基本密码部件

(1)S盒

S盒是以字节为单位的非线性替换,其密码学的作用是混淆,它的输入和输出都是8位的字节。设输入字节位a,输出字节为b,则S盒的运算可表示为

S盒的替换规则如表1所示,例如输入为EF,则输出为第E行和第F列交叉处的值84,即S(EF)=84。

表1 SM4密码算法的S盒

(2)非线性变换τ

非线性变换τ是以字为单位的非线性替换,它由4个S盒并置构成。设输入为A=(a0,a1,a2,a3)(4个32位的字),输出为B=(b0,b1,b2,b3)(4个32位的字),则

(3)线性变换部件L

线性变换部件LS是以字为处理单位的线性变换,其输入输出都是32位的字,它的密码学作用是扩散。

设L的输入为字B,输出为字C,则

(4)合成变换T

合成变换T由非线性变换τ和线性变换L复合而成,数据处理的单位是字。设输入为字X,则先对X进行非线性τ变换,再进行线性L变换。记为

由于合成变换T是非线性变换和线性变换L的复合,所以它综合起到混淆和扩散的作用,从而可提高密码的安全性。

3.轮函数

轮函数由上述基本密码部件构成。设轮函数F的输入为4个32单位字(X0,X1,X2,X3),共128位,轮密钥为一个32位的字rk。输出也是一个32位的字,由下式给出:

F(X0,X1,X2,X3,rk)= X0⊕T(X1X2X3⊕rk)

根据公式(3),有

F(X0,X1,X2,X3,rk)= X0⊕L(τ(X1X2X3⊕rk))

B=(X1X2X3⊕rk),根据式(1)和式(2),有

F(X0,X1,X2,X3,rk)=

轮函数的结构如图1、图2所示。

4.加密算法

加密算法采用32轮迭代结构,每轮使用一个轮密钥。

设输入的明文为4个字(X0,X1,X2,X3)(128比特长),输入的轮密钥为rki(i=0,1,...,31),共32个字。输出的密文为4个字(Y0,Y1,Y2,Y3)(128比特长)。加密算法可描述如下:

为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序处理R:

   加密算法的框图如图1、图2所示。

图2 SM4算法的加密算法和轮函数结构图

5.解密算法

解密算法与加密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

算法的输入为密文(Y0,Y1,Y2,Y3)和轮密钥rki(i=31,30,...,0),输出为明文(X0,X1,X2,X3),则(Y0,Y1,Y2,Y3)=X35,X34,X33,X32。为了便于与加密算法对照,解密算法中仍然用Xi表示密文,于是可得到如下的解密算法。

解密算法:

与加密算法之后需要一个反序处理同样的道理,在解密算法之后也需要一个反序处理R:

X0,X1,X2,X3)=R(X3,X2,X1,X0)

  1. 密钥扩展算法

SM4算法加密时输入128位的密钥,采用32轮迭代结构,每一轮使用一个32位的轮密钥,共使用32个轮密钥。使用密钥扩展算法,从加密密钥产生出32个轮密钥。

  • 常数FK

在密钥扩展中使用如下的常数:

  • 固定参数CK

共使用32个固定参数CKi,每个CKi是一个字,其产生规则如下:

的第j个字节,即

这32个固定参数如下(十六进制):

0070E15, 1C232A31, 383F464D, 545B6269

70777E85, 8C939AA1, A8AFB6BD, C4CBD2D9

E0E7EEF5, FC030A11, 181F262D, 343B4249

50575E65, 6C737A81, 888F969D, A4ABB2B9

C0C7CED5, DCE3EAF1, F8FF060D, 141B2229

30373E45, 4C535A61, 686F767D, 848B9299

A0A7AEB5, BCC3CAD1, D8DFE6ED, F4FB0209

10171E25, 2C333A41, 484F565D, 646B7279

6.密钥扩展算法

设输入的加密密钥为MK=(MK0,MK1,MK2,MK3),输出轮密钥为rki(i=0,1,...,31),密钥扩展算法可描述如下,其中,Ki(i=0,1,...,35)为中间数据:

a. (

b.

其中的变换与加密算法轮函数中的T基本相同,只将其中的线性变化L修改为以下的:

密钥扩展算法的结构与加密算法的结构类似,也是采用了32轮的迭代处理。

工作模式:

从国密算法中可以知道,分组加密是对128比特的明文输入和128比特的加密密钥进行处理,生成128比特的密文输出,即分组加密算法只能加密固定长度的明文分组块。

但实际情况往往是明文的长度会远超过密码分组的长度,因此需要对分组加密算法进行迭代,才能将明文全部加密,采用的迭代方法就是分组加密算法的加密工作模式。

ECB模式:

Electronic CodeBook mode,电子密码本模式

ECB模式是将明文分成固定长度的组块,然后对每个明文分组块使用相同的密钥进行独立加密或解密,且该加密的结果将直接作为密文分组。
ECB模式是最简单的分组加密算法的一种工作模式。

ECB模式的工作原理:

图3 ECB模式加密过程

CBC模式

CBC(Cipher Block Chaining)模式,即密码分组链接模式。该模式首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。只有第一个明文分组特殊,需要提前为其生成一个与分组长度相同的比特序列,进行XOR运算,这个比特序列称为初始化向量(Initialization Vector),简称IV。

CBC模式的加密过程:

CFB模式

CFB(Cipher FeedBack)模式,即密文反馈模式。该模式首先将前一个密文分组进行加密,再与当前明文分组进行XOR运算,来生成密文分组。同样CFB模式也需要一个IV。

OFB模式

OFB(Output FeedBack)模式,即输出反馈模式。该模式会产生一个密钥流,即将密码算法的前一个输出值,做为当前密码算法的输入值。该输入值再与明文分组进行XOR运行,计算得出密文分组。该模式需要一个IV,进行加密后做为第一个分组的输入。

扩散

扩散就是让明文中的每一位影响密文中的许多位,或者说让密文中的每一位受明文中的许多位的影响.这样可以隐蔽明文的统计特性。

混淆

混淆就是将密文与密钥之间的统计关系变得尽可能复杂,使得对手即使获取了关于密文的一些统计特性,也无法推测密钥。使用复杂的非线性代替变换可以达到比较好的混淆效果,而简单的线性代替变换得到的混淆效果则不理想。

雪崩效应

雪崩效应(avalanche effect),密码学术语,指加密算法(尤其是块密码和加密散列函数)的一种理想属性。雪崩效应是指当输入发生最微小的改变(例如,反转一个二进制位)时,也会导致输出的不可区分性改变(输出中每个二进制位有50%的概率发生反转)。

实验步骤

实验基本方法:

(1)用java语言编写SM4分组密码算法;

(2)编程实现对文件的加密,加密模式为电码本或分组链接模式;

(3)额外要求:编程实现密码反馈模式和输出反馈模式。

说明:

(1)SM4分组密码算法可以自编,也可以网上下载现成算法;

(2)工作模式的程序可以自编,也可以利用cryptopp加密包编程。

实验步骤:

(1)编程实现SM4分组密码算法;

(2)改变1位明文观察输出SM4分组密码算法的32轮输出;

(3)改变1位密钥观察输出SM4分组密码算法的32轮输出;

(4)在电码本模式、分组链接模式、密码反馈模式和输出反馈模式中,在最少128个分组的明文中,观察当一个密文分组错误时,还原的明文有几个分组错误。

实验代码

 sm4.h文件
#pragma once
#ifdef __cplusplus
#endif
#include <stdbool.h>
#include <stdint.h>
#include <string>

void sm4_ecb_encrypt(const uint8_t key[16], size_t len, const uint8_t *plain, uint8_t *cipher);
void sm4_ecb_decrypt(const uint8_t key[16], size_t len, const uint8_t *cipher, uint8_t *plain);

void sm4_cbc_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *plain, uint8_t *cipher);
void sm4_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *cipher, uint8_t *plain);

void sm4_cfb_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *plain, uint8_t *cipher);
void sm4_cfb_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *cipher, uint8_t *plain);

void sm4_ofb_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *plain, uint8_t *cipher);
void sm4_ofb_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *cipher, uint8_t *plain);



#define SM4_MIN_MODE SM4_ECB_MODE
#define SM4_ECB_MODE 1
#define SM4_CBC_MODE 2
#define SM4_CFB_MODE 3
#define SM4_OFB_MODE 4
#define SM4_MAX_MODE SM4_OFB_MODE

typedef struct {
    uint32_t rkey[32];
    uint8_t iv[16];
    uint8_t mode;
} sm4_ctx_t;

void sm4_close(sm4_ctx_t *ctx);
int sm4_init(sm4_ctx_t *ctx, uint8_t mode, const uint8_t key[16], const uint8_t iv[16]);
int sm4_encrypt(sm4_ctx_t *ctx, size_t len, const uint8_t *plain, uint8_t *cipher);
int sm4_decrypt(sm4_ctx_t *ctx, size_t len, const uint8_t *cipher, uint8_t *plain);

# ifdef __cplusplus

# endif

#ifndef __MasterEncoder_H__
#define __MasterEncoder_H__
#include <mutex>
#include <string>
using namespace std;
class MasterEncoder
{
public:
	static MasterEncoder* getInstance();
	MasterEncoder();
	~MasterEncoder();

	void setSignAndKey(char* sign, int signLen, unsigned char key);

	void decode(unsigned char* data, long size);
	void encode(unsigned char* data, long size);

	void writePDF(const string& filePath, unsigned char* data, long size);
	unsigned char* readPDF(const string& filepath, long& size);

public:
	void encodePDF(const string& pdfPath, const string& savePath);
	void decodePDF(const string& pdfPath, const string& savePath);
	unsigned char* decodePDF(const string& pdfPath, long& size);

private:
	static MasterEncoder* _instance;
	static mutex _mtx;

	unsigned char _codeKey;
	char* _sign;
	int _signLen;

};


#endif // !MasterEncoder

sm4.cpp文件
#include "sm4.h"
#include <stdio.h>
#include<iostream>
/** SBox */
static const uint8_t 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,
};

/** 数据类型转换(char to int)八位(字节数组)转32位(字) */
static inline uint32_t _load_le_u32(const uint8_t bs[4]) {
	return *(uint32_t*)bs;
}
/** 数据类型转换(char to int)八位(字节数组)转32位(字) */
static inline uint32_t _load_be_u32(const uint8_t bs[4]) {
	return ((uint32_t)bs[0] << 24) | ((uint32_t)bs[1] << 16) | ((uint32_t)bs[2] << 8) | bs[3];
}
/** 数据类型转换(int to char)32位(字)转八位(字节数组) */
static inline void _store_le_u32(const uint32_t x, uint8_t bs[4]) {
	*(uint32_t*)bs = x;
}
/** 数据类型转换(int to char)32位(字)转八位(字节数组) */
static inline void _store_be_u32(const uint32_t x, uint8_t bs[4]) {
	bs[0] = (x >> 24) & 0xff;
	bs[1] = (x >> 16) & 0xff;
	bs[2] = (x >> 8) & 0xff;
	bs[3] = (x) & 0xff;
}
/** 数据类型转换(char to int)八位(字节数组)转64位*/
static inline void _store_le_u64(const uint64_t x, uint8_t bs[8]) {
	*(uint64_t*)bs = x;
}
/** 数据类型转换(char to int)八位(字节数组)转64位*/
static inline void _store_be_u64(const uint64_t x, uint8_t bs[8]) {
	bs[0] = (x >> 56) & 0xff;
	bs[1] = (x >> 48) & 0xff;
	bs[2] = (x >> 40) & 0xff;
	bs[3] = (x >> 32) & 0xff;
	bs[4] = (x >> 24) & 0xff;
	bs[5] = (x >> 16) & 0xff;
	bs[6] = (x >> 8) & 0xff;
	bs[7] = (x) & 0xff;
}
/**将x左移n位 */
static inline uint32_t _lshift(uint32_t x, int n) {
	return (x << n) | (x >> (32 - n));
}
/**将x右移n位 */
static inline uint32_t _rshift(uint32_t x, int n) {
	return (x << (32 - n)) | (x >> n);
}

/**求out和in按位异或的结果 结果存在out*/
static inline void _xor_block(uint8_t *out, const uint8_t *in, size_t len) {
	for (size_t i = 0; i < len; ++i) {
		out[i] ^= in[i];
	}
}
/*转一位16进制*/
static inline char _hex(uint8_t n) {
	static const char HEX[16] = {
		'0', '1', '2', '3', '4', '5', '6', '7',
		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
	};
	return HEX[n];
}
// expand uint8 data to hex format in place, so data should have len * 2 space
//八位扩展到16位形式
static inline void _expand_hex(uint8_t *data, size_t len) {
	for (size_t i = 0; i < len; ++i) {
		size_t j = len - 1 - i;
		uint8_t x = data[j];
		data[j * 2] = (uint8_t)_hex((x >> 4) & 0xf);
		data[j * 2 + 1] = (uint8_t)_hex(x & 0xf);
	}
}
/**
 * .
 * 
 * \param x 32位输入
 * \return 
 */
static uint32_t _sbox(uint32_t x) {
    uint8_t u[4];
    *(uint32_t *)u = x;
    u[0] = SBOX[u[0]];
    u[1] = SBOX[u[1]];
    u[2] = SBOX[u[2]];
    u[3] = SBOX[u[3]];
    return *(uint32_t *)u;
}

/** 线性变换L.输入输出都是32位的字*/
static inline uint32_t _st1(uint32_t x) {
    x = _sbox(x);
    return x ^ _lshift(x, 2) ^ _lshift(x, 10) ^ _lshift(x, 18) ^ _lshift(x, 24);
}

/** 密码扩展算法使用的线性变换.*/
static inline uint32_t _st2(uint32_t x) {
    x = _sbox(x);
    return x ^ _lshift(x, 13) ^ _lshift(x, 23);
}

/**常数FK*/
static const uint32_t FK[4] = {
    0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
};

/**32个固定参数CK_i,每个CK_i是一个字*/
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,
};

/**
 * 密钥扩展算法得到轮密钥.
 * \param key 初始密钥
 * \param rkey 轮密钥
 */
static void sm4_calc_key(const uint8_t key[16], uint32_t rkey[32]) {
    uint32_t x[5];
    /**
      * 将输入的密钥每32比特合并(得到MK_0,MK_1,MK_2,MK_3),
      */
    x[0] = _load_be_u32(key);
    x[1] = _load_be_u32(key + 4);
    x[2] = _load_be_u32(key + 8);
    x[3] = _load_be_u32(key + 12);
    /**
     * 并异或FK 得到(K_0,K_1,K_2,K_3)
    ( K_0,K_1,K_2,K_3)=(MK_0⊕FK_0,MK_1⊕FK_1,MK_2⊕FK_2,MK_3⊕FK_3)
     */
    x[0] ^= FK[0];
    x[1] ^= FK[1];
    x[2] ^= FK[2];
    x[3] ^= FK[3];
    /**
     * 32轮密钥拓展
     * For i=0,1,...,31 Do rk_i=K_(i+4)=K_i⊕T' (K_(i+1)⊕K_(i+2)⊕K_(i+3)⊕CK_i)
     */
    cout << "轮密钥生成!" << endl;

    for (int i = 0; i < 32; ++i) {
        uint32_t *y0 = x + (i % 5);
        uint32_t *y1 = x + ((i + 1) % 5);
        uint32_t *y2 = x + ((i + 2) % 5);
        uint32_t *y3 = x + ((i + 3) % 5);
        uint32_t *y4 = x + ((i + 4) % 5);

        *y4 = *y0 ^ _st2(*y1 ^ *y2 ^ *y3 ^ CK[i]);
        rkey[i] = *y4;
        cout << "第" << i + 1 << "个轮密钥: ";
        printf("%02x", rkey[i]);
        cout << endl;
    }
  
}

/**对轮密钥进行反序变换.*/
static inline void sm4_rev_key(uint32_t rkey[32]) {
    for (int i = 0; i < 16; ++i) {
        uint32_t t = rkey[i];
        rkey[i] = rkey[31 - i];
        rkey[31 - i] = t;
    }
}

/**
 * 用轮密钥对 in 加密 为 out
 * \param rkey
 * \param in
 * \param out
 */
static void sm4_calc_block(const uint32_t rkey[32], const uint8_t in[16], uint8_t out[16]) {
   /*
    cout << endl << "输 入 明 文: ";
    for (int i = 0; i < 16; i++)
        printf("%02x ", in[i]);
    cout << endl;
    */
    uint32_t x[5];
    // 将32比特数拆分成4个8比特数
    x[0] = _load_be_u32(in);
    x[1] = _load_be_u32(in + 4);
    x[2] = _load_be_u32(in + 8);
    x[3] = _load_be_u32(in + 12);
   
    for (int i = 0; i < 32; ++i) {
        uint32_t *y0 = x + (i % 5);
        uint32_t *y1 = x + ((i + 1) % 5);
        uint32_t *y2 = x + ((i + 2) % 5);
        uint32_t *y3 = x + ((i + 3) % 5);
        uint32_t *y4 = x + ((i + 4) % 5);
        //轮函数F(X_0, X_1, X_2, X_3, rk) = X_0⊕L(τ(X_1⊕X_2⊕X_3⊕rk))
       // cout << "第" << i+1 << "个轮密钥rkey["<<i<<"]: ";
        
        *y4 = *y0 ^ _st1(*y1 ^ *y2 ^ *y3 ^ rkey[i]);
        //cout << y1;
        /*
        cout << "第" << i + 1 << "轮输出: ";
        _store_be_u32(x[0], out);
        _store_be_u32(x[4], out + 4);
        _store_be_u32(x[3], out + 8);
        _store_be_u32(x[2], out + 12);
        printf("%02x ", x[2]);  printf("%02x ", x[3]); printf("%02x ", x[4]); printf("%02x ", x[0]);
        cout << endl;
        //printf("%02x ", y1); printf("%02x ", y2); printf("%02x ", y3); printf("%02x ", y4);
       */
    }
    _store_be_u32(x[0], out);
    _store_be_u32(x[4], out + 4);
    _store_be_u32(x[3], out + 8);
    _store_be_u32(x[2], out + 12);
    cout << "最终该分组加密结果(将第32轮结果反序后):" << endl;
   // cout << "最终加密结果(将第32轮结果反序后):" << endl;
    printf("%02x ", x[0]);  printf("%02x ", x[4]); printf("%02x ", x[3]); printf("%02x ", x[2]);
    cout << endl;
}


/** ECB模式 加密 (已生成的轮密钥做参数)(过程调用 功能函数)*/
static inline void _ecb(const uint32_t* rkey, size_t len, const uint8_t* in, uint8_t* out) {
    for (size_t i = 0; i < len; i += 16) {
        sm4_calc_block(rkey, in + i, out + i);//加密
    }
}

/**
 * ECB模式加密.(初始密钥做参数)
 * \param key 初始密钥
 * \param len 
 * \param plain 明文
 * \param cipher 密文
 */
void sm4_ecb_encrypt(const uint8_t key[16], size_t len, const uint8_t* plain, uint8_t* cipher) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);//初始化轮密钥
    _ecb(rkey, len, plain, cipher);
    // memset(rkey, 0, sizeof(rkey));
}
/**
 * ECB模式解密
 * \param key 初始密钥
 * \param len 
 * \param cipher 密文
 * \param plain 明文
 */
void sm4_ecb_decrypt(const uint8_t key[16], size_t len, const uint8_t* cipher, uint8_t* plain) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);//初始化轮密钥
    sm4_rev_key(rkey);
    _ecb(rkey, len, cipher, plain);
    // memset(rkey, 0, sizeof(rkey));
}

/**CBC模式 加密(已生成的轮密钥做参数).工具函数 */
static inline void _cbc_encrypt(const uint32_t *rkey, uint8_t *iv, size_t len, const uint8_t *plain, uint8_t *cipher) {
    for (size_t i = 0; i < len; i += 16) {
        _xor_block(iv, plain + i, 16);//iv和plain异或  结果存在iv
        sm4_calc_block(rkey, iv, cipher + i); //加密
        memcpy(iv, cipher + i, 16);
    }
}

/** CBC 模式 解密 工具函数*/
static inline void _cbc_decrypt(const uint32_t *rkey, uint8_t *iv, size_t len, const uint8_t *cipher, uint8_t *plain) {
    for (size_t i = 0; i < len; i += 16) {
        sm4_calc_block(rkey, cipher + i, plain + i);
        _xor_block(plain + i, iv, 16);
        memcpy(iv, cipher + i, 16);
    }
}


/**
 * CBC 密码块链 (Cipher Block Chaining) 模式 加密
 * 无法单独对一个中间的明文分组进行加密
明文的微小改变会导致其后全部密文分组发生改变
 * \param key 初始密钥
 * \param iv 初始向量
 * \param len 分组数
 * \param plain 明文
 * \param cipher 密文
 */
void sm4_cbc_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t* plain, uint8_t* cipher) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);//初始化轮密钥
    uint8_t out[16];
    memcpy(out, iv, 16);
    _cbc_encrypt(rkey, out, len, plain, cipher);
    // memset(rkey, 0, sizeof(rkey));
    // memset(out, 0, sizeof(out));
}

/**
 * CBC 密码块链 (Cipher Block Chaining) 模式 解密算法.
 * \param key 初始密钥
 * \param iv 初始向量
 * \param len 分组数
 * \param cipher 密文
 * \param plain 明文
 */
void sm4_cbc_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t* cipher, uint8_t* plain) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);
    sm4_rev_key(rkey);
    uint8_t out[16];
    memcpy(out, iv, 16);
    _cbc_decrypt(rkey, out, len, cipher, plain);
    // memset(rkey, 0, sizeof(rkey));
    // memset(out, 0, sizeof(out));
}


/**
 * CFB模式 加密.(工具函数)
 加密:将前一个密文分组(或初始化向量 IV)进行再加密;
将明文分组和上一步处理得到的再加密的密文分组进行异或。
 */
static inline void _cfb_encrypt(const uint32_t *rkey, uint8_t *iv, size_t len, const uint8_t *plain, uint8_t *cipher) {
    for (size_t i = 0; i < len; i += 16) {
        sm4_calc_block(rkey, iv, cipher + i);
        _xor_block(cipher + i, plain + i, 16);
        memcpy(iv, cipher + i, 16);
    }
}


/**
 * CFB模式的解密过程几乎就是颠倒的CBC模式的加密过程。.
 * CFB模式 解密.(工具函数)
 * \param rkey
 * \param iv
 * \param len
 * \param cipher
 * \param plain
 */
static inline void _cfb_decrypt(const uint32_t *rkey, uint8_t *iv, size_t len, const uint8_t *cipher, uint8_t *plain) {
    for (size_t i = 0; i < len; i += 16) {
        sm4_calc_block(rkey, iv, plain + i);
        _xor_block(plain + i, cipher + i, 16);
        memcpy(iv, cipher + i, 16);
    }
}


/**
 * CFB模式 加密
 * \param key
 * \param iv
 * \param len
 * \param plain
 * \param cipher
 */
void sm4_cfb_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *plain, uint8_t *cipher) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);
    uint8_t out[16];
    memcpy(out, iv, 16);
    _cfb_encrypt(rkey, out, len, plain, cipher);
    // memset(rkey, 0, sizeof(rkey));
    // memset(out, 0, sizeof(out));
}
/**
 * CFB解密函数.
 * \param key 初始密钥
 * \param iv 初始向量
 * \param len 分组数
 * \param cipher 密文
 * \param plain 明文
 */
void sm4_cfb_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *cipher, uint8_t *plain) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);
    uint8_t out[16];
    memcpy(out, iv, 16);
    _cfb_decrypt(rkey, out, len, cipher, plain);
}


/**
 * .OFB模式 加密.(工具函数)
 * 加密:先将初始化向量 IV 用密钥加密生成密钥流
再将密钥流与明文流异或得到密文流
 * \param rkey
 * \param iv
 * \param len 明文分组数
 * \param in
 * \param out
 *//**OFB模式 加密.(工具函数)*/
static inline void _ofb(const uint32_t* rkey, uint8_t* iv, size_t len, const uint8_t* in, uint8_t* out) {
    for (size_t i = 0; i < len; i += 16) {
        sm4_calc_block(rkey, iv, out + i);
        memcpy(iv, out + i, 16);
        _xor_block(out + i, in + i, 16);
    }
}

/**
 * OFB模式 加密.
 * \param key 初始密钥
 * \param iv 初始向量
 * \param len 长度
 * \param plain 明文
 * \param cipher 密文
 */
void sm4_ofb_encrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *plain, uint8_t *cipher) {
    uint32_t rkey[32];
    sm4_calc_key(key, rkey);
    uint8_t out[16];
    memcpy(out, iv, 16);
    _ofb(rkey, out, len, plain, cipher);
    // memset(rkey, 0, sizeof(rkey));
    // memset(out, 0, sizeof(out));
}
/**
 * OFB模式 解密
 * \param key 初始密钥
 * \param iv 初始向量
 * \param len 长度
 * \param cipher 密文
 * \param plain 明文
 */
void sm4_ofb_decrypt(const uint8_t key[16], const uint8_t iv[16], size_t len, const uint8_t *cipher, uint8_t *plain) {
    sm4_ofb_encrypt(key, iv, len, cipher, plain);
}


#define SM4_ENCRYPT 0x10
#define SM4_DECRYPT 0x20

void sm4_close(sm4_ctx_t *ctx) {
    memset(ctx, 0, sizeof(sm4_ctx_t));
}
/**
 * .SM4 初始化
 * \param ctx
 * \param mode 模式选择参数
 * \param key 初始密钥
 * \param iv 初始向量
 * \return 
 */
int sm4_init(sm4_ctx_t *ctx, uint8_t mode, const uint8_t key[16], const uint8_t iv[16]) {
    if (mode < SM4_ECB_MODE || mode > SM4_OFB_MODE) {
        return -1;
    }
    if (mode == SM4_ECB_MODE && iv != NULL) {
        return -1;
    }
    if (mode != SM4_ECB_MODE && iv == NULL) {
        return -1;
    }
    ctx->mode = mode;
    sm4_calc_key(key, ctx->rkey);
    if (iv != NULL) {
        memcpy(ctx->iv, iv, 16);
    } else {
        memset(ctx->iv, 0, 16);
    }
    return 0;
}

/**
 * SM4加密 可选择四种方式.
 * \param ctx
 * \param len 长度
 * \param plain 明文
 * \param cipher 密文
 * \return 
 */
int sm4_encrypt(sm4_ctx_t *ctx, size_t len, const uint8_t *plain, uint8_t *cipher) {
    if ((ctx->mode & 0xf0) == 0) {
        ctx->mode |= SM4_ENCRYPT;
    }
    if ((ctx->mode & 0xf0) != SM4_ENCRYPT) {
        return -1;
    }

    uint8_t m = ctx->mode & 0x0f;
    if (m == SM4_ECB_MODE) {
        _ecb(ctx->rkey, len, plain, cipher);
    } else if (m == SM4_CBC_MODE) {
        _cbc_encrypt(ctx->rkey, ctx->iv, len, plain, cipher);
    } else if (m == SM4_CFB_MODE) {
        _cfb_encrypt(ctx->rkey, ctx->iv, len, plain, cipher);
    } else if (m == SM4_OFB_MODE) {
        _ofb(ctx->rkey, ctx->iv, len, plain, cipher);
    } else {
        return -1;
    }
    return 0;
}

/**
 * SM4解密函数. 可选择四种工作模式
 * \param ctx 模式选择等函数
 * \param len 长度
 * \param cipher 密文
 * \param plain 明文
 * \return 
 */
int sm4_decrypt(sm4_ctx_t *ctx, size_t len, const uint8_t *cipher, uint8_t *plain) {
    uint8_t m = ctx->mode & 0x0f;
    if ((ctx->mode & 0xf0) == 0) {
        ctx->mode |= SM4_DECRYPT;
        if (m != SM4_CFB_MODE && m != SM4_OFB_MODE) {
            sm4_rev_key(ctx->rkey);
        }
    }
    if ((ctx->mode & 0xf0) != SM4_DECRYPT) {
        return -1;
    }

    if (m == SM4_ECB_MODE) {
        _ecb(ctx->rkey, len, cipher, plain);
    } else if (m == SM4_CBC_MODE) {
        _cbc_decrypt(ctx->rkey, ctx->iv, len, cipher, plain);
    } else if (m == SM4_CFB_MODE) {
        _cfb_decrypt(ctx->rkey, ctx->iv, len, cipher, plain);
    } else if (m == SM4_OFB_MODE) {
        _ofb(ctx->rkey, ctx->iv, len, cipher, plain);
    } else {
        return -1;
    }
    return 0;
}

test_sm4.cpp文件
#include <stdio.h>
#include<iostream>
#include "sm4.h"
#include <fstream>
#include <string>
#include <cstring>
#pragma warning (disable : 4996)
using namespace std;
#include<stdlib.h>



class SM4Test {
    
public:
    //将密文/明文最后一组 长度 填充为16位
    static char* PKCS5Padding(string strParams)
    {
        int nRaw_size = strParams.size();
        int i = 0, j = nRaw_size / 16 + 1, k = nRaw_size % 16;
        int nPidding_size = 16 - k;
        char* szArray;
        szArray = (char*)malloc(nRaw_size + nPidding_size);
        memcpy(szArray, strParams.c_str(), nRaw_size);
        for (int i1 = nRaw_size; i1 < (nRaw_size + nPidding_size); i1++)
        {
            // PKCS5Padding 算法:
            szArray[i1] = nPidding_size;
        }
        return szArray;
    }


    static void menu0() {
        cout<<"|※欢迎使用SM4加解密系统,请选择您的操作:   |"<<endl;
        cout<<("|      1.对文本加密                         |")<<endl;
        cout<<"|       2.对文本解密                         |"<<endl;
        cout<<"|       3.对文件加密                         |"<<endl;
        cout<<"|       4.对文件解密                         |"<<endl;
    }
   
    static void expect_equal(const char* name, const uint8_t* a, const uint8_t* b, size_t len) {
        if (memcmp(a, b, len) == 0) {
            printf("%s OK!\n", name);
        }
        else {
            printf("%s FAIL!\n", name);
        }
    }
    static uint8_t getuint8(string s) {
        const int l0 = s.length();
        uint8_t val = std::atoi(s.c_str());
        return val;
    }

    /**
     * 选择工作模式(ECB/CBC/CFB/OFB) 字符串加密显示. 
     * \param s 输入字符串
     */
    static void ECBencrypt(string s, uint8_t* key, uint8_t* iv, int mode) {
        uint8_t cipher0[16];
        string plain4 = s;
        const int l = plain4.length();
        const char* mm = plain4.c_str();//明文的uint8_t 类型 // string 转换为 char*
        const uint8_t* M = (uint8_t*)mm;
        int i = l / 16 + 1;//输入明文长度大于16位 则循环i轮,进行i轮加密
        if (mode = SM4_ECB_MODE) {
            cout << "ECB加密:"<<endl;
        }
        else if (mode = SM4_CBC_MODE) {
            cout << "CBC加密:" << endl;
        }
        else if (mode = SM4_CFB_MODE) {
            cout << "CFB加密:" << endl;
        }
        else if (mode = SM4_OFB_MODE) {
            cout << "OFB加密:" << endl;
        }
        cout << "明 文: ";
        cout << plain4 << endl;
        cout << "密 文: ";
        for (int c = 0; c < i; c++) {
            string Str = "";
            if (c != i - 1)  Str = plain4.substr(c * 16, 16); //不是最后一组明文,截取16位
            else Str = plain4.substr(c * 16);//最后一组明文,截取至末尾
            const char* str = Str.c_str();
            if (c == i - 1) str = PKCS5Padding(Str); //最后一组明文 长度可能小于16位 先进行字节填充
            const uint8_t* MM = (uint8_t*)str;//类型转换
            if (mode = SM4_ECB_MODE) sm4_ecb_encrypt(key, 16, MM, cipher0);
            else if (mode = SM4_CBC_MODE) sm4_cbc_encrypt(key, iv, 16, MM, cipher0);
            else if (mode = SM4_CFB_MODE) sm4_cfb_encrypt(key, iv, 16, MM, cipher0);
            else if (mode = SM4_OFB_MODE) sm4_ofb_encrypt(key, iv, 16, MM, cipher0);
            for (int m = 0; m < 16; ++m) {
                //printf("%02x ", cipher[m]);
                cout << cipher0[m];
            }
        }
        cout << endl;
    }
   
    /**
     *  ECB解密显示
     * \param c 密文
     * \param key 密钥
     * \param iv 初始向量
     */
    static void ECBdecrypt(uint8_t* cipher0, uint8_t* key, uint8_t* iv,int mode) {
        uint8_t plain2[16];
        string tis((char*)cipher0);//密文转string 便于提取子串
        if (mode = SM4_ECB_MODE) {
            cout << "ECB解密:" << endl;
        }
        else if (mode = SM4_CBC_MODE) {
            cout << "CBC解密:" << endl;
        }
        else if (mode = SM4_CFB_MODE) {
            cout << "CFB解密:" << endl;
        }
        else if (mode = SM4_OFB_MODE) {
            cout << "OFB解密:" << endl;
        }
        cout << "密 文: " << cipher0 << endl;
        int l0 = tis.length();
        int r = l0 / 16;//密文长度大于16位 则循环r+1轮,进行r轮解密
        cout << "明 文: ";
        for (int i = 0; i < r; i++) {
            string Tis = "";
            if (i != r - 1) Tis = tis.substr(i * 16, 16);//非最后一组密文提取密文中的16位
            if (i == r - 1) {
                Tis = tis.substr(i * 16); //最后一组 可能不足16位,截取至末尾

            }
            const char* str = Tis.c_str();
            string strr0((char*)str);
            if (i == r - 1) str = PKCS5Padding(Tis);//最后一组密文 长度可能小于16位 先进行字节填充
            const uint8_t* CC = (uint8_t*)str;
            //sm4_ecb_decrypt(key, 16, CC, plain2);
            if (mode = SM4_ECB_MODE) sm4_ecb_decrypt(key, 16, CC, plain2);
            else if (mode = SM4_CBC_MODE) sm4_cbc_decrypt(key, iv, 16, CC, plain2);
            else if (mode = SM4_CFB_MODE) sm4_cfb_decrypt(key, iv, 16, CC, plain2);
            else if (mode = SM4_OFB_MODE) sm4_ofb_decrypt(key, iv, 16, CC, plain2);
            for (int m = 0; m < 16; ++m) {
                cout << plain2[m];
            }
        }
    }

    static void sm4_test(void) {
        uint8_t plain[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
        uint8_t plain3[] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
        uint8_t cipher[16*128];
        uint8_t plain2[16*128];
        uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
        uint8_t iv[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
        uint8_t cipher00[] = { 0x68, 0x1e, 0xdf ,0x34 ,0xd2 ,0x06 ,0x96 ,0x5e ,0x86 ,0xb3 ,0xe9 ,0x4f ,0x53 ,0x6e ,0x42 ,0x46 };
        
        
        //构造可分为128个明文分组的明文 plain_128
        uint8_t* plain128[128];
        for (int i = 0; i < 128; i++) {
            plain128[i] = plain;
        }
        uint8_t plain_128[16*128];
        for (int i = 0; i < 128; i++) {
            for (int j = 0; j < 16; j++)
                plain_128[i * 16 + j] = plain128[i][j];
        }
        //构造可分为128个密文分组的密文 cipher_128
        uint8_t* cipher128[128];
        for (int i = 0; i < 128; i++) {
            cipher128[i] = cipher00;
        }
        uint8_t cipher_128[16 * 128];
        for (int i = 0; i < 128; i++) {
            for (int j = 0; j < 16; j++)
                cipher_128[i * 16 + j] = cipher128[i][j];
        }
      
        /*
        cout <<endl<< "|------------------------ ECB加密 Test01--------------------------|" << endl;
        string s = "好好学习天天向上";
        ECBencrypt(s,key, iv, SM4_ECB_MODE); //ECB加密 Test01
        cout << "|-------------------------ECB解密 Test01--------------------------|" << endl;
        uint8_t cipher0[] = "r%8Yk€T舗h創*奛鷨<市$ 籃";
        ECBdecrypt(cipher0, key, iv, SM4_ECB_MODE);//ECB解密 Test01
        */

        cout << endl <<endl << "|------------------------ ECB加密 Test02--------------------------|" << endl;
        sm4_ecb_encrypt(key, 16, plain, cipher);
        cout << "明 文: ";
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", plain[i]);
        }
        cout<<endl << "密 文: " ;
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", cipher[i]);
        }
        /*
        //测试128个明文分组
        cout <<endl<< endl << "128个明文分组 加密测试:" << endl;
        sm4_ecb_encrypt(key, 16*128, plain_128, cipher);
        cout << "明 文: "<<endl;
        for (int i = 0; i < 16*128; ++i) {
            printf("%02x ", plain_128[i]);
        }
        cout << endl << "密 文: "<<endl;
        for (int i = 0; i < 16*128; ++i) {
            printf("%02x ", cipher[i]);
        }
        */
      
        
        cout<<endl << "|------------------------ ECB解密 Test02--------------------------|" << endl;
        sm4_ecb_decrypt(key, 16, cipher, plain2);
        cout << "密 文: ";
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", cipher[i]);
        }
        cout<<endl << "明 文: "<<endl;
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", plain2[i]);
        }
        cout << endl;
        /*
        //测试128位密文还原
        for (int i = 0; i < 16; i++)
            cipher_128[i] = 0x01;//修改第一个密文分组为全0x01
        cout << endl << endl << "128个密文分组 解密测试:" << endl;
        sm4_ecb_decrypt(key, 16 * 128, cipher_128, plain2);
        cout << "密 文: "<<endl;
        for (int i = 0; i < 16 * 128; ++i) {
            printf("%02x ", cipher_128[i]);
        }
        cout << endl << "明 文: "<<endl;
        for (int i = 0; i < 16 * 128; ++i) {
            printf("%02x ", plain2[i]);
        }*/

        uint8_t p1[32];
        uint8_t p2[32];
        uint8_t c1[32];
        //p1[0] = 0x01;
        uint8_t p3[] = { 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
        memset(p2, 0, 32);
        cout << endl <<endl<< "|------------------------ CBC加密 Test----------------------------|" << endl;
        cout << "明 文: ";
        sm4_cbc_encrypt(key, key, 32, iv, c1);
        for (int i = 0; i < 32; ++i) {
            printf("%02x ", iv[i]);
        }
        cout << endl << "密 文: " ;
        for (int i = 0; i < 32; ++i) {
            printf("%02x ", c1[i]);
        }
        /*
        //测试128个明文分组
        cout << endl << endl << "128个明文分组 加密测试:" << endl;
        sm4_cbc_encrypt(key, iv, 16 * 128, plain_128, cipher);
        cout << "明 文: " << endl;
        for (int i = 0; i < 16 * 128; ++i) {
            printf("%02x ", plain_128[i]);
        }
        cout << endl << "密 文: " << endl;
        for (int i = 0; i < 16 * 128; ++i) {
            printf("%02x ", cipher[i]);
        }*/


        cout <<endl<< "|-------------------------CBC解密 Test----------------------------|" << endl;
        cout << "密 文: ";
        sm4_cbc_decrypt(key, key, 32, c1, p2);
        for (int i = 0; i < 32; ++i) {
            printf("%02x ", c1[i]);
        }
        printf("\n");
        printf("明 文: ");
        for (int i = 0; i < 32; ++i) {
            printf("%02x ", p2[i]);
        }

        cout << endl<<endl << "|-------------------------CFB加密 Test----------------------------|" << endl;
        cout << "明 文: ";
        sm4_cfb_encrypt(key, key, 32, p3, c1);
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", p3[i]);
        }
        printf("\n");
        printf("密 文: ");
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", c1[i]);
        }
        
        cout << endl << "|-------------------------CFB解密 Test----------------------------|" << endl;
        cout << "密 文: ";
        sm4_cfb_decrypt(key, key, 32, c1, p2);
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", c1[i]);
        }
        printf("\n");
        printf("明 文: ");
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", p2[i]);
        }
        cout << endl << endl << "|-------------------------OFB加密 Test----------------------------|" << endl;
        cout << "明 文: ";
        sm4_ofb_encrypt(key, key, 32, iv, c1);
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", iv[i]);
        }
        printf("\n");
        printf("密 文: ");
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", c1[i]);
        }
        cout << endl << "|-------------------------OFB解密 Test----------------------------|" << endl;
        cout << "密 文: ";
        sm4_ofb_decrypt(key, key, 32, c1, p2);
        //expect_equal("sm4_ofb", p1, p2, 32);
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", c1[i]);
        }
        printf("\n");
        printf("明 文: ");
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", p2[i]);
        }
    }

    static void sm4_ctx_test(int mode, const char* name) {
        uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };

        uint8_t p1[32];
        uint8_t p2[32];
        uint8_t c1[32];
        for (int i = 0; i < 32; ++i) {
            p1[i] = (i * i) & 0xff;
        }
        memset(p2, 0, 32);
        memset(c1, 0, 32);

        const uint8_t* iv = NULL;
        if (mode != SM4_ECB_MODE) {
            iv = key;
        }

        sm4_ctx_t ctx_en;
        sm4_ctx_t ctx_de;
        int r = sm4_init(&ctx_en, mode, key, iv);
        if (r != 0) {
            printf("sm4_init(%s | SM4_ENCRYPT) FAIL!\n", name);
            return;
        }
        r = sm4_init(&ctx_de, mode, key, iv);
        if (r != 0) {
            printf("sm4_init(%s | SM4_DECRYPT) FAIL!\n", name);
            return;
        }

        r = sm4_encrypt(&ctx_en, 16, p1, c1);
        r = sm4_encrypt(&ctx_en, 16, p1 + 16, c1 + 16);
        if (r != 0) {
            printf("sm4_encrypt(%s) FAIL!\n", name);
            return;
        }
        r = sm4_decrypt(&ctx_de, 32, c1, p2);
        if (r != 0) {
            printf("sm4_decrypt(%s) FAIL!\n", name);
            return;
        }

        expect_equal(name, p1, p2, 32);
    }
};



int main() {
    
    SM4Test::sm4_test();

    while (1) { }

}

/**
 * (主函数替换)
 * .利用该主函数中可对文件进行加解密
 * \param argc 控制台参数个数
 * \param argv (本程序)文件路径 +/-
 * \return
 *//*
int main(int argc, char* argv[])
{
    cout << "argc=" << argc << endl;
    cout << "argv[0]=" << argv[0] << endl;
    cout << "argv[1]=" << argv[1] << endl;
    cout << "argv[2]=" << argv[2] << endl;

    FILE* fpr, * fpw;//注意  FILE 为全大写
    char ch;// key = 0xfa;//初始密钥
    uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };

    //命令行参数必须是3个,且第3个参数必须是+/-
    if (argc != 3 || *argv[2] != '+' && *argv[2] != '-')
    {
        printf("usage: 可执行文件名  +/-");
        return 0;
    }
    //以读二进制文件的方式打开指定文件  argv[1] 为文件路径
    if ((fpr = fopen(argv[1], "rb")) == NULL)
    {
        printf("cannot open this file");
        return 0;
    }
    //以读写二进制文件的方式打开指定文件
    //因为会不断对fpw进行写操作【逐字符写】,
    //为避免后一次写操作覆盖了前一次内容,不可使用"w+"
    if ((fpw = fopen(argv[1], "rb+")) == NULL)
    {
        printf("cannot open file");
        return 0;
    }
    //逐字符读取文件fpr中,直至到达文件尾(EOF表示文件尾,值为-1)
    //设置 定长数组 装二进制数16位
    uint8_t chs[16];
    uint8_t cipher[16];
    int nn = 0;//计数器 记录chs数组目前长度
    cout << "now nn = " << nn << endl;
    while ((ch = fgetc(fpr)) != EOF)
    {
        cout << "读到第" << nn << "个字符"<<endl ;

        if (nn == 16) { //若数组内长度为16 (满一组) 数组从下标0开始填充
            nn = 0;
            cout << "读到的组为" << endl;
            for (int i = 0; i < 16; ++i) {
                printf("%02x ", chs[i]);
            }
           for (int i = 0; i <= 15; i++)
                chs[i] = 0;
         }
         else if(nn != 16){
             chs[nn] = ch;
             nn++;
         }
         if(nn == 16){//chs内为一组  //将读取到的字符加密/解密后写到文件fpw中
             if (*argv[2] == '+') //加密chs 返回char  char* 再写入文件
                 sm4_ecb_encrypt(key, 16, chs, cipher); //此时chs为明文 cipher为密文
             else if (*argv[2] == '-')
                 sm4_ecb_decrypt(key, 16, chs, cipher);//此时 chs为密文 cipher为明文
             for (int i = 0; i < 15; i++)
                 fputc(cipher[i], fpw);
            // fputc(ch ^ key, fpw);
         }

    }
    cout << "now nn = " << nn << endl;
    if (nn != 17) {//最后一组还没写入文件 再写一次
        cout << "最后一组为" << endl;
        for (int i = 0; i < 16; ++i) {
            printf("%02x ", chs[i]);
        }
        if (*argv[2] == '+') //加密chs 返回char  char* 再写入文件
            sm4_ecb_encrypt(key, 16, chs, cipher); //此时chs为明文 cipher为密文
        else if (*argv[2] == '-')
            sm4_ecb_decrypt(key, 16, chs, cipher);//此时 chs为密文 cipher为明文
        for (int i = 0; i < 15; i++)
            fputc(cipher[i], fpw);
    }
    if (*argv[2] == '+') cout << "文件加密成功!" << endl;
    if (*argv[2] == '-') cout << "文件解密成功!" << endl;
    fclose(fpr);
    fclose(fpw);
    return 0;
}*/

  • 31
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SM9是一种基于椭圆曲线密码学的公钥密码算法,SM9密钥分割算法是SM9算法中的一种重要应用。这种算法可以将一份私密密钥分割为多个部分,其中只有任意一部分被泄露,也无法获取原密钥。下面是SM9密钥分割算法Java代码实现。 首先,需要引入SM9算法和椭圆曲线算法的相关库: import org.bouncycastle.asn1.*; import org.bouncycastle.asn1.sm.*; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.params.*; import org.bouncycastle.crypto.generators.*; import org.bouncycastle.crypto.*; 接着,定义密钥分割的方法: public static byte[][] SM9KeySplit(byte[] prikey) { byte[][] res = new byte[5][]; SM2KeyPairGenerator gen = new SM2KeyPairGenerator(); SecureRandom random = new SecureRandom(); SM2KeyGenerationParameters param = new SM2KeyGenerationParameters(random); gen.init(param); AsymmetricCipherKeyPair kp = gen.generateKeyPair(); ECPublicKeyParameters pub = (ECPublicKeyParameters) kp.getPublic(); ECPrivateKeyParameters prv = (ECPrivateKeyParameters) kp.getPrivate(); byte[] pubkey = pub.getQ().getEncoded(false); res[0] = pubkey; res[1] = prv.getD().toByteArray(); byte[] hash = SM3Digest.hash(prikey, 0, prikey.length); SM9Parameters p = new SM9Parameters(); SM9KeySplitGenerator ksg = new SM9KeySplitGenerator(p); SM9PrivateKeySplitParameters split = ksg.generateSplit(prv, hash); res[2] = split.getSplitPart(1).toByteArray(); res[3] = split.getSplitPart(2).toByteArray(); res[4] = split.getSplitPart(3).toByteArray(); return res; } 在这个方法中,首先使用SM2算法生成一个EC密钥对,其中公钥是用于密钥分割的种子。然后使用SM9算法的密钥分割生成器生成密钥分割部分,将其存储在一个byte数组中,并最终返回一个byte数组的数组,每个元素都存储了一部分密钥分割内容。 最后,可以调用这个方法来进行密钥分割: byte[] prikey = new byte[] { /* 输入原私钥的byte数组 */ }; byte[][] splitRes = SM9KeySplit(prikey); // 将密钥分割结果存储在文件中或者其他方式进行保护 这样就完成了SM9密钥分割算法Java代码实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值