基于cyptopp库的rsa加解密详解

编译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加密

示例代码

加密与解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#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值部分。
这里写图片描述

数字签名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#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

坚持原创技术分享,您的支持将鼓励我继续创作!