一、简介
Crypto++ 是一个免费开源的 C++ 密码学库,由 Wei Dai(美籍华裔)首次开发,当前由 Crypto++ 项目团队维护,源代码在 github 上进行托管。
- 官方网址:https://www.cryptopp.com/
- github 网址:https://github.com/weidai11/cryptopp
二、安裝 Crypto++ 庫
1)套件安裝
# ubutnu安裝 Crypto++ 函式庫
sudo apt install libcrypto++-dev
2)自行编译安装
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
三、程序开发
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;
}