基于Crypto++库的RSA非对称加密实现对数据的加解密

Naiiive

发布日期: 2018-11-15 08:20:03 浏览量: 662
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

背景

写了一个基于Crypto++加密库中RSA非对称加密算法实现的对数据加密和解密的一个小程序,Crypto++加密库就不详细介绍了,这个库提供了很多知名的加解密算法,直接调用就好了,使用起来还是比较方便的。

写这篇文章,就是分享自己的学习心得。自己的密码学部分的知识学得不怎么好,还好有Crypto++开源库可以使用,弥补了对加解密部分的不足。现在,向大家分享使用Crypto++中的RSA非对称加密算法实现对数据的加密解密方面的知识。

程序编译设置注意事项

首先,先要下载Crypto++库的开源代码,然后,自己编译得到Crypto++的库文件。下载链接还有具体的编译步骤,可以参考这个平台上其他用户写的分享文章“使用VS2013编译Crypto++加密库”,里面有详细介绍。

在导入Crypto++的库文件到自己的工程项目的时候,要对自己的工程项目进行编译设置。主要一点就是:项目工程的属性中的“运行库”设置,要与编译Crypto++的库文件时设置的“运行库”选项要对应一致,否则程序会编译不过的。也就是要检查LIB库工程和本测试工程的:属性 —> C/C++ —> 代码生成 —> 运行库 是否统一。

如果编译出错,报告XX重复定义等错误,同样,要检查LIB库工程和本测试工程的:属性 —> C/C++ —> 代码生成 —> 运行库 是否统一。

程序设计原理

1. 产生公钥和私钥文件原理

RSA是非对称加密算法,所以它的加密和解密的密钥是不同的,它有自己的公钥和私钥。在正常的使用过程中,公钥一般是用来加密数据,私钥用来解密数据。反之,也可以。公钥可以公开,但是私钥不可以公开。

对于Crypto++库产生公私钥的原理如下:

  • 首先用类RandomPool的方法Put()产生种子seed的byte型伪随机

  • RSAES_OAEP_SHA_Decryptor是一个解密的公钥密码系统在文件rsa.h 有如下定义:

    • typedef RSAES<OAEP<SHA>>::Decryptor RSAES_OAEP_SHA_Decryptor; 就是在这个类用前面产生的伪随机数和密钥长度keyLength生解密的密钥
  • 接着,通过类FileSink打开文件szPrivateKeyFileName实行序列化操作,用HexEncoder把它转换为十六进制

  • 最后,用DEREncode把上面处理好的密码对象写入文件

这样就得到私钥密码的密钥文件了。产生公钥文件的方法和产生私钥密码文件不同的地方就是使用了RSAES_OAEP_SHA_Encryptor是一个加密的公钥密码系统, 在文件rsa.h 有如下定义:

typedef RSAES<OAEP<SHA>>::Encryptor RSAES_OAEP_SHA_Encryptor; 是用上面产生的密钥密码系统priv来生成相应公钥。

2. 使用RSA公钥加密数据实现原理

RSA公钥加密可以分成以下两种形式:一种是公钥存储在文件中,加密时,从文件获取密钥;另一种是公钥存储在程序中,直接传递存储密钥的地址。虽然,这两种形式只是公钥传递的形式上的区别,RSA加密的原理还是一样的。但,从编程的角度,把这两个进行区分。

先介绍公钥存储在文件中的方式,那么RSA公钥加密的实现原理是:

  • 首先用类RandomPool在种子seed下用方法Put()产生伪随机数,Seed可以任取

  • 用类FileSource对公钥文件pubFilename进行一定的转换放入临时缓冲区,并把它从十六进制转换为byte型

  • 然后用FileSource的对象pubFile 实例化公钥密码系统RSAES_OAEP_SHA_Encryptor生成对象pub

  • 用类StringSink 把outstr添加到一个String对象,接着用HexEncoder把这个对象转换为十六进制

  • 然后用伪随机数randPool、公钥密码系统pub和十六进制的String对象实例化一个公钥密码加密的过滤器,再用这个过滤器对字符串message进行加密把结果放到十六进制的字符串result里,这样就完成了对字符串的加密

