• 基于crypto++国产加密软件SM4的实现,和文件的加解密,顺带加了ase,base64。


                唔,美国压制得越狠,各种替代产品就越能活。

                本文分享SM4的一种快速实现与集成方式。

                  

                SM4(原名SMS4)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布[1][2],相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”[1]。2016年8月,成为中国国家密码标准(GB/T 32907-2016)[3]。在商用密码体系中,SM4主要用于数据加密,其算法公开,分组长度与密钥长度均为128bit,加密算法密钥扩展算法都采用32轮非线性迭代结构,S盒为固定的8比特输入8比特输出[4][5]。  

                 是密码界大神wangxiaoyun(让美国安全部颤抖的人)提供的。

                 主要对标的是对称加密里面的DES与AES。

                 安全性被大机构验证过,是目前最好的国产对称加密方案。

                 废话不多话了,既然搜到了本文,肯定是想着怎么实现的。

                 首先,GMSSL 应该是实现最完整的,啥算法基本都有,但比较大。简单得了解下放弃了。感兴趣的可以自己看http://gmssl.org/

                 本人对Crypto++之前有接触,使用过他提供的AES加密方式,搜了下官网,发现从6.0开始便支持SM4了,太好了。

                 https://www.cryptopp.com/docs/ref/class_s_m4.html#details  这里可以查看详细信息。

                 本人下载了最新版本8.2的。解压之后打开VS2013,对lib库进行编译,会有个cryptlib.lib的输出。我们只需要这个库即可。

      

                                                                                   

               我添加了下测试项目SM4-Cipher进行测试与验证。 验证是通过在线平台看看是否一致。http://aks.jd.com/tools/sec/

               直接上代码了。

               

    #include <windows.h>
    #include <string>
    #include <iostream>
    #include "modes.h"
    #include "filters.h"
    #include "base64.h"
    #include "aes.h"
    #include "sm4.h"
    using namespace std;
    using namespace CryptoPP;
    
    std::string base64_encrypt(const std::string& src)
    {
        //byte decoded[] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 };
        std::string encoded;
    
        try
        {
            StringSource ss(src, true,
                new Base64Encoder(
                new StringSink(encoded), false
                ) // Base64Encoder
                ); // StringSource
    
            return encoded;
        }
        catch (...)
        {
        }
    
        return encoded;
    }
    
    std::string base64_decrypt(const std::string& src)
    {
        std::string decoded;
    
        try
        {
            StringSource ss(src, true,
                new Base64Decoder(
                new StringSink(decoded)
                ) // Base64Decoder
                ); // StringSource
    
            return decoded;
        }
        catch (...)
        {
    
        }
        return decoded;
    
    }
    //typedef unsigned char byte;
    
    static CryptoPP::byte AES_KEY[] = "1234567890111111";
    static CryptoPP::byte AES_IV[] = "1234567890111111";
    
    //这里封装下sm4 加密算法加解密
    bool sm4_encrypt(void* data, size_t size, std::string& out)
    {
        out.clear();
        try
        {
            ECB_Mode<SM4>::Encryption cbcEncryption(AES_KEY, 16);
            StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(out));
            stfEncryptor.Put(reinterpret_cast<const unsigned char*>(data), size);
            stfEncryptor.MessageEnd();
        }
        catch (...)
        {
            return false;
        }
        return true;
    }
    
    bool sm4_decrypt(void* data, int size, std::string& out)
    {
        out.clear();
        try
        {
            ECB_Mode<SM4>::Decryption cbcDecryption(AES_KEY, 16);
            StreamTransformationFilter stfEncryptor(cbcDecryption, new CryptoPP::StringSink(out));
            stfEncryptor.Put(reinterpret_cast<const unsigned char*>(data), size);
            stfEncryptor.MessageEnd();
        }
        catch (...)
        {
            return false;
        }
        return true;
    }
    
    
    std::string aes_encrypt(const char* src, const int &length,std::string& out)
    {
        //  
        try
        {
            AES::Encryption aesEncryption(AES_KEY, 16);
            CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, AES_IV);
            StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(out));
            stfEncryptor.Put(reinterpret_cast<const unsigned char*>(src), length);
            stfEncryptor.MessageEnd();
    
            return out;
        }
        catch (...)
        {
        }
        return out;
    }
    
    std::string aes_decrypt(const char* src, const int &length, std::string& out)
    {
        try
        {
            AES::Decryption aesDecryption(AES_KEY, 16);
            CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, AES_IV);
            StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(out));
            stfDecryptor.Put(reinterpret_cast<const unsigned char*>(src), length);
            stfDecryptor.MessageEnd();
    
            return out;
        }
        catch (...)
        {
        }
        return out;
    }

               以上简单得实现了 base64、aes、sm4。并测试可行。

               大文件加密需要分块,注意无论是aes还是sm4,都有16字节对齐的概念。而且若块大小不是16字节倍数,补齐为16字节倍数。如果块大小是16字节倍数,则再添加16字节。

               切记。

              

    void testfile()
    {
        const DWORD Two_G = 2 << 30;
        string path;
        int type = 0;
        int encrypt = 1;
        char name[6] = { 0 };
        name[0] = '0';
        name[1] = '.';
        name[2] = 't';
        name[3] = 'm';
        name[4] = 'p';
        cout << "----------本程序基于crypto++库开发------------
    ";
        while (true)
        {
            cout << "请输入您要加解密的文件
    ";
            cin >> path;
            if (GetFileAttributesA(path.c_str()) == INVALID_FILE_ATTRIBUTES)
            {
                cout << "文件输入错误
    ";
                continue;
            }
    
            cout << "请输入您要加解密文件的种类
     1:SM4 2:AES-256 
    ";
            cin >> type;
            if (type < 1 || type>2)
            {
                cout << "暂不支持的类型
    ";
                continue;
            }
    
    
            cout << "您要加密还是解密?
     1:加密 0:解密 
    ";
            cin >> encrypt;
            if (encrypt != 0 && encrypt != 1)
            {
                cout << "输入有误
    ";
                continue;
            }
    
            string path2 = "D:\";
            path2.append(name);
    
            cout << "加解密文件会输出到" << path2 << endl;
            cout << "开始加解密操作了,从打开文件开始到生成全部临时文件结束,请耐心等待
    ";
            DWORD begin = GetTickCount();
    
    
    
            HANDLE hFile = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
            if (hFile == INVALID_HANDLE_VALUE)
            {
                cout << "打开文件出错
    ";
                continue;
            }
            DWORD dwBytesToRead = GetFileSize(hFile, NULL);
            if (dwBytesToRead > Two_G)
            {
                cout << "文件太大啦
    ";
                CloseHandle(hFile);
                continue;
            }
            if (GetFileAttributesA(path2.c_str()) != INVALID_FILE_ATTRIBUTES)
            {
                DeleteFileA(path2.c_str());
            }
            HANDLE hFile2 = CreateFileA(path2.c_str(), GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
            if (hFile2 == INVALID_HANDLE_VALUE)
            {
                CloseHandle(hFile);
                cout << "打开文件出错
    ";
                continue;
            }
            //一次加密1M吧 1M = 16B * 65536
            //一次解密需要多16字节。
            DWORD size_once = 1024 * 1024;
            if (encrypt == 0)
            {
                size_once += 16;
            }
            char * pbuff = (char*)malloc(size_once);
            //string 的大小已经在堆里了
            DWORD readbyte;
            do{                                       //循环读文件,确保读出完整的文件    
                ReadFile(hFile, pbuff, size_once, &readbyte, NULL);
                if (readbyte==0)
                    break;
                dwBytesToRead -= readbyte;
    
                //注意,本次只有readbyte可以用
                std::string out;
                if (encrypt == 1)
                {
                    if (type == 1)
                    {
                        sm4_encrypt(pbuff, readbyte, out);
                    }
                    else
                    {
                        aes_encode(pbuff, readbyte, out);
                    }
    
                }
                else
                {
                    if (type == 1){
                        sm4_decrypt(pbuff, readbyte, out);
                    }
                    else
                    {
                        aes_decode(pbuff, readbyte, out);
                    }
    
                }
    
                //out写入文件
                DWORD dwBytesToWrite = out.size();
                DWORD dwBytesWrite = 0;
                const char * tmpBuf = out.c_str();
                do{                                       //循环写文件,确保完整的文件被写入  
                    WriteFile(hFile2, tmpBuf, dwBytesToWrite, &dwBytesWrite, NULL);
                    dwBytesToWrite -= dwBytesWrite;
                    tmpBuf += dwBytesWrite;
    
                } while (dwBytesToWrite > 0);
    
    
            } while (dwBytesToRead > 0);
            free(pbuff);
            CloseHandle(hFile);
            CloseHandle(hFile2);
            DWORD end = GetTickCount();
            cout << "本次加密结束,使用的时间为" << end - begin << "毫秒
    ";
    
            name[0]++;
        }
    }
  • 相关阅读:
    setTimeout 理解
    Git 使用规范流程
    JavaScript异步编程 ( 一 )
    javaScript模块化一
    javascript 知识点坑
    javaScript闭包
    函数式编程
    JavaScript的68个技巧一
    MySql 隐式转换
    MySQL优化
  • 原文地址:https://www.cnblogs.com/xuhuajie/p/11950829.html
Copyright © 2020-2023  润新知