Crypto++安装与使用

发布时间 2023-06-15 17:32:41作者: DoubleLi

一、简介

Crypto++ 是一个免费开源的 C++ 密码学库,由 Wei Dai(美籍华裔)首次开发,当前由 Crypto++ 项目团队维护,源代码在 github 上进行托管。

二、安裝 Crypto++ 庫

1)套件安裝

# ubutnu安裝 Crypto++ 函式庫
sudo apt install libcrypto++-dev

2)自行编译安装

官网下载码源,或者从github clone。

wget https://cryptopp.com/cryptopp870.zip
unzip -a cryptopp870.zip -d cryptopp

cd cryptopp
#静态库编译【推荐】
make -j4  # 或者 make static  -j4 
#动态库编译
make shared  -j4 

# 測試 Crypto++ 函式庫
./cryptest.exe v

# 安装
sudo make install
# 或
make install PREFIX=./install_x86_64

安装pem包到cryptopp

  • 以 PEM 格式读取和写入密钥和参数。
git clone https://github.com/noloader/cryptopp-pem/* .git
cp cryptopp-pem/*  cryptopp
# 重新编译安装cryptopp

交叉编译

# 安装依赖,以aarch64为例
sudo apt install binutils-aarch64-linux-gnu-dbg binutils-aarch64-linux-gnu cpp-aarch64-linux-gnu \
g++-10-aarch64-linux-gnu g++-9-aarch64-linux-gnu g++-aarch64-linux-gnu g++ \
gcc-10-aarch64-linux-gnu-base gcc-9-aarch64-linux-gnu-base gcc-aarch64-linux-gnu \
pkg-config-aarch64-linux-gnu qemu-efi-aarch64 gcc arch-test

# 需指定编译器
make CXX=aarch64-linux-gnu-g++ CXXFLAGS="-O2 -fPIC -pipe -Wall -shared" -f GNUmakefile-cross  -j4

三、程序开发

c++ 使用Crypto++开发文章

1.示例1

ECB 模式、16字节长度的 key、PKCS7填充方式的场景下,使用 AES 算法进行加解密。

#include <iostream>
#include <string>
#include "cryptlib.h"
#include "aes.h"
#include "modes.h"
#include "files.h"
#include "osrng.h"
#include "hex.h"

using namespace CryptoPP;
using namespace std;

int main(int argc, char* argv[]) {
    // 建立隨機亂數產生器
    // AutoSeededRandomPool prng;
    // 將金鑰與 IV 放置於安全的記憶體空間
    // SecByteBlock key(AES::DEFAULT_KEYLENGTH); // 採用預設的金鑰長度(128 位元)
    // SecByteBlock key(AES::MAX_KEYLENGTH);  // 採用最長的金鑰長度(256 位元)
    // SecByteBlock key(24);                  // 自行指定金鑰長度(192 位元)
    // 產生隨機金鑰與 IV
    // prng.GenerateBlock(key, key.size());
    
    byte key[AES::DEFAULT_KEYLENGTH] = "abcd1234";

    // 原始資料
    std::string plain = "Crypto++ is a free C++ library for cryptography";

    // 用來儲存密文與明文的變數
    std::string cipher, encoded, recovered;

    std::cout << "key:" << key << std::endl;
    std::cout << "原始資料:" << plain << std::endl;

    try {
        // 採用 AES-ECB 加密
        ECB_Mode<AES>::Encryption e;

        // 設定金鑰
        e.SetKey(key, sizeof(key));

        // 進行加密
        StringSource s(plain, true,
            new StreamTransformationFilter(e,
                new StringSink(cipher)
            ) // StreamTransformationFilter
        ); // StringSource

    } catch(const Exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    // Pretty print cipher text
    StringSource ss2( cipher, true,
        new HexEncoder(
            new StringSink( encoded )
        ) // HexEncoder
    ); // StringSource
    std::cout << "cipher text: " << encoded << std::endl;

    try {
        // 採用 AES-ECB 解密
        ECB_Mode<AES>::Decryption d;

        // 設定金鑰與 IV
        d.SetKey(key, sizeof(key));

        // 進行解密
        StringSource s(cipher, true,
            new StreamTransformationFilter(d,
                new StringSink(recovered)
            ) // StreamTransformationFilter
        ); // StringSource

    } catch(const Exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "解開的明文:" << recovered << std::endl;

    return EXIT_SUCCESS;
}

2.示例2

通过RSA对数据进行签署和验签。

#include <string>
#include <iostream>
#include <cstdlib>
#include "rsa.h"
#include "pssr.h"
#include "sha.h"
#include "osrng.h"
#include "secblock.h"

#include "files.h"
#include "hex.h"
#include <pem.h>

using namespace CryptoPP;
using namespace std;

void SaveKey( const RSA::PublicKey& PublicKey, const string& filename, const string format)
{
    if (format == "pem") {
        FileSink file( filename.c_str(), true /*binary*/ );
        CryptoPP::PEM_Save(file, PublicKey);
    } else if (format == "binary") {
        // DER Encode Key - X.509 key format
        PublicKey.Save(
            FileSink( filename.c_str(), true /*binary*/ ).Ref()
        );
    }
}