那么,对于另一种公钥存储在程序中的方式,RSA公钥加密的原理和上面的区别,只是在第 2 步的区别,也就是用类StringSource对公钥文件pubFilename进行一定的转换放入临时缓冲区,并把它从十六进制转换为byte型。

3. 使用RSA私钥钥解密数据实现原理

同样,对应上述的公钥加密,私钥解密同样区分两种私钥获取的形式。

先介绍私钥存储在文件中的方式,那么RSA私钥解密的实现原理的基本流程跟加密的基本流程差不多,就使用了几个不同的类,但是这些类跟加密函数的对应类的功能是相对的,很容易理解。

  • 用类FileSource对私钥文件privFilename进行一定的转换放入临时缓冲区,并把它从十六进制转换为byte型

  • 然后用FileSource的对象privFile 实例化公钥密码系统RSAES_OAEP_SHA_Decryptor生成对象priv

  • 用类StringSink 把outstr添加到一个String对象,接着用HexEncoder把这个对象转换为十六进制

  • 然后用伪随机数randPool、私钥密码系统prov和十六进制的String对象实例化一个私钥密码解密的过滤器,再用这个过滤器对字符串message进行解密把结果放到十六进制的字符串result里,这样就完成了对字符串的解密

和加密一样,对于另一种私钥存储在程序中的方式,RSA私钥解密的原理和上面的区别,只是在第 1 步的区别,也就是用类StringSource对公钥文件provFilename进行一定的转换放入临时缓冲区,并把它从十六进制转换为byte型。

编程实现

1. 导入Crypt++库文件

  1. //*************************************************
  2. // crypt++加密库的头文件和静态库
  3. //*************************************************
  4. #include "crypt\\include\\rsa.h"
  5. #include "crypt\\include\\randpool.h"
  6. #include "crypt\\include\\hex.h"
  7. #include "crypt\\include\\files.h"
  8. using namespace CryptoPP; // 命名空间
  9. #ifdef _DEBUG
  10. #ifdef _WIN64
  11. #pragma comment(lib, "crypt\\lib\\x64\\debug\\cryptlib.lib")
  12. #else
  13. #pragma comment(lib, "crypt\\lib\\x86\\debug\\cryptlib.lib")
  14. #endif
  15. #else
  16. #ifdef _WIN64
  17. #pragma comment(lib, "crypt\\lib\\x64\\release\\cryptlib.lib")
  18. #else
  19. #pragma comment(lib, "crypt\\lib\\x86\\release\\cryptlib.lib")
  20. #endif
  21. #endif
  22. //*************************************************

2. RSA产生公私钥实现

  1. BOOL GenerateRSAKey(DWORD dwRSAKeyLength, char *pszPrivateKeyFileName, char *pszPublicKeyFileName, BYTE *pSeed, DWORD dwSeedLength)
  2. {
  3. RandomPool randPool;
  4. randPool.Put(pSeed, dwSeedLength);
  5. // 生成RSA私钥
  6. RSAES_OAEP_SHA_Decryptor priv(randPool, dwRSAKeyLength);
  7. HexEncoder privFile(new FileSink(pszPrivateKeyFileName)); // 打开文件实行序列化操作
  8. priv.DEREncode(privFile);
  9. privFile.MessageEnd();
  10. // 生成RSA公钥
  11. RSAES_OAEP_SHA_Encryptor pub(priv);
  12. HexEncoder pubFile(new FileSink(pszPublicKeyFileName)); // 打开文件实行序列化操作
  13. pub.DEREncode(pubFile); // 写密码对象pub到文件对象pubFile里
  14. pubFile.MessageEnd();
  15. return TRUE;
  16. }

3. RSA公钥加密实现

