狂自私

导航

实现SM4算法(16字节版)

base_sm4.h

#pragma once
#include <vector>
#include <iostream>

/*32位以内的循环左移*/
#define SM4_Rotl32(buf,n) (((buf)<<(n))|((buf)>>(32-(n))))
class base_sm4
{
public:
    base_sm4() {};
    /*
    * 函数SM4_SelfCheck是SM4自检函数,它用标准数据作为输入,那么输出也是一个标准结果,
    如果输出和标准结果不同,就说明发生错误了。
    若函数返回0,则表示自检成功,否则失败。
    */
    int SM4_SelfCheck();
protected:
    std::vector<unsigned int>SM4_CK{
        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,
    };
    std::vector<unsigned int>SM4_FK{
        0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC,
    };
    std::vector<unsigned char>SM4_Sbox{
        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,
    };
    /*
    *    函数SM4_KeySchedule用来生成轮密钥,
        参数MK是输入参数,存放主密钥(也就是加密密钥);
        rk是输出参数,存放生成的轮密钥。rk为32长度
    */
    void SM4_KeySchedule(std::vector<unsigned char>::iterator MK, std::vector<unsigned int>::iterator rK);
    /*
    * 函数SM4_Encrypt是SM4加密函数,输入参数MK存放主密钥;
    输入参数PlainText存放要加密的明文;
    输出参数CipherText存放加密的结果,即密文。
    */
    void SM4_Encrypt(std::vector<unsigned char>::iterator MK, std::vector<unsigned char>::iterator PlainText, std::vector<unsigned char>::iterator CipherText);
    /*
    * 函数SM4_Decrypt是SM4解密函数,输入参数MK存放主密钥,这个密钥和加密时的主密钥必须一样;
    输入参数CipherText存放要解密的密文;
    输出参数PlainText存放解密的结果,即明文。
    */
    void SM4_Decrypt(std::vector<unsigned char>::iterator MK, std::vector<unsigned char>::iterator CipherText, std::vector<unsigned char>::iterator PlainText);

};
View Code

base_sm4.cpp

