C++利用Crypto++,vs2005環境下的RSA應用
阿新 • • 發佈:2019-02-20
——————————————————說明:部分內容參考網上現有。————————————————--
——————此文適合新手入門,大神直接飛過————————
————感想,可跳過哈 ,^_^————
這幾天老師要求做一個關於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~~~~~~~處女座~~~~~~~~~