1> 公钥存储在文件实现

  1. string RSA_Encrypt_ByFile(char *pszOriginaString, char *pszPublicKeyFileName, BYTE *pSeed, DWORD dwSeedLength)
  2. {
  3. RandomPool randPool;
  4. randPool.Put(pSeed, dwSeedLength);
  5. FileSource pubFile(pszPublicKeyFileName, TRUE, new HexDecoder);
  6. RSAES_OAEP_SHA_Encryptor pub(pubFile);
  7. // 加密
  8. string strEncryptString;
  9. StringSource(pszOriginaString, TRUE, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(strEncryptString))));
  10. return strEncryptString;
  11. }

2> 公钥存储在程序中

  1. string RSA_Encrypt_ByMem(char *pszOriginaString, char *pszMemPublicKey, BYTE *pSeed, DWORD dwSeedLength)
  2. {
  3. RandomPool randPool;
  4. randPool.Put(pSeed, dwSeedLength);
  5. StringSource pubStr(pszMemPublicKey, TRUE, new HexDecoder);
  6. RSAES_OAEP_SHA_Encryptor pub(pubStr);
  7. // 加密
  8. string strEncryptString;
  9. StringSource(pszOriginaString, TRUE, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(strEncryptString))));
  10. return strEncryptString;
  11. }

4. RSA私钥解密实现

1> 公钥存储在文件实现

  1. string RSA_Decrypt_ByFile(char *pszEncryptString, char *pszPrivateKeyFileName)
  2. {
  3. FileSource privFile(pszPrivateKeyFileName, TRUE, new HexDecoder);
  4. RSAES_OAEP_SHA_Decryptor priv(privFile);
  5. string strDecryptString;
  6. StringSource(pszEncryptString, TRUE, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(strDecryptString))));
  7. return strDecryptString;
  8. }

2> 公钥存储在程序中

  1. string RSA_Decrypt_ByMem(char *pszEncryptString, char *pszMemPrivateKey)
  2. {
  3. StringSource privStr(pszMemPrivateKey, TRUE, new HexDecoder);
  4. RSAES_OAEP_SHA_Decryptor priv(privStr);
  5. string strDecryptString;
  6. StringSource(pszEncryptString, TRUE, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(strDecryptString))));
  7. return strDecryptString;
  8. }

程序测试

