您的位置:首页 > 编程语言 > C语言/C++

C++利用Crypto++,vs2005环境下的RSA应用

2015-07-24 15:02 567 查看
——————————————————说明:部分内容参考网上现有。————————————————--

——————此文适合新手入门,大神直接飞过————————

————感想,可跳过哈 ,^_^————

这几天老师要求做一个关于rsa加密的项目,要求加解密文本内容。主要遇到密钥生成、待加解密字符串过长等遇到问题,下面会一一解决。网上查看资料大多是每次都生成新的密钥,而且加密的明文较短,所以第一次有了写博客的冲动哈!~~~~~

—————进入主题 !  ———————

一、crypto++sdk,环境及项目的配置,参照:http://www.cnblogs.com/cxun/archive/2008/07/30/743541.html

二、生成固定密钥,参照crypto++官方文档:http://www.cryptopp.com/wiki/Keys_and_Formats#Generating.2C_Validating.2C_Saving.2C_and_Loading_Keys

        所用代码示例也为官方sample,稍稍改动了一点点,在代码中会有说明。(别被吓唬了,其实慢慢看还是很容易的)

       必须现在c盘建一个rsa05的文件夹,否则会出错。出错点在下面代码中有标注。(之前没有建立这个文件夹,程序会中断抛出异常。)

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;

#include <string>
using std::string;

#include <stdexcept>
using std::runtime_error;

#include <queue.h>
using CryptoPP::ByteQueue;

#include "filters.h"
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::PK_EncryptorFilter;
using CryptoPP::PK_DecryptorFilter;

#include <files.h>
using CryptoPP::FileSource;
using CryptoPP::FileSink;

#include "dsa.h"
using CryptoPP::DSA;

#include "rsa.h"
using CryptoPP::RSA;
using CryptoPP::InvertibleRSAFunction;
using CryptoPP::RSAES_OAEP_SHA_Encryptor;
using CryptoPP::RSAES_OAEP_SHA_Decryptor;

#include <cryptlib.h>
using CryptoPP::PrivateKey;
using CryptoPP::PublicKey;
using CryptoPP::BufferedTransformation;

#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;

#pragma comment(lib, "cryptlib.lib");

void EncodePrivateKey(const string& filename, const RSA::PrivateKey& key);
void EncodePublicKey(const string& filename, const RSA::PublicKey& key);
void Encode(const string& filename, const BufferedTransformation& bt);

void DecodePrivateKey(const string& filename, RSA::PrivateKey& key);
void DecodePublicKey(const string& filename, RSA::PublicKey& key);
void Decode(const string& filename, BufferedTransformation& bt);

