ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

实现SM4算法(16字节版)

2022-09-14 09:34:12  阅读:262  来源: 互联网

标签:std 字节 iterator 16 SM4 vector 0xff buf


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

 

标签:std,字节,iterator,16,SM4,vector,0xff,buf
来源: https://www.cnblogs.com/love-DanDan/p/16691861.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有