在main函数中调用上面封装好的函数进行测试,main函数为:

  1. char g_szPubKey[] = "30819D300D06092A864886F70D010101050003818B0030818702818100F0CE882D7CCB990323A6DB1B775EBE8F2910BFE75B4B580EF8C5089BB25FEDEEABCE2BBD2AC64A138E47F96A6C39152FE98067C0B4F5DC28F8D9394325ADB12A90A9598FF7A2A7211DEF974FC8A005D0CBCDE059FB8F7F9D214C5BAC2532CEB8EC4041AEAB19E80B8C4020F4A50102F9E738647E2384EA2FCD30C3681559CF6F020111";
  2. char g_szPrivKey[] = "30820275020100300D06092A864886F70D01010105000482025F3082025B02010002818100F0CE882D7CCB990323A6DB1B775EBE8F2910BFE75B4B580EF8C5089BB25FEDEEABCE2BBD2AC64A138E47F96A6C39152FE98067C0B4F5DC28F8D9394325ADB12A90A9598FF7A2A7211DEF974FC8A005D0CBCDE059FB8F7F9D214C5BAC2532CEB8EC4041AEAB19E80B8C4020F4A50102F9E738647E2384EA2FCD30C3681559CF6F020111028180210D49E8203005F15F3F0F03C5170B18AB4892CF70EC39434F52426FB91C39C162E0100AE7C0DCFDAA1DF50E9B67351AA7942251AA68051EB8BE7145739A599220030CF5E35ED4DEA41DD6E955722AE46153339FE7417BD00ADF53B368EAB6E71FAE0F7F394A34C91612B0F11AEC5525DB84DD982E6BF10CE74F177FA51ADC51024100F80296900AF134CCC5AC12C58D741C735F5EE9CBDFB8C1B1EB039BF078E37B09322074193B7B0AE5A60B544DDDB9159294E91744404A2C7CDF96287F5483D691024100F8908925066C3ED9AC8EAFE63A59D56FCBEC354A3DD513489DEDA70E42338CD2AEBDEEF685148123B31A55CA27B2A59CA53E2352DA284F30585A5D6B571245FF02410091E367A0066FC4B4B083565616F901AD4728C5C3384E900E4E021F7E653A849BFF5E6269320C24871661046A09F4670AEE2EC264620D8394BFC1BD781398D891024057BA8AC1C608162EB55F896050D46972C0717C38520EF7BF46CC5914175D7CFF107F4547F2BBF157E4DC1E47594E1C55677F57C2E395C19897A76C44009D09A5024100BBB92D3E8776B52FA20303E39FE8AE862637BB75880D82C6580C3217445C4A95BFB6E94120AD62AADC313418A350FF21B0ED861848626CC0F55936F750B44FC4";
  3. int _tmain(int argc, _TCHAR* argv[])
  4. {
  5. char szPrivateFile[] = "privatefile";
  6. char szPublicFile[] = "publicfile";
  7. char szSeed[] = "WriteBugWriteBug";
  8. char szOriginalString[] = "WRITE-BUG技术共享平台 - 一个专注校园计算机技术交流共享的平台";
  9. /* 密钥在文件方式 */
  10. // 生成RSA公私密钥对
  11. GenerateRSAKey(1024, szPrivateFile, szPublicFile, (BYTE *)szSeed, ::lstrlen(szSeed));
  12. // RSA公钥加密字符串
  13. string strEncryptString = RSA_Encrypt_ByFile(szOriginalString, szPublicFile, (BYTE *)szSeed, ::lstrlen(szSeed));
  14. // RSA私钥解密字符串
  15. string strDecryptString = RSA_Decrypt_ByFile((char *)strEncryptString.c_str(), szPrivateFile);
  16. // 显示
  17. printf("原文字符串:\n[%d]%s\n", ::lstrlen(szOriginalString), szOriginalString);
  18. printf("密文字符串:\n[%d]%s\n", strEncryptString.length(), strEncryptString.c_str());
  19. printf("解密明文字符串:\n[%d]%s\n", strDecryptString.length(), strDecryptString.c_str());
  20. printf("\n\n");
  21. /* 密钥在内存方式 */
  22. // RSA公钥加密字符串
  23. string strEncryptString_Mem = RSA_Encrypt_ByMem(szOriginalString, g_szPubKey, (BYTE *)szSeed, ::lstrlen(szSeed));
  24. // RSA私钥解密字符串
  25. string strDecryptString_Mem = RSA_Decrypt_ByMem((char *)strEncryptString_Mem.c_str(), g_szPrivKey);
  26. // 显示
  27. printf("原文字符串:\n[%d]%s\n", ::lstrlen(szOriginalString), szOriginalString);
  28. printf("密文字符串:\n[%d]%s\n", strEncryptString_Mem.length(), strEncryptString_Mem.c_str());
  29. printf("解密明文字符串:\n[%d]%s\n", strDecryptString_Mem.length(), strDecryptString_Mem.c_str());
  30. system("pause");
  31. return 0;
  32. }

测试结果为:

根据图片显示,数据成功被加密和解密,两种公钥存储形式测试均成功。

总结

使用Crypto++库的好处之一,就是方便易用,即使你不了解具体的加密算法,但你只要知道要使用的加密算法这个名称,依然可以做出使用相应的加密算法进行数据加解密。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download RSA_Test.7z ( 638.57kb, 16次下载 )

keyboard_arrow_left上一篇 : U盘量产之更改U盘容量大小 内存快速搜索遍历 : 下一篇keyboard_arrow_right



Naiiive
2018-11-15 08:21:57
Crypto++库的编译可以参考本站上其他用户写的技术分享“使用VS2013编译Crypto++加密库”
LittleGirl
2019-04-01 10:38:56
实现起来比较简单

发送私信

我在一个迷惘的故事里,看着自己的人生演绎着百态

11
文章数
14
评论数
最近文章
eject