void SaveKey( const RSA::PrivateKey& PrivateKey, const string& filename, const string format)
{
    if (format == "pem") {
        FileSink file( filename.c_str(), true /*binary*/ );
        CryptoPP::PEM_Save(file, PrivateKey);
    } else if (format == "binary") {
        // DER Encode Key - PKCS #8 key format
        PrivateKey.Save(
            FileSink( filename.c_str(), true /*binary*/ ).Ref()
        );
    }
}

void LoadKey( const string& filename, RSA::PublicKey& PublicKey, const string format)
{
    if (format == "pem") {
        FileSource file(filename.c_str(), true, NULL, true /*binary*/ );
        PEM_Load(file, PublicKey);
    } else  if (format == "binary") {
        // DER Encode Key - X.509 key format
        PublicKey.Load(
            FileSource(filename.c_str(), true, NULL, true /*binary*/ ).Ref()
        );
    }
}

void LoadKey( const string& filename, RSA::PrivateKey& PrivateKey, const string format)
{
    if (format == "pem") {
        FileSource file(filename.c_str(), true, NULL, true /*binary*/ );
        PEM_Load(file, PrivateKey);
    } else  if (format == "binary") {
        // DER Encode Key - PKCS #8 key format
        PrivateKey.Load(
            FileSource(filename.c_str(), true, NULL, true /*binary*/ ).Ref()
        );
    }
}

int main(int argc, char* argv[]) {

    // 建立隨機亂數產生器
    AutoSeededRandomPool prng;

    try {
        // 產生 RSA 私鑰
        RSA::PrivateKey rsaPrivKey;
        rsaPrivKey.GenerateRandomWithKeySize(prng, 1024);
        // 產生對應的 RSA 公鑰
        RSA::PublicKey rsaPubKey(rsaPrivKey);
        SaveKey(rsaPrivKey, "rsaPrivKey.pem", "pem");
        SaveKey(rsaPubKey, "rsaPubkey.pem", "binary");

        // RSA::PrivateKey rsaPrivKey;
        // RSA::PublicKey rsaPubKey;
        // LoadKey("rsaPrivKey.pem", rsaPrivKey);
        // LoadKey("rsaPubkey.pem", rsaPubKey);

        // 資料內容
        std::string message = "Yoda said, Do or Do Not. There is not try.";

        // 數位簽章
        std::string signature;

        // 簽署器
        RSASS<PSS, SHA256>::Signer signer(rsaPrivKey);

        // 對資料進行簽署
        StringSource(message, true,
            new SignerFilter(prng, signer,
                new StringSink(signature)
            ) // SignerFilter
        ); // StringSource

        std::string encoded;
        StringSource ss2( signature, true,
            new HexEncoder(
                new StringSink( encoded )
            ) // HexEncoder
        ); // StringSource
        std::cout << "簽署: " << encoded << std::endl;

        // 簽章驗證器
        RSASS<PSS, SHA256>::Verifier verifier(rsaPubKey);

        // 驗證數位簽章
        StringSource(message+signature, true,
            new SignatureVerificationFilter(
                verifier, NULL,
                SignatureVerificationFilter::THROW_EXCEPTION
                | SignatureVerificationFilter::SIGNATURE_AT_END
            ) // SignatureVerificationFilter
        ); // StringSource

        std::cout << "簽章驗證成功" << std::endl;

    } catch(CryptoPP::Exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return EXIT_SUCCESS;
}

参考