|
背景(只是個人感想,技術(shù)上不對后面的內(nèi)容構(gòu)成知識性障礙,可以skip): 最近,基于某些原因和需要,筆者需要去了解一下Crypto++庫,然后對一些數(shù)據(jù)進行一些加密解密的操作。 筆者之前沒接觸過任何加密解密方面的知識(當然,把每個字符的ASCII值加1之流對明文進行加密的“趣事”還是干過的,當時還很樂在其中。),甚至一開始連Crypto++的名字都沒有聽過,被BS了之后,就開始了Crypto++的入門探索過程。 最初,大概知道了要了解兩大類算法中的幾個算法——對稱加密算法:DES、AES(后來因為人品好的緣故也了解了下非對稱加密算法RSA,后文會詳述何謂“人品好”);散列算法(需要通過Hash運算):SHA-256。 起初,筆者以為這樣的知名算法在網(wǎng)上應該有很多現(xiàn)成的例子。筆者比較懶,對于自己不熟悉的東西,總希望找捷徑,直接找別人現(xiàn)(在已經(jīng)寫)成可(編譯運)行的代碼然后施展ctrl + C,ctrl + V算法(咳,什么算法,是大法?。。。?。 However,發(fā)覺網(wǎng)上的例子不是稀缺,就是只有代碼沒有解釋。筆者覺得很難忍受這樣的“莫名其妙”(奇怪的是筆者容忍了windows了,盡管它不開源),遂決定從零開始…… ……寫在代碼前…… 一些前期工作——編譯cryptlib并使其可用: 本文不涉及這部分內(nèi)容,因為已經(jīng)有相對完善的資料: 總結(jié)了一點預備知識: 關(guān)于幾個算法的介紹,網(wǎng)上各大百科都有,筆者不再詳細Ctrl+C/V了。不過在寫代碼之前,即使復制修改人家代碼之前,也有必要了解一下幾個算法(除了名稱之外)的使用流程(不是算法具體的實現(xiàn),汗?。?/p> 對稱加密:(AES、DES) 相對于與非對稱加密而言,加密、解密用的密匙相同。就像日常生活中的鑰匙,開門和鎖門都是同一把。 詳見:http://baike.baidu.com/view/119320.htm 非對稱加密:(RSA) 相對于上述的對稱加密而言,加密、解密用的密匙不同,有公匙和私匙之分。 詳見:http://baike.baidu.com/view/554866.htm 散列算法:(SHA系列,我們熟悉的MD5等) 用途:驗證信息有沒有被修改。 原理:對長度大的信息進行提煉(通過一個Hash函數(shù)),提煉過后的信息長度小很多,得到的是一個固定長度的值 (Hash值)。對于兩個信息量很大的文件通過比較這兩個值,就知道這兩個文件是否完全一致(另外一個文件有沒有被修改)。從而避免了把兩個文件中的信息 進行逐字逐句的比對,減少時間開銷。 形象地描述:鬼泣3里面維吉爾跟但丁除了發(fā)型之外都很像。怎么區(qū)分兩個雙生子?比較他們的DNA就好比是比較信息量很大的文件,然而直接看發(fā)型就好比是看Hash值。一眼就看出來了。 注:以上是筆者對幾個概念的,非常不嚴格的,非常主觀的,概括的描述,想要詳細了解,可以: http://wenku.baidu.com/view/4fb8e0791711cc7931b716aa.html 幾個算法的介紹,選擇,比較。 ……Code speaking…… 平臺:WindowsXP IDE以及工具:Visual Studio 2008 + Visual Assist 庫版本:Crypto++ 庫的文檔(包括類和函數(shù)的接口列表): 對稱加密算法: DES: 一開始筆者并沒有找到關(guān)于DES運用的很好的例程,或者說,筆者的搜索功力薄弱,未能找到非常完整的例程吧。 http://bbs./showthread.php?p=745389 筆者以下的代碼主要是參考上面URL的論壇回帖,但是作了些修改: 1
#include <iostream>2 #include <des.h>3 ![]() 4 #pragma comment( lib, "cryptlib.lib" )5 ![]() 6 using namespace std;7 using namespace CryptoPP;8 ![]() 9 int main( void )10 {11 //主要是打印一些基本信息,方便調(diào)試:12 cout << "DES Parameters: " << endl;13 cout << "Algorithm name : " << DES::StaticAlgorithmName() << endl; 14 15 unsigned char key[ DES::DEFAULT_KEYLENGTH ];16 unsigned char input[ DES::BLOCKSIZE ] = "12345";17 unsigned char output[ DES::BLOCKSIZE ];18 unsigned char txt[ DES::BLOCKSIZE ];19 ![]() 20 cout << "input is: " << input << endl;21 ![]() 22 //可以理解成首先構(gòu)造一個加密器23 DESEncryption encryption_DES;24 ![]() 25 //回憶一下之前的背景,對稱加密算法需要一個密匙。加密和解密都會用到。26 //因此,設置密匙。27 encryption_DES.SetKey( key, DES::KEYLENGTH );28 //進行加密29 encryption_DES.ProcessBlock( input, output );30 ![]() 31 //顯示結(jié)果32 //for和for之后的cout可有可無,主要為了運行的時候看加密結(jié)果33 //把字符串的長度寫成一個常量其實并不被推薦。34 //不過筆者事先知道字符串長,為了方便調(diào)試,就直接寫下。35 //這里主要是把output也就是加密后的內(nèi)容,以十六進制的整數(shù)形式輸出。36 for( int i = 0; i < 5; i++ )37 {38 cout << hex << (int)output[ i ] << ends;39 }40 cout << endl;41 ![]() 42 //構(gòu)造一個加密器43 DESDecryption decryption_DES; 44 ![]() 45 //由于對稱加密算法的加密和解密都是同一個密匙,46 //因此解密的時候設置的密匙也是剛才在加密時設置好的key47 decryption_DES.SetKey( key, DES::KEYLENGTH );48 //進行解密,把結(jié)果寫到txt中49 //decryption_DES.ProcessAndXorBlock( output, xorBlock, txt );50 decryption_DES.ProcessBlock( output, txt );51 ![]() 52 //以上,加密,解密還原過程已經(jīng)結(jié)束了。以下是為了驗證:53 //加密前的明文和解密后的譯文是否相等。54 if ( memcmp( input, txt, 5 ) != 0 )55 {56 cerr << "DES Encryption/decryption failed.\n";57 abort();58 }59 cout << "DES Encryption/decryption succeeded.\n";60 61 return 0;62 }63 ![]()
AES: 在實際運用的時候,從代碼上看,AES跟DES非常相像。但是值得注意一點的是,AES取代了DES成為21世紀的加密標準。是因為以其密匙長度和高安全性獲得了先天優(yōu)勢。雖然界面上看上去沒多大區(qū)別,但是破解難度遠遠大于DES。詳細情況,在之前的URL有提及過。 1
#include <iostream>2 #include <aes.h>3 ![]() 4 #pragma comment( lib, "cryptlib.lib" )5 ![]() 6 using namespace std; 7 using namespace CryptoPP;8 ![]() 9 int main()10 {11 ![]() 12 //AES中使用的固定參數(shù)是以類AES中定義的enum數(shù)據(jù)類型出現(xiàn)的,而不是成員函數(shù)或變量13 //因此需要用::符號來索引14 cout << "AES Parameters: " << endl;15 cout << "Algorithm name : " << AES::StaticAlgorithmName() << endl; 16 ![]() 17 //Crypto++庫中一般用字節(jié)數(shù)來表示長度,而不是常用的字節(jié)數(shù)18 cout << "Block size : " << AES::BLOCKSIZE * 8 << endl;19 cout << "Min key length : " << AES::MIN_KEYLENGTH * 8 << endl;20 cout << "Max key length : " << AES::MAX_KEYLENGTH * 8 << endl;21 ![]() 22 //AES中只包含一些固定的數(shù)據(jù),而加密解密的功能由AESEncryption和AESDecryption來完成23 //加密過程24 AESEncryption aesEncryptor; //加密器 25 ![]() 26 unsigned char aesKey[AES::DEFAULT_KEYLENGTH]; //密鑰27 unsigned char inBlock[AES::BLOCKSIZE] = "123456789"; //要加密的數(shù)據(jù)塊28 unsigned char outBlock[AES::BLOCKSIZE]; //加密后的密文塊29 unsigned char xorBlock[AES::BLOCKSIZE]; //必須設定為全零30 ![]() 31 memset( xorBlock, 0, AES::BLOCKSIZE ); //置零32 ![]() 33 aesEncryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH ); //設定加密密鑰34 aesEncryptor.ProcessAndXorBlock( inBlock, xorBlock, outBlock ); //加密35 ![]() 36 //以16進制顯示加密后的數(shù)據(jù)37 for( int i=0; i<16; i++ ) {38 cout << hex << (int)outBlock[i] << " ";39 }40 cout << endl;41 ![]() 42 //解密43 AESDecryption aesDecryptor;44 unsigned char plainText[AES::BLOCKSIZE];45 ![]() 46 aesDecryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH );47 //細心的朋友注意到這里的函數(shù)不是之前在DES中出現(xiàn)過的:ProcessBlock,48 //而是多了一個Xor。其實,ProcessAndXorBlock也有DES版本。用法跟AES版本差不多。49 //筆者分別在兩份代碼中列出這兩個函數(shù),有興趣的朋友可以自己研究一下有何差異。50 aesDecryptor.ProcessAndXorBlock( outBlock, xorBlock, plainText );51 ![]() 52 ![]() 53 for( int i=0; i<16; i++ ) 54 { 55 cout << plainText[i]; 56 }57 cout << endl;58 ![]() 59 return 0;60 }61 ![]() 62 ![]()
非對稱加密算法: RSA: 小背景: 1
//version at Crypto++ 5.602 #include "randpool.h"3 #include "rsa.h"4 #include "hex.h"5 #include "files.h"6 #include <iostream>7 ![]() 8 using namespace std;9 using namespace CryptoPP;10 ![]() 11 #pragma comment(lib, "cryptlib.lib")12 ![]() 13 ![]() 14 //------------------------15 ![]() 16 // 函數(shù)聲明17 ![]() 18 //------------------------19 ![]() 20 void GenerateRSAKey( unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed );21 string RSAEncryptString( const char *pubFilename, const char *seed, const char *message );22 string RSADecryptString( const char *privFilename, const char *ciphertext );23 RandomPool & GlobalRNG();24 ![]() 25 //------------------------26 // 主程序27 //------------------------28 ![]() 29 void main( void )30 ![]() 31 {32 char priKey[ 128 ] = { 0 };33 char pubKey[ 128 ] = { 0 };34 char seed[ 1024 ] = { 0 };35 ![]() 36 // 生成 RSA 密鑰對37 strcpy( priKey, "pri" ); // 生成的私鑰文件38 strcpy( pubKey, "pub" ); // 生成的公鑰文件39 strcpy( seed, "seed" );40 GenerateRSAKey( 1024, priKey, pubKey, seed );41 ![]() 42 // RSA 加解密43 char message[ 1024 ] = { 0 };44 cout<< "Origin Text:\t" << "Hello World!" << endl << endl;45 strcpy( message, "Hello World!" );46 string encryptedText = RSAEncryptString( pubKey, seed, message ); // RSA 公匙加密47 cout<<"Encrypted Text:\t"<< encryptedText << endl << endl;48 string decryptedText = RSADecryptString( priKey, encryptedText.c_str() ); // RSA 私匙解密49 }50 ![]() 51 ![]() 52 ![]() 53 //------------------------54 ![]() 55 // 生成RSA密鑰對56 ![]() 57 //------------------------58 ![]() 59 void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)60 {61 RandomPool randPool;62 randPool.Put((byte *)seed, strlen(seed));63 ![]() 64 RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);65 HexEncoder privFile(new FileSink(privFilename));66 ![]() 67 priv.DEREncode(privFile);68 privFile.MessageEnd();69 ![]() 70 RSAES_OAEP_SHA_Encryptor pub(priv);71 HexEncoder pubFile(new FileSink(pubFilename));72 pub.DEREncode(pubFile);73 ![]() 74 pubFile.MessageEnd();75 ![]() 76 return ;77 }78 ![]() 79 ![]() 80 ![]() 81 //------------------------82 ![]() 83 // RSA加密84 ![]() 85 //------------------------86 ![]() 87 string RSAEncryptString( const char *pubFilename, const char *seed, const char *message )88 {89 FileSource pubFile( pubFilename, true, new HexDecoder );90 RSAES_OAEP_SHA_Encryptor pub( pubFile );91 ![]() 92 RandomPool randPool;93 randPool.Put( (byte *)seed, strlen(seed) );94 ![]() 95 string result;96 StringSource( message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))) );97 98 return result;99 }100 ![]() 101 ![]() 102 ![]() 103 //------------------------104 // RSA解密105 //------------------------106 ![]() 107 string RSADecryptString( const char *privFilename, const char *ciphertext )108 {109 FileSource privFile( privFilename, true, new HexDecoder );110 RSAES_OAEP_SHA_Decryptor priv(privFile);111 ![]() 112 string result;113 StringSource( ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))) );114 ![]() 115 return result;116 }117 ![]() 118 ![]() 119 ![]() 120 //------------------------121 ![]() 122 // 定義全局的隨機數(shù)池123 ![]() 124 //------------------------125 ![]() 126 RandomPool & GlobalRNG()127 {128 static RandomPool randomPool;129 return randomPool;130 }131 ![]() 132 ![]()
散列算法:
1
//http://hi.baidu.com/magic475/blog/item/19b37a8c1fa15a14b21bbaeb.html2 #include <iostream>3 #include <string.h>4 ![]() 5 #include "sha.h"6 #include "secblock.h"7 #include "modes.h"8 #include "hex.h"9 ![]() 10 #pragma comment( lib, "cryptlib.lib")11 ![]() 12 using namespace std;13 using namespace CryptoPP;14 ![]() 15 void CalculateDigest(string &Digest, const string &Message);16 bool VerifyDigest(const string &Digest, const string &Message);17 ![]() 18 int main( void )19 {20 //main函數(shù)中注釋掉的,關(guān)于strMessage2的代碼,其實是筆者模擬了一下21 //通過求Hash值來對“大”量數(shù)據(jù)進行校驗的這個功能的運用。22 //注釋之后并不影響這段代碼表達的思想和流程。23 string strMessage( "Hello world" );24 string strDigest;25 //string strMessage2( "hello world" ); //只是第一個字母不同26 //string strDigest2;27 ![]() 28 CalculateDigest( strDigest, strMessage ); //計算Hash值并打印一些debug信息29 cout << "the size of Digest is: " << strDigest.size() << endl;30 cout << "Digest is: " << strDigest << endl;31 ![]() 32 //CalculateDigest( strDigest2, strMessage2 );33 //why put this function here will affect the Verify function?34 //作者在寫代碼的過程中遇到的上述問題。35 //如果把這行代碼的注釋取消,那么之后的運行結(jié)果就不是預料中的一樣:36 //即使strDigest也無法對應strMessage,筆者不知道為什么,希望高手指出,謝謝!37 ![]() 38 bool bIsSuccess = false;39 bIsSuccess = VerifyDigest( strDigest, strMessage ); 40 //通過校驗,看看strDigest是否對應原來的message41 if( bIsSuccess )42 {43 cout << "sussessive verify" << endl;44 cout << "origin string is: " << strMessage << endl << endl;45 }46 else47 {48 cout << "fail!" << endl;49 }50 ![]() 51 //通過strDigest2與strMessage進行校驗,要是相等,52 //就證明strDigest2是對應的strMessage2跟strMessage1相等。53 //否則,像這個程序中的例子一樣,兩個message是不相等的54 /*CalculateDigest( strDigest2, strMessage2 );55 bIsSuccess = VerifyDigest( strDigest2, strMessage );56 if( !bIsSuccess )57 {58 cout << "success! the tiny modification is discovered~" << endl;59 cout << "the origin message is: \n" << strMessage << endl;60 cout << "after modify is: \n" << strMessage2 << endl;61 }*/62 return 0;63 }64 ![]() 65 ![]() 66 //基于某些原因,以下兩個子函數(shù)的實現(xiàn)跟原來參考代碼中的實現(xiàn)有所區(qū)別,67 //詳細原因,筆者在CalculateDigest函數(shù)的注釋中寫明68 void CalculateDigest(string &Digest, const string &Message)69 {70 SHA256 sha256;71 int DigestSize = sha256.DigestSize();72 char* byDigest;73 char* strDigest;74 ![]() 75 byDigest = new char[ DigestSize ];76 strDigest = new char[ DigestSize * 2 + 1 ];77 ![]() 78 sha256.CalculateDigest((byte*)byDigest, (const byte *)Message.c_str(), Message.size());79 memset(strDigest, 0, sizeof(strDigest));80 //uCharToHex(strDigest, byDigest, DigestSize);81 //參考的代碼中有以上這么一行,但是貌似不是什么庫函數(shù)。82 //原作者大概是想把Hash值轉(zhuǎn)換成16進制數(shù)保存到一個string buffer中,83 //然后在主程序中輸出,方便debug的時候?qū)φ詹榭础?br> 84 //但是這并不影響計算Hash值的行為。85 //因此筆者注釋掉了這行代碼,并且修改了一下這個函數(shù)和后面的VerifyDigest函數(shù),86 //略去原作者這部分的意圖,繼續(xù)我們的程序執(zhí)行。87 ![]() 88 Digest = byDigest;89 ![]() 90 delete []byDigest;91 byDigest = NULL;92 delete []strDigest;93 strDigest = NULL;94 ![]() 95 return;96 }97 ![]() 98 bool VerifyDigest(const string &Digest, const string &Message)99 {100 bool Result;101 SHA256 sha256;102 char* byDigest;103 ![]() 104 byDigest = new char[ sha256.DigestSize() ];105 strcpy( byDigest, Digest.c_str() );106 ![]() 107 //HexTouChar(byDigest, Digest.c_str(), Digest.size());108 //為何注釋掉,請參看CalculateDigest函數(shù)的注釋109 Result = sha256.VerifyDigest( (byte*)byDigest, (const byte *)Message.c_str(), Message.size() );110 ![]() 111 delete []byDigest;112 byDigest = NULL;113 return Result;114 }115 ![]() 116 ![]() 后記: 為什么寫這篇文章呢?因為筆者在搜索過程中覺得這方面的資料有點分散,因此想把它們集中起來,方便剛剛?cè)腴T的朋友。 同時,也算是為自己留點學習資料吧。 鳴謝: jingzhongrong vczh 沒了這兩位,在這個宇宙、這個時間、這個維度肯定不會有這篇文章,哈哈! |
|
|