int main(int argc, char** argv)
{
std::ios_base::sync_with_stdio(false);

// http://www.cryptopp.com/docs/ref/class_auto_seeded_random_pool.html AutoSeededRandomPool rnd;

// http://www.cryptopp.com/docs/ref/rsa_8h.html RSA::PrivateKey rsaPrivate;
rsaPrivate.GenerateRandomWithKeySize(rnd, 2048);

RSA::PublicKey rsaPublic(rsaPrivate);

EncodePrivateKey("C:\\rsa05\\rsa-private.key", rsaPrivate);  //将密钥放在C:\\rsa05目录下
EncodePublicKey("C:\\rsa05\\rsa-public.key", rsaPublic);     //必须预先在C盘建立rsa05文件夹,否则出错

cout << "Successfully generated and saved RSA keys" << endl;

////////////////////////////////////////////////////////////////////////////////////

RSA::PrivateKey k1;
DecodePrivateKey("C:\\rsa05\\rsa-private.key", k1);

RSA::PublicKey k2;
DecodePublicKey("C:\\rsa05\\rsa-public.key", k2);

cout << "Successfully loaded RSA keys" << endl;

////////////////////////////////////////////////////////////////////////////////////

if(!k1.Validate(rnd, 3))
throw runtime_error("Rsa private key validation failed");

if(!k2.Validate(rnd, 3))
throw runtime_error("Rsa public key validation failed");

cout << "Successfully validated RSA keys" << endl;

////////////////////////////////////////////////////////////////////////////////////

if(rsaPrivate.GetModulus() != k1.GetModulus() ||
rsaPrivate.GetPublicExponent() != k1.GetPublicExponent() ||
rsaPrivate.GetPrivateExponent() != k1.GetPrivateExponent())
{
throw runtime_error("private key data did not round trip");
}

if(rsaPublic.GetModulus() != k2.GetModulus() ||
rsaPublic.GetPublicExponent() != k2.GetPublicExponent())
{
throw runtime_error("public key data did not round trip");
}

cout << "Successfully round-tripped RSA keys" << endl;

////////////////////////////////////////////////////////////////////////////////////

//其实这里就可以实现简单的加解密了
//-------------------------------------------------------------------------------
/*
string plain="RSA Encryption", cipher, recovered;

////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor e( k2 );

StringSource( plain, true,
new PK_EncryptorFilter( rnd, e,
new StringSink( cipher )
) // PK_EncryptorFilter
); // StringSource

////////////////////////////////////////////////
////////////////////////////////////////////////

////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor d( k1 );

StringSource( cipher, true,
new PK_DecryptorFilter( rnd, d,
new StringSink( recovered )
) // PK_EncryptorFilter
); // StringSource

assert( plain == recovered );

cout<<"plain:\t"<<plain<<"\r\n\r\n"<<"cipher:\t"<<cipher<<"\r\n\r\n";
*/
//-------------------------------------------------------------------------------

return 0;
}

void EncodePrivateKey(const string& filename, const RSA::PrivateKey& key)
{
// http://www.cryptopp.com/docs/ref/class_byte_queue.html ByteQueue queue;
key.DEREncodePrivateKey(queue);

Encode(filename, queue);
}

void EncodePublicKey(const string& filename, const RSA::PublicKey& key)
{
// http://www.cryptopp.com/docs/ref/class_byte_queue.html ByteQueue queue;
key.DEREncodePublicKey(queue);

Encode(filename, queue);
}

void Encode(const string& filename, const BufferedTransformation& bt)
{
// http://www.cryptopp.com/docs/ref/class_file_sink.html FileSink file(filename.c_str());

bt.CopyTo(file);
file.MessageEnd();
}

void DecodePrivateKey(const string& filename, RSA::PrivateKey& key)
{
// http://www.cryptopp.com/docs/ref/class_byte_queue.html ByteQueue queue;

Decode(filename, queue);
key.BERDecodePrivateKey(queue, false /*optParams*/, queue.MaxRetrievable());
}

void DecodePublicKey(const string& filename, RSA::PublicKey& key)
{
// http://www.cryptopp.com/docs/ref/class_byte_queue.html ByteQueue queue;

Decode(filename, queue);
key.BERDecodePublicKey(queue, false /*optParams*/, queue.MaxRetrievable());
}

void Decode(const string& filename, BufferedTransformation& bt)
{
// http://www.cryptopp.com/docs/ref/class_file_source.html FileSource file(filename.c_str(), true /*pumpAll*/);

file.TransferTo(bt);
bt.MessageEnd();
}


三、下面是我根据官方的说明自己做了两个函数用于加解密任意长度的字符串。下面在代码里讲解。

       ——————rsajm.h——————

#include "randpool.h"
#include "dsa.h"
#include "rsa.h"
#include "osrng.h"
#include "hex.h"
#include "filters.h"
#include "files.h"
#include "cryptlib.h"
#include <string.h>
#include <iostream>
#include <queue.h>
 
using namespace std;
using namespace CryptoPP;
 
#pragma comment(lib, "cryptlib.lib")

void EncodePrivateKey(const string& filename, const RSA::PrivateKey& key);
void EncodePublicKey(const string& filename, const RSA::PublicKey& key);
void Encode(const string& filename, const BufferedTransformation& bt);

