SM4
逆向进阶算法 比较难一些
加密原理
代码实现
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
// --- 基础常量与 S 盒 ---
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,0xa2,0x1e,0x82,0x51,0x1f,
0x18,0xab,0x22,0x40,0x4a,0xed,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,
0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,
0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,
0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,
0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,
0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,
0x2d,0x0f,0xb0,0x54,0xbb,0x16,0x12,0x0b,0x70,0x59,0xaf,0xee,0x3f,0x97,0x0a,0x5a,
0xf1,0xed,0x2f,0x02,0x92,0x72,0xa9,0x49,0xda,0x91,0x5f,0x6a,0x27,0x05,0xc6,0x9f,
0x69,0xef,0xfb,0x23,0xca,0x0b,0xdd,0x5a,0x62,0x32,0x3b,0x2b,0x39,0x27,0x53,0x91,
0xad,0x64,0x55,0x32,0x51,0xdf,0x57,0x05,0x04,0x23,0x3e,0x18,0x53,0x38,0xde,0x2b,
0x79,0x92,0x30,0x06,0x35,0x6b,0x5b,0xef,0xf0,0x12,0x1c,0xaf,0x44,0x2e,0xa2,0x39,
0xb0,0x0c,0x7f,0x5d,0x9e,0x5d,0x27,0x40,0x82,0xd2,0x48,0x75,0xe2,0x48,0x6d,0x39
};
// 系统参数 FK 和 固定参数 CK
static const uint32_t FK[4] = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
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
};
// --- 基础宏运算 ---
#define SHL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
// 字节序转换:将4字节数组转为32位字
uint32_t GET32(const uint8_t *b) {
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
}
// 将32位字转回字节数组
void PUT32(uint32_t n, uint8_t *b) {
b[0] = (uint8_t)(n >> 24);
b[1] = (uint8_t)(n >> 16);
b[2] = (uint8_t)(n >> 8);
b[3] = (uint8_t)n;
}
// 非线性变换 Tau:通过S盒
uint32_t sm4_tau(uint32_t A) {
uint8_t b[4];
b[0] = SBOX[(A >> 24) & 0xFF];
b[1] = SBOX[(A >> 16) & 0xFF];
b[2] = SBOX[(A >> 8) & 0xFF];
b[3] = SBOX[A & 0xFF];
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
}
// 线性变换 L (加密用)
uint32_t sm4_L(uint32_t B) {
return B ^ SHL(B, 2) ^ SHL(B, 10) ^ SHL(B, 18) ^ SHL(B, 24);
}
// 密钥扩展专用的线性变换 L'
uint32_t sm4_L_prime(uint32_t B) {
return B ^ SHL(B, 13) ^ SHL(B, 23);
}
// --- 核心功能 ---
// 密钥扩展算法:将128位key生成32个轮密钥rk
void sm4_set_key(const uint8_t *key, uint32_t *rk) {
uint32_t MK[4], K[36];
for (int i = 0; i < 4; i++) MK[i] = GET32(key + i * 4);
for (int i = 0; i < 4; i++) K[i] = MK[i] ^ FK[i];
for (int i = 0; i < 32; i++) {
K[i + 4] = K[i] ^ sm4_L_prime(sm4_tau(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]));
rk[i] = K[i + 4];
}
}
// 单分组(16字节)加解密核心函数
void sm4_one_round(const uint32_t *rk, const uint8_t *in, uint8_t *out) {
uint32_t x[36];
for (int i = 0; i < 4; i++) x[i] = GET32(in + i * 4);
for (int i = 0; i < 32; i++) {
x[i + 4] = x[i] ^ sm4_L(sm4_tau(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ rk[i]));
}
for (int i = 0; i < 4; i++) PUT32(x[35 - i], out + i * 4);
}
// PKCS7 填充处理
int sm4_padding(uint8_t *data, int len) {
uint8_t pad = 16 - (len % 16);
for (int i = 0; i < pad; i++) data[len + i] = pad;
return len + pad;
}
// PKCS7 去除填充
int sm4_unpadding(uint8_t *data, int len) {
uint8_t pad = data[len - 1];
if (pad < 1 || pad > 16) return -1;
return len - pad;
}
// --- 模式实现 ---
// ECB 模式加密
void sm4_ecb_encrypt(uint32_t *rk, uint8_t *in, int len, uint8_t *out) {
for (int i = 0; i < len; i += 16) {
sm4_one_round(rk, in + i, out + i);
}
}
// CBC 模式加密
void sm4_cbc_encrypt(uint32_t *rk, uint8_t *iv, uint8_t *in, int len, uint8_t *out) {
uint8_t temp[16], current_iv[16];
memcpy(current_iv, iv, 16);
for (int i = 0; i < len; i += 16) {
for (int j = 0; j < 16; j++) temp[j] = in[i + j] ^ current_iv[j]; // 异或上一个密文块
sm4_one_round(rk, temp, out + i);
memcpy(current_iv, out + i, 16); // 更新IV为当前密文块
}
}
// --- 测试主函数 ---
int main() {
uint8_t key[16] = "1234567812345678"; // 16字节密钥
uint8_t iv[16] = "0000000000000000"; // 16字节初始向量
char msg[] = "Hello SM4, National Cryptography Standard!";
uint8_t buffer[128];
uint8_t cipher[128];
uint8_t plain[128];
uint32_t rk[32];
uint32_t drk[32];
// 1. 密钥扩展 (解密时轮密钥序反转)
sm4_set_key(key, rk);
for(int i=0; i<32; i++) drk[i] = rk[31-i];
// 2. 填充数据
int msg_len = strlen(msg);
memcpy(buffer, msg, msg_len);
int pad_len = sm4_padding(buffer, msg_len);
printf("原始数据: %s\n", msg);
// 3. CBC 模式测试
sm4_cbc_encrypt(rk, iv, buffer, pad_len, cipher);
printf("CBC 加密结果(HEX): ");
for(int i=0; i<pad_len; i++) printf("%02x", cipher[i]);
printf("\n");
// 4. CBC 模式解密 (手动实现解密逻辑:解密后异或IV)
uint8_t last_block[16], current_iv[16];
memcpy(current_iv, iv, 16);
for(int i=0; i<pad_len; i+=16) {
memcpy(last_block, cipher + i, 16); // 存下当前密文块供下次使用
sm4_one_round(drk, cipher + i, plain + i);
for(int j=0; j<16; j++) plain[i+j] ^= current_iv[j];
memcpy(current_iv, last_block, 16);
}
int final_len = sm4_unpadding(plain, pad_len);
plain[final_len] = '\0';
printf("CBC 解密结果: %s\n", plain);
return 0;
}
评论