#include "base_sm4.h"
void base_sm4::SM4_KeySchedule(std::vector<unsigned char>::iterator MK, std::vector<unsigned int>::iterator rK) {
    unsigned int temp{}, buf{};
    std::vector<unsigned int>K(36, 0);

    for (int i{}; i < 4; ++i) {
        K[i] = this->SM4_FK[i] ^ ((MK[4 * i] << 24) | (MK[4 * i + 1] << 16) | (MK[4 * i + 2] << 8) | (MK[i * 4 + 3]));
    }
    for (int i{}; i < 32; ++i) {
        temp = K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ this->SM4_CK[i];
        buf = ((this->SM4_Sbox[(temp >> 24 & 0xff)]) << 24) | ((this->SM4_Sbox[(temp >> 16 & 0xff)]) << 16) | ((this->SM4_Sbox[(temp >> 8 & 0xff)]) << 8) | (this->SM4_Sbox[(temp & 0xff)]);
        K[i + 4] = K[i] ^ (buf ^ (SM4_Rotl32((buf), 13)) ^ (SM4_Rotl32((buf), 23)));
        rK[i] = K[i + 4];
    }
}
void base_sm4::SM4_Encrypt(std::vector<unsigned char>::iterator MK, std::vector<unsigned char>::iterator PlainText, std::vector<unsigned char>::iterator CipherText) {
    unsigned int temp{}, buf{};
    std::vector<unsigned int> rk(36, 0);
    std::vector<unsigned int> X(36, 0);
    this->SM4_KeySchedule(MK, rk.begin());
    for (int i{}; i < 4; ++i) {
        X[i] = (PlainText[i * 4] << 24) | (PlainText[i * 4 + 1] << 16) | (PlainText[i * 4 + 2] << 8) | (PlainText[i * 4 + 3]);
    }
    for (int i{}; i < 32; i++) {
        temp = X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i];
        buf = ((this->SM4_Sbox[(temp >> 24 & 0xff)]) << 24) | ((this->SM4_Sbox[(temp >> 16 & 0xff)]) << 16) | ((this->SM4_Sbox[(temp >> 8 & 0xff)]) << 8) | (this->SM4_Sbox[(temp & 0xff)]);
        X[i + 4] = X[i] ^ (buf ^ SM4_Rotl32((buf), 2) ^ SM4_Rotl32((buf), 10) ^ SM4_Rotl32((buf), 18) ^ SM4_Rotl32((buf), 24));
    }
    for (int i{}; i < 4; ++i) {
        CipherText[4 * i] = (X[35 - i] >> 24) & 0xff;
        CipherText[4 * i + 1] = (X[35 - i] >> 16) & 0xff;
        CipherText[4 * i + 2] = (X[35 - i] >> 8) & 0xff;
        CipherText[4 * i + 3] = (X[35 - i]) & 0xff;
    }
}
void base_sm4::SM4_Decrypt(std::vector<unsigned char>::iterator MK, std::vector<unsigned char>::iterator CipherText, std::vector<unsigned char>::iterator PlainText) {
    unsigned int temp, buf;
    std::vector<unsigned int> rk(36, 0);
    std::vector<unsigned int> X(36, 0);
    this->SM4_KeySchedule(MK, rk.begin());

    for (int i{}; i < 4; ++i) {
        X[i] = (CipherText[i * 4] << 24) | (CipherText[i * 4 + 1] << 16) | (CipherText[i * 4 + 2] << 8) | (CipherText[i * 4 + 3]);
    }
    for (int i{}; i < 32; ++i) {
        temp = X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[31 - i];
        buf = ((this->SM4_Sbox[(temp >> 24 & 0xff)]) << 24) | ((this->SM4_Sbox[(temp >> 16 & 0xff)]) << 16) | ((this->SM4_Sbox[(temp >> 8 & 0xff)]) << 8) | (this->SM4_Sbox[(temp & 0xff)]);
        X[i + 4] = X[i] ^ (buf ^ SM4_Rotl32((buf), 2) ^ SM4_Rotl32((buf), 10) ^ SM4_Rotl32((buf), 18) ^ SM4_Rotl32((buf), 24));
    }
    for (int i{}; i < 4; ++i) {
        PlainText[4 * i] = (X[35 - i] >> 24) & 0xff;
        PlainText[4 * i + 1] = (X[35 - i] >> 16) & 0xff;
        PlainText[4 * i + 2] = (X[35 - i] >> 8) & 0xff;
        PlainText[4 * i + 3] = (X[35 - i]) & 0xff;
    }
}
int base_sm4::SM4_SelfCheck() {
    //Standard data   标准数据
    std::vector<unsigned char> key { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
    std::vector<unsigned char> plain { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
    std::vector<unsigned char>cipher { 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46 };
    std::vector<unsigned char> En_output(16,0);
    std::vector<unsigned char>De_output(16, 0);
    SM4_Encrypt(key.begin(), plain.begin(), En_output.begin());
    SM4_Decrypt(key.begin(), cipher.begin(), De_output.begin());
    //判断
    for (int i = 0; i < 16; i++)
    {
        //第一个判断是判断加密结果是否和标准密文数据相同
        //第二个判断解密结果是否和明文相同
        if ((En_output[i] != cipher[i]) || (De_output[i] != plain[i]))
        {
            std::cout << "Self-check error\nEn_output:";
            for (int j = 0; j < 16; j++) {
                std::cout << std::hex << static_cast<int>(En_output[j]) << ",";
            }
            std::cout << "\nDe_output:";
            for (int j = 0; j < 16; j++) {
                std::cout << std::hex << static_cast<int>(De_output[j]) << ",";
            }
            std::cout << "\n";
            return 1;
        }
    }
    std::cout << "sm4(16字节)自检成功!\n\n";
    return 0;
}
View Code

实现SM4算法(16字节版).cpp

// 实现SM4算法(16字节版).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// 为什么叫16字节版呢?这是因为本例只能对16字节数据进行加解密。
// 为什么不直接给出能对任意长度数据进行加解密的版本呢?
// 这是因为任意长度加解密的版本也是以16字节版为基础的。
// 别忘记了,SM4的分组长度是16字节,SM4是分组加解密的,任何长度的明文都会划分为16字节一组,
// 然后一组一组地进行加解密。
//

#include <iostream>
#include "C版/sm4.h"
#include "base_sm4.h"

int main()
{
    //SM4_SelfCheck();
    base_sm4 sm4;
    sm4.SM4_SelfCheck();
    std::cout << "Hello World!\n";
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
View Code

 

posted on 2022-09-14 09:18  狂自私  阅读(313)  评论(0编辑  收藏  举报