void DecodePrivateKey(const string& filename, RSA::PrivateKey& key);
void DecodePublicKey(const string& filename, RSA::PublicKey& key);
void Decode(const string& filename, BufferedTransformation& bt);

void EncodePrivateKey(const string& filename, const RSA::PrivateKey& key)
{
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html     ByteQueue queue;
    key.DEREncodePrivateKey(queue);

    Encode(filename, queue);
}

void EncodePublicKey(const string& filename, const RSA::PublicKey& key)
{
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html     ByteQueue queue;
    key.DEREncodePublicKey(queue);

    Encode(filename, queue);
}

void Encode(const string& filename, const BufferedTransformation& bt)
{
    // http://www.cryptopp.com/docs/ref/class_file_sink.html     FileSink file(filename.c_str());

    bt.CopyTo(file);
    file.MessageEnd();
}

void DecodePrivateKey(const string& filename, RSA::PrivateKey& key)
{
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html     ByteQueue queue;

    Decode(filename, queue);
    key.BERDecodePrivateKey(queue, false /*optParams*/, queue.MaxRetrievable());
}

void DecodePublicKey(const string& filename, RSA::PublicKey& key)
{
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html     ByteQueue queue;

    Decode(filename, queue);
    key.BERDecodePublicKey(queue, false /*optParams*/, queue.MaxRetrievable());
}

void Decode(const string& filename, BufferedTransformation& bt)
{
    // http://www.cryptopp.com/docs/ref/class_file_source.html     FileSource file(filename.c_str(), true /*pumpAll*/);

    file.TransferTo(bt);
    bt.MessageEnd();
}

<pre name="code" class="cpp">AutoSeededRandomPool rnd;

//接收string类型字符串,进行rsa加密,并进行16进制编码,最后返回密文。
//
string myRsaEncrypt(string myPlaintText)
{
RSA::PublicKey myPubkey;
DecodePublicKey("C:\\rsa05\\rsa-public.key", myPubkey);
RSAES_OAEP_SHA_Encryptor e( myPubkey );

string result;

//——————————————————————————————————————————————————————
//由于加密的明文有最大长度,长度为FixedMaxPlaintextLength(),所以下面进行字符串长度的分割。
int maxTextlen = e.FixedMaxPlaintextLength();

for ( int i = myPlaintText.size() , j = 0; i > 0; i -= maxTextlen , j += maxTextlen)
{
string partPlaintext = myPlaintText.substr(j,maxTextlen);
string partCiphertext ;

StringSource(partPlaintext, true,
new PK_EncryptorFilter(rnd, e, new HexEncoder(new StringSink(partCiphertext))));
result += partCiphertext ;

}
return result;

}

//解密函数和上面的加密函数差不多哈~~
string myRsaDecrypt(string myCipherText)
{
RSA::PrivateKey myPrikey;
DecodePrivateKey("C:\\rsa05\\rsa-private.key", myPrikey);
RSAES_OAEP_SHA_Decryptor d( myPrikey );

string result;

int maxCiphertextLen = d.FixedCiphertextLength() * 2;

for ( int i = myCipherText.size() , j = 0; i > 0; i -= maxCiphertextLen , j += maxCiphertextLen)
{
string partCiphertext= myCipherText.substr(j,maxCiphertextLen);
string partPlaintext ;

StringSource(partCiphertext, true,
new HexDecoder(new PK_DecryptorFilter(rnd, d, new StringSink(partPlaintext))));
result += partPlaintext ;

}

return result;
}




四、最后贴出网上看到把txt文件内容到string里面的非常精简的代码段
ifstream in("C:\\rsa05\\resultCipher.txt", ios::in);
istreambuf_iterator<char> beg(in), end;
string sResultData(beg, end);
in.close();
//	cout<<sResultData;


五、OK~~~~~~~处女座~~~~~~~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息