编译Cryptopp
编译过程没有什么特别,需要注意的是,如果使用dll版本的库,只包含IPS认证的算法,而编译静态链接库则包含全部算法,具体参考[1,2]。
- cryptopp - This builds the DLL. Please note that if you wish to use Crypto++ as a FIPS validated module, you must use a pre-built DLL that has undergone the FIPS validation process instead of building your own.
- dlltest - This builds a sample application that only uses the DLL.
- cryptest Non-DLL-Import Configuration - This builds the full static library along with a full test driver.
- cryptest DLL-Import Configuration - This builds a static library containing only algorithms not in the DLL, along with a full test driver that uses both the DLL and the static library.
本人编译的lib库大小为50多M。
RSA算法介绍
关于rsa算法的介绍可以参考阮一峰的两篇两篇博文,在文末[3,4]以列出。
在RSA算法中有几个需要注意的点,我罗列一下:
非对称加密:对称加密算法在加密和解密时使用的是同一个秘钥;而非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,进行加密)和私有密钥(private key,用于解密)。
RSA用途:RSA加密算法除了用于少量数据加密之外,最主要的应用就是数字签名。
数字签名:包含3个步骤。详见[5]:
- 待发送消息(message)利用Hash函数,生成信息的摘要;
- 私钥加密摘要,生成”数字签名”(signature)
- 发送message+signature
- 公钥解密签名
- message重新生成摘要,与发送过来的摘要进行比较
公钥和私钥:公钥和私钥是成对的,它们互相解密。公钥加密,私钥解密。私钥数字签名,公钥验证。
RSA秘钥长度:cyptopp至少要求秘钥长度为1024;秘钥长度即为n值大小,即n=128byte
明文长度:一般应小于等于密钥长度(Bytes)-11,末尾采用填充。
解决长度限制:主要有2种方式
- 先用对称加密算法(AES/DES等)加密数据,然后用RSA公钥加密对称加密密钥,用RSA的私钥解密得到对称加密的密钥,然后完成反向操作得到明文。
- 分段进行RSA加密
示例代码
加密与解密
#include "rsa.h"
using CryptoPP::RSA;
using CryptoPP::InvertibleRSAFunction;
using CryptoPP::RSAES_OAEP_SHA_Encryptor;
using CryptoPP::RSAES_OAEP_SHA_Decryptor;
#include "sha.h"
using CryptoPP::SHA1;
#include "filters.h"
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::PK_EncryptorFilter;
using CryptoPP::PK_DecryptorFilter;
#include "files.h"
using CryptoPP::FileSink;
using CryptoPP::FileSource;
#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;
#include "SecBlock.h"
using CryptoPP::SecByteBlock;
#include "cryptlib.h"
using CryptoPP::Exception;
using CryptoPP::DecodingResult;
using CryptoPP::PrivateKey;
using CryptoPP::PublicKey;
using CryptoPP::BufferedTransformation;
#include <string>
using std::string;
#include <stdexcept>
using std::runtime_error;
#include <exception>
using std::exception;
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <queue.h>
using CryptoPP::ByteQueue;
#include <integer.h>
using CryptoPP::Integer;
#include <base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;
#include <assert.h>
////////////////////////////////////////////////
//保存公钥和私钥
void SavePrivateKey(const string& filename, const PrivateKey& key);
void SavePublicKey(const string& filename, const PublicKey& key);
////////////////////////////////////////////////
//base64编码
void SaveBase64PrivateKey(const string& filename, const PrivateKey& key);
void SaveBase64PublicKey(const string& filename, const PublicKey& key);
////////////////////////////////////////////////
//保存
void Save(const string& filename, const BufferedTransformation& bt);
void SaveBase64(const string& filename, const BufferedTransformation& bt);
//读取key
void LoadPrivateKey(const string& filename, PrivateKey& key);
void LoadPublicKey(const string& filename, PublicKey& key);
void LoadBase64PrivateKey(const string& filename, PrivateKey& key);
void LoadBase64PublicKey(const string& filename, PublicKey& key);
void LoadBase64(const string& filename, BufferedTransformation& bt);
void Load(const string& filename, BufferedTransformation& bt);
int main(int argc, char* argv[])
{
try
{
////////////////////////////////////////////////
// 生成私钥和公钥
AutoSeededRandomPool rng;
InvertibleRSAFunction parameters;
parameters.GenerateRandomWithKeySize( rng, 1024 ); //生成1024bit密钥,即n=128byte
const Integer& n = parameters.GetModulus();
const Integer& p = parameters.GetPrime1();
const Integer& q = parameters.GetPrime2();
const Integer& d = parameters.GetPrivateExponent();
const Integer& e = parameters.GetPublicExponent();
cout << "RSA Parameters:" << endl;
cout << " n: " << std::hex << n << endl; //n=p*q
cout << " p: " << std::hex << p << endl; //p
cout << " q: " << std::hex << q << endl; //q
cout << " d: " << std::hex << d << endl;
cout << " e: " << std::hex << e << endl; //e默认是17,原因不明
cout << endl;
//生成公钥和私钥
RSA::PrivateKey privateKey( parameters );//私钥用于加密(n,d)
RSA::PublicKey publicKey( parameters ); //公钥用于解密(n,e)
//默认使用ASN.1 DER编码
//SavePrivateKey("rsa-private.key", privateKey);
//SavePublicKey("rsa-public.key", publicKey);
////////////////////////////////////////////////
//输出privateKey
//ByteQueue queue;
//privateKey.Save(queue);
////////////////////////////////////////////////
//保存private_key到char[]中,
//注意char[]长度要足够
//注意这里privateKey不仅包括n和d
//是使用ASN.1 DER编码的字符数组
//char private_key_der_string[1024];
//size_t size = queue.MaxRetrievable();
//queue.Get((byte*)private_key_der_string,size);
//for(int i=0;i<1024;i++)
// cout << std::hex << ((int)private_key_der_string[i]&0xff) << " ";
////////////////////////////////////////////////
//保存private_key到string中,
//注意要预留string size
//string private_key_der_string;
//size_t size = queue.MaxRetrievable();
//if(size)
//{
// private_key_der_string.resize(size);
// queue.Get((byte*)private_key_der_string.data(),
// private_key_der_string.size());
//}
//for(auto it = private_key_der_string.begin();
// it!=private_key_der_string.end(); it++)
// cout<< std::hex << (*it & 0xff); //16进制输出char自动转int,需要截断字节
//cout << endl << endl;
////////////////////////////////////////////////
//StringSource参数:(原始字符串, 长度, 变换方式filter)
//使用filter将char[]转存为base64编码
//string bs64_private_key;
//StringSource ss(private_key_der_string, true,
// new Base64Encoder( //base64编码器
// new StringSink(bs64_private_key) //保存到bs64_private_key
// )
// );
//cout << bs64_private_key << endl;
////////////////////////////////////////////////
//保存base64 key到文件
SaveBase64PrivateKey("rsa-base64-private.key", privateKey);
SaveBase64PublicKey("rsa-base64-public.key", publicKey);
//////////////////////////////////////////////////
//=================分割线=======================//
//////////////////////////////////////////////////
////////////////////////////////////////////////
//读取bs64保存的privateKey和publicKey
//RSA::PrivateKey private_Key;
RSA::PublicKey public_Key;
//LoadBase64PrivateKey("rsa-base64-private.key", private_Key);
LoadBase64PublicKey("rsa-base64-public.key", public_Key);
string text= "你好世界", encrypted_text, decrypted_text;
////////////////////////////////////////////////
// 公钥加密
// 这里为了验证有效性
// 直接使用生成的publicKey
RSAES_OAEP_SHA_Encryptor encryptor( public_Key );
StringSource( text, true,
new PK_EncryptorFilter( rng, encryptor,
new StringSink( encrypted_text )
)
);
// 私钥解密
RSAES_OAEP_SHA_Decryptor decryptor( privateKey );
StringSource( encrypted_text, true,
new PK_DecryptorFilter( rng, decryptor,
new StringSink( decrypted_text )
)
);
cout << decrypted_text << endl;
//assert( text == decrypted_text );
}
catch( CryptoPP::Exception& e )
{
cerr << "Caught Exception..." << endl;
cerr << e.what() << endl;
}
system("pause");
return 0;
}
void Save(const string& filename, const BufferedTransformation& bt)
{
FileSink file(filename.c_str());
bt.CopyTo(file);
file.MessageEnd();
}
void SaveBase64(const string& filename, const BufferedTransformation& bt)
{
Base64Encoder encoder;
bt.CopyTo(encoder);
encoder.MessageEnd();
Save(filename, encoder);
}
void SavePrivateKey(const string& filename, const PrivateKey& key)
{
ByteQueue queue;
key.Save(queue);
Save(filename, queue);
}
void SavePublicKey(const string& filename, const PublicKey& key)
{
ByteQueue queue;
key.Save(queue);
Save(filename, queue);
}
void SaveBase64PrivateKey(const string& filename, const PrivateKey& key)
{
ByteQueue queue;
key.Save(queue);
SaveBase64(filename, queue);
}
void SaveBase64PublicKey(const string& filename, const PublicKey& key)
{
ByteQueue queue;
key.Save(queue);
SaveBase64(filename, queue);
}
void LoadPrivateKey(const string& filename, PrivateKey& key)
{
ByteQueue queue;
Load(filename, queue);
key.Load(queue);
}
void LoadPublicKey(const string& filename, PublicKey& key)
{
ByteQueue queue;
Load(filename, queue);
key.Load(queue);
}
void Load(const string& filename, BufferedTransformation& bt)
{
FileSource file(filename.c_str(), true /*pumpAll*/);
file.TransferTo(bt);
bt.MessageEnd();
}
void LoadBase64(const string& filename, BufferedTransformation& bt)
{
Base64Decoder decoder;
Load(filename,decoder);
decoder.CopyTo(bt);
bt.MessageEnd();
}
void LoadBase64PrivateKey(const string& filename, PrivateKey& key)
{
ByteQueue queue;
LoadBase64(filename, queue);
key.Load(queue);
}
void LoadBase64PublicKey(const string& filename, PublicKey& key)
{
ByteQueue queue;
LoadBase64(filename, queue);
key.Load(queue);
}
注意:
下面是生成的一组秘钥值,30开头的值是密钥的保存形式。查看源代码,可以发现其内部是使用默认使用ASN.1 DER编码进行持久化。
利用dumpans1,可以对DER编码进行解释。图片中的红框部分为密钥种的N值部分。
数字签名
#include "stdafx.h"
#include "rsa.h"
using CryptoPP::RSA;
using CryptoPP::RSASS;
using CryptoPP::InvertibleRSAFunction;
#include "pssr.h"
using CryptoPP::PSS;
#include "sha.h"
using CryptoPP::SHA1;
#include "files.h"
using CryptoPP::FileSink;
using CryptoPP::FileSource;
#include "filters.h"
using CryptoPP::SignerFilter;
using CryptoPP::SignatureVerificationFilter;
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::Integer;
#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;
#include "SecBlock.h"
using CryptoPP::SecByteBlock;
#include <string>
using std::string;
#include <iostream>
using std::cout;
using std::endl;
#include <sha.h>
using CryptoPP::SHA;
int main(int argc, char* argv[])
{
try
{
////////////////////////////////////////////////
// 伪随机数生成器
AutoSeededRandomPool rng;
InvertibleRSAFunction parameters;
parameters.GenerateRandomWithKeySize( rng, 1024 );
///////////////////////////////////////
// 生成私钥和公钥
RSA::PrivateKey privateKey( parameters ); //(n,e)
RSA::PublicKey publicKey( parameters ); //(n,d)
// 发送消息
string message = "Hello,world!";
string signature;
// 生成摘要
SHA hash;
//byte digest[SHA::DIGESTSIZE];
string digest;
digest.resize(SHA::DIGESTSIZE);
hash.CalculateDigest((byte*)digest.data(),(byte*)message.data(),message.length());
// 输出摘要
for(auto it = digest.begin(); it!=digest.end(); it++)
cout<< std::hex << (*it & 0xff); //16进制输出char自动转int,需要截断字节
cout << endl << endl;
////////////////////////////////////////////////
// 利用私钥进行签名
RSASS<PSS, SHA1>::Signer signer( privateKey );
StringSource( digest, true,
new SignerFilter( rng, signer,
new StringSink( signature )
) // SignerFilter
); // StringSource
// 输出摘要加密结果
for(auto it = signature.begin(); it!=signature.end(); it++)
cout<< std::hex << (*it & 0xff); //16进制输出char自动转int,需要截断字节
cout << endl << endl;
////////////////////////////////////////////////
// 利用公钥校验与恢复
RSASS<PSS, SHA1>::Verifier verifier( publicKey );
StringSource( digest+signature, true,
new SignatureVerificationFilter(
verifier, NULL,
SignatureVerificationFilter::THROW_EXCEPTION
) // SignatureVerificationFilter
); // StringSource
} //SignatureVerificationFilter::THROW_EXCEPTION 验证失败抛出异常
catch( CryptoPP::Exception& e ) {
std::cerr << "Error: " << e.what() << std::endl;
}
system("pause");
return 0;
}
参考
[1]http://www.codegur.me/37488545/how-to-build-crypto-5-6-2-in-msvc2013-for-qt
[2]http://cryptopp.com/wiki/Fips_dll
[3]http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
[4]http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
[5]http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html
[6]http://www.office68.com/computer/10174.html