ttcrypt 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +44 -0
- data/README.md +45 -0
- data/Rakefile +10 -0
- data/ext/ttcrypt/.gitignore +1 -0
- data/ext/ttcrypt/big_integer.cpp +59 -0
- data/ext/ttcrypt/big_integer.h +321 -0
- data/ext/ttcrypt/byte_buffer.cpp +84 -0
- data/ext/ttcrypt/byte_buffer.h +352 -0
- data/ext/ttcrypt/common_utils.cpp +24 -0
- data/ext/ttcrypt/common_utils.h +61 -0
- data/ext/ttcrypt/extconf.rb +62 -0
- data/ext/ttcrypt/pollard_rho.cpp +83 -0
- data/ext/ttcrypt/pollard_rho.h +55 -0
- data/ext/ttcrypt/rsa_key.cpp +373 -0
- data/ext/ttcrypt/rsa_key.h +248 -0
- data/ext/ttcrypt/ruby_cpp_tools.cpp +66 -0
- data/ext/ttcrypt/ruby_cpp_tools.h +77 -0
- data/ext/ttcrypt/sha1.cpp +185 -0
- data/ext/ttcrypt/sha1.h +49 -0
- data/ext/ttcrypt/sha256.c +379 -0
- data/ext/ttcrypt/sha256.h +67 -0
- data/ext/ttcrypt/text_utils.cpp +63 -0
- data/ext/ttcrypt/text_utils.h +64 -0
- data/ext/ttcrypt/ttcrypt.cpp +51 -0
- data/ext/ttcrypt/ttcrypt.h +45 -0
- data/ext/ttcrypt/ttcrypt_ruby.cpp +234 -0
- data/lib/ttcrypt/version.rb +5 -0
- data/lib/ttcrypt.rb +142 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/ttcrypt_spec.rb +318 -0
- data/ttcrypt.gemspec +47 -0
- metadata +139 -0
@@ -0,0 +1,373 @@
|
|
1
|
+
//
|
2
|
+
// RsaKey.cpp
|
3
|
+
// zcoin
|
4
|
+
//
|
5
|
+
// Created by Sergey Chernov on 02.06.14.
|
6
|
+
// Copyright (c) 2014 thrift. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
/*
|
10
|
+
This program is free software: you can redistribute it and/or modify
|
11
|
+
it under the terms of the GNU General Public License as published by
|
12
|
+
the Free Software Foundation, either version 3 of the License, or
|
13
|
+
(at your option) any later version.
|
14
|
+
|
15
|
+
This program is distributed in the hope that it will be useful,
|
16
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
+
GNU General Public License for more details.
|
19
|
+
|
20
|
+
You should have received a copy of the GNU General Public License
|
21
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
|
+
*/
|
23
|
+
|
24
|
+
#include "rsa_key.h"
|
25
|
+
#include "ttcrypt.h"
|
26
|
+
#include <assert.h>
|
27
|
+
#include <future>
|
28
|
+
|
29
|
+
using namespace ttcrypt;
|
30
|
+
using namespace thrift;
|
31
|
+
|
32
|
+
namespace ttcrypt {
|
33
|
+
|
34
|
+
static byte_buffer mgf1(const byte_buffer& z, size_t l) {
|
35
|
+
const size_t hLen = 20;
|
36
|
+
byte_buffer t;
|
37
|
+
for (unsigned i = 0; i <= l / hLen; i++)
|
38
|
+
t += sha1(z + i2osp(i, 4));
|
39
|
+
return byte_buffer(t, 0, l - 1);
|
40
|
+
}
|
41
|
+
|
42
|
+
byte_buffer eme_oaep_encode(const byte_buffer& message, size_t emLen,
|
43
|
+
const byte_buffer& p, const byte_buffer* pseed) {
|
44
|
+
const size_t hLen = 20;
|
45
|
+
const size_t hLen2 = 2 * hLen;
|
46
|
+
|
47
|
+
size_t mLen = message.size();
|
48
|
+
|
49
|
+
if (emLen <= hLen2 + 1)
|
50
|
+
throw rsa_key::error("padded length too small");
|
51
|
+
if (mLen >= emLen - 1 - hLen2 || mLen > emLen - 2 * hLen2 - 1)
|
52
|
+
throw rsa_key::error("message too long");
|
53
|
+
|
54
|
+
byte_buffer ps = byte_buffer('\0', emLen - mLen - hLen2 - 1);
|
55
|
+
byte_buffer pHash = sha1(p);
|
56
|
+
byte_buffer db = pHash + ps + "\001" + message;
|
57
|
+
byte_buffer seed = (pseed != 0) ? *pseed : byte_buffer::random(hLen);
|
58
|
+
byte_buffer dbMask = mgf1(seed, emLen - hLen);
|
59
|
+
byte_buffer maskedDb = db ^ dbMask;
|
60
|
+
byte_buffer seedMask = mgf1(maskedDb, hLen);
|
61
|
+
byte_buffer maskedSeed = seed ^ seedMask;
|
62
|
+
|
63
|
+
return maskedSeed + maskedDb;
|
64
|
+
}
|
65
|
+
|
66
|
+
byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer& p) {
|
67
|
+
const size_t hLen = 20;
|
68
|
+
if (message.size() < hLen * 2 + 1)
|
69
|
+
throw rsa_key::error("message is too short");
|
70
|
+
|
71
|
+
byte_buffer maskedSeed(message, 0, hLen - 1);
|
72
|
+
byte_buffer maskedDb(message, hLen, -1);
|
73
|
+
auto seedMask = mgf1(maskedDb, hLen);
|
74
|
+
auto seed = maskedSeed ^ seedMask;
|
75
|
+
auto db_mask = mgf1(seed, message.size() - hLen);
|
76
|
+
auto db = maskedDb ^ db_mask;
|
77
|
+
auto pHash = sha1(p);
|
78
|
+
|
79
|
+
int index = db.index_of('\001', hLen);
|
80
|
+
if (index < 0)
|
81
|
+
throw rsa_key::error("message is invalid");
|
82
|
+
|
83
|
+
byte_buffer pHash2(db, 0, hLen - 1);
|
84
|
+
byte_buffer ps(db, hLen, index - 1);
|
85
|
+
byte_buffer m(db, index + 1, -1);
|
86
|
+
|
87
|
+
for (auto x : ps) {
|
88
|
+
if (x != '\0')
|
89
|
+
throw rsa_key::error("message is invalid");
|
90
|
+
}
|
91
|
+
|
92
|
+
if (pHash2 != pHash)
|
93
|
+
throw rsa_key::error("wrong p value");
|
94
|
+
|
95
|
+
return m;
|
96
|
+
}
|
97
|
+
|
98
|
+
byte_buffer rsa_key::rsadp(const byte_buffer& ciphertext) const {
|
99
|
+
big_integer c = big_integer(ciphertext);
|
100
|
+
if (c >= n - 1)
|
101
|
+
throw rsa_key::error("cipertext is too long");
|
102
|
+
if (fast_key) {
|
103
|
+
// Fast
|
104
|
+
auto m1 = powmod_sec((c % p), dp, p);
|
105
|
+
auto m2 = powmod_sec((c % q), dq, q);
|
106
|
+
auto h = ((m1 - m2) * q_inv) % p;
|
107
|
+
return i2osp(m2 + q * h, byte_size - 1);
|
108
|
+
} else {
|
109
|
+
// slow c^d mod n
|
110
|
+
if (d == 0)
|
111
|
+
throw rsa_key::error("missing private key");
|
112
|
+
return i2osp(powmod_sec(c, d, n), byte_size - 1);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
byte_buffer emsa_pss_encode(const byte_buffer& message, size_t emBits,
|
117
|
+
byte_buffer (*hash)(const byte_buffer&), const byte_buffer *_salt = 0) {
|
118
|
+
auto mHash = hash(message);
|
119
|
+
auto hLen = mHash.size();
|
120
|
+
|
121
|
+
// TODO: implement bits logic!
|
122
|
+
auto emLen = (emBits + 7) / 8;
|
123
|
+
|
124
|
+
// required: emLen < hLen + sLen + 2
|
125
|
+
size_t sLen;
|
126
|
+
byte_buffer salt;
|
127
|
+
if (_salt) {
|
128
|
+
salt = *_salt;
|
129
|
+
sLen = salt.size();
|
130
|
+
} else {
|
131
|
+
sLen = emLen - hLen - 2;
|
132
|
+
salt = byte_buffer::random(sLen);
|
133
|
+
}
|
134
|
+
|
135
|
+
if (emLen < hLen + sLen + 2)
|
136
|
+
throw rsa_key::error("invliad salt length");
|
137
|
+
|
138
|
+
auto M1 = byte_buffer('\0', 8) + mHash + salt;
|
139
|
+
auto H = hash(M1);
|
140
|
+
auto PS = byte_buffer('\0', emLen - sLen - hLen - 2);
|
141
|
+
auto DB = PS.append_byte(1) + salt;
|
142
|
+
auto dbMask = mgf1(H, emLen - hLen - 1);
|
143
|
+
|
144
|
+
auto maskedDb = DB ^ dbMask;
|
145
|
+
|
146
|
+
// Clear leftmost bits
|
147
|
+
auto clear_bits = 8 * emLen - emBits;
|
148
|
+
if (clear_bits > 0)
|
149
|
+
maskedDb.set(0, clear_left_bits(maskedDb.at(0), clear_bits));
|
150
|
+
|
151
|
+
return maskedDb + H + "\xbc";
|
152
|
+
}
|
153
|
+
|
154
|
+
bool emsa_pss_verify(const byte_buffer& source_message,
|
155
|
+
const byte_buffer& encoded_message, size_t emBits,
|
156
|
+
byte_buffer (*hash)(const byte_buffer&), size_t sLen) {
|
157
|
+
|
158
|
+
auto mHash = hash(source_message);
|
159
|
+
auto emLen = (emBits + 7) / 8;
|
160
|
+
|
161
|
+
size_t hLen = mHash.size();
|
162
|
+
if (sLen == 0)
|
163
|
+
sLen = emLen - hLen - 2;
|
164
|
+
|
165
|
+
if (emLen < hLen + sLen + 2 || encoded_message[-1] != 0xbc)
|
166
|
+
return false;
|
167
|
+
|
168
|
+
byte_buffer maskedDB(encoded_message, 0, emLen - hLen - 2); // range is inclusive!
|
169
|
+
|
170
|
+
// Check MSB bits are cleared
|
171
|
+
auto clear_bits = 8 * emLen - emBits;
|
172
|
+
if (clear_bits > 0) {
|
173
|
+
byte bitmask = 0x80;
|
174
|
+
for (unsigned bit_no = 0; bit_no++ < clear_bits;) {
|
175
|
+
if ((maskedDB[0] & bitmask) != 0) // Compiler should optimize this
|
176
|
+
return false;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
byte_buffer H(encoded_message, emLen - hLen - 1, emLen - 2); // range inclusive
|
181
|
+
auto dbMask = mgf1(H, emLen - hLen - 1);
|
182
|
+
|
183
|
+
auto DB = maskedDB ^ dbMask;
|
184
|
+
|
185
|
+
DB.set(0, clear_left_bits(DB[0], clear_bits));
|
186
|
+
|
187
|
+
for (unsigned i = 0; i < emLen - hLen - sLen - 2; i++) {
|
188
|
+
if (DB[i] != 0) {
|
189
|
+
return false;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
if (DB[emLen - hLen - sLen - 2] != 1)
|
194
|
+
return false;
|
195
|
+
|
196
|
+
byte_buffer salt(DB, -sLen, -1);
|
197
|
+
|
198
|
+
auto M1 = byte_buffer('\0', 8) + mHash + salt;
|
199
|
+
auto H1 = hash(M1);
|
200
|
+
return H == H1;
|
201
|
+
}
|
202
|
+
|
203
|
+
// Note that signing does not require blinding - it is not prone to the
|
204
|
+
// timing attack
|
205
|
+
byte_buffer rsa_key::rsasp1(const byte_buffer &message) const {
|
206
|
+
big_integer m = message;
|
207
|
+
if (m >= n)
|
208
|
+
throw rsa_key::error("message representative is too long");
|
209
|
+
if (fast_key) {
|
210
|
+
// Fast
|
211
|
+
auto s1 = powmod(m % p, dp, p);
|
212
|
+
auto s2 = powmod(m % q, dq, q);
|
213
|
+
auto h = (s1 - s2) * q_inv % p;
|
214
|
+
auto s = s2 + q * h;
|
215
|
+
return i2osp(s, byte_size);
|
216
|
+
} else {
|
217
|
+
// slow
|
218
|
+
if (d == 0)
|
219
|
+
throw rsa_key::error("missing private key");
|
220
|
+
return i2osp(powmod(m, d, n), byte_size);
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
byte_buffer rsa_key::rsavp1(const byte_buffer& signature) const {
|
225
|
+
big_integer s = signature;
|
226
|
+
if (s > n - 1)
|
227
|
+
throw invalid_argument("signature representative too big");
|
228
|
+
require_public_key();
|
229
|
+
return i2osp(powmod_sec(s, e, n), byte_size);
|
230
|
+
}
|
231
|
+
|
232
|
+
bool rsa_key::verify(const byte_buffer& message, const byte_buffer& signature,
|
233
|
+
byte_buffer (*hash)(const byte_buffer&), size_t s_len) const {
|
234
|
+
if (signature.size() != byte_size)
|
235
|
+
return false;
|
236
|
+
try {
|
237
|
+
return emsa_pss_verify(message, rsavp1(signature), bits_size - 1, hash,
|
238
|
+
s_len);
|
239
|
+
} catch (const invalid_argument& e) {
|
240
|
+
return false;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
void rsa_key::normalize_key() {
|
245
|
+
if (n == 0)
|
246
|
+
n = p * q;
|
247
|
+
if ((dp == 0 || dq == 0 || q_inv == 0) && p != 0 && q != 0) {
|
248
|
+
dp = inverse(e, p - 1);
|
249
|
+
dq = inverse(e, q - 1);
|
250
|
+
q_inv = inverse(q, p);
|
251
|
+
fast_key = true;
|
252
|
+
} else
|
253
|
+
fast_key = p != 0 && q != 0 && dp != 0 && dq != 0 && q_inv != 0;
|
254
|
+
bits_size = n.bit_length();
|
255
|
+
byte_size = (bits_size + 7) / 8;
|
256
|
+
}
|
257
|
+
|
258
|
+
static big_integer prime(unsigned bits) {
|
259
|
+
// Set 2 MSB bits to ensire we git enough big pq
|
260
|
+
// and calculate margin
|
261
|
+
big_integer r = (1_b << (bits - 2)) + (1_b << (bits - 1));
|
262
|
+
big_integer s = (1_b << bits) - 1;
|
263
|
+
while (1) {
|
264
|
+
auto p = next_prime(big_integer::random_between(r, s));
|
265
|
+
if (p <= s)
|
266
|
+
return p;
|
267
|
+
// loop if prime is too big (unlikely)
|
268
|
+
}
|
269
|
+
throw logic_error("failed prime generation");
|
270
|
+
}
|
271
|
+
|
272
|
+
rsa_key rsa_key::generate(unsigned int k, size_t e) {
|
273
|
+
if (e == 0)
|
274
|
+
e = 0x10001;
|
275
|
+
|
276
|
+
if (e < 3 || (e != 0x10001 && !big_integer(e).is_prime()))
|
277
|
+
throw rsa_key::error("exponent should be prime number >= 3");
|
278
|
+
|
279
|
+
// v2.2 Algorithm
|
280
|
+
while (true) {
|
281
|
+
auto future = std::async(std::launch::async, [k] {return prime(k/2);});
|
282
|
+
auto q = prime(k - k / 2);
|
283
|
+
auto p = future.get();
|
284
|
+
if (p == q)
|
285
|
+
continue;
|
286
|
+
|
287
|
+
auto n = p * q;
|
288
|
+
if (n.bit_length() != k) {
|
289
|
+
// logic error: bit length mismatch, regenerating
|
290
|
+
continue;
|
291
|
+
}
|
292
|
+
|
293
|
+
auto Ln = lcm(p - 1, q - 1);
|
294
|
+
if (gcd(e, Ln) != 1)
|
295
|
+
continue;
|
296
|
+
|
297
|
+
if (p > q)
|
298
|
+
swap(p, q);
|
299
|
+
|
300
|
+
return rsa_key(n, e, p, q);
|
301
|
+
}
|
302
|
+
throw logic_error("pq generation failed");
|
303
|
+
}
|
304
|
+
|
305
|
+
void rsa_key::set(string name, const thrift::big_integer &value) {
|
306
|
+
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
307
|
+
switch (name[0]) {
|
308
|
+
case 'e':
|
309
|
+
e = value;
|
310
|
+
break;
|
311
|
+
case 'p':
|
312
|
+
this->p = value;
|
313
|
+
break;
|
314
|
+
case 'q':
|
315
|
+
if (name == "qinv" || name == "q_inv")
|
316
|
+
q_inv = value;
|
317
|
+
else
|
318
|
+
q = value;
|
319
|
+
break;
|
320
|
+
case 'n':
|
321
|
+
n = value;
|
322
|
+
break;
|
323
|
+
case 'd':
|
324
|
+
if (name == "dp") {
|
325
|
+
dp = value;
|
326
|
+
} else if (name == "dq") {
|
327
|
+
dq = value;
|
328
|
+
} else
|
329
|
+
d = value;
|
330
|
+
break;
|
331
|
+
default:
|
332
|
+
throw error("unknown paramerer ");
|
333
|
+
break;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
337
|
+
unordered_map<string, big_integer> rsa_key::get_params(bool include_all) const
|
338
|
+
noexcept {
|
339
|
+
unordered_map<string, big_integer> params;
|
340
|
+
if (n != 0) {
|
341
|
+
params["n"] = n;
|
342
|
+
}
|
343
|
+
if (e != 0) {
|
344
|
+
params["e"] = e;
|
345
|
+
}
|
346
|
+
if (p != 0) {
|
347
|
+
params["p"] = p;
|
348
|
+
}
|
349
|
+
if (q != 0) {
|
350
|
+
params["q"] = q;
|
351
|
+
}
|
352
|
+
|
353
|
+
if (d != 0 && ((p == 0 && q == 0) || include_all)) {
|
354
|
+
params["d"] = q;
|
355
|
+
}
|
356
|
+
|
357
|
+
if (dp != 0 && include_all) {
|
358
|
+
params["dp"] = dp;
|
359
|
+
}
|
360
|
+
|
361
|
+
if (dq != 0 && include_all) {
|
362
|
+
params["dq"] = dq;
|
363
|
+
}
|
364
|
+
|
365
|
+
if (q_inv != 0 && include_all) {
|
366
|
+
params["qinv"] = q_inv;
|
367
|
+
}
|
368
|
+
|
369
|
+
return params;
|
370
|
+
}
|
371
|
+
|
372
|
+
}
|
373
|
+
|
@@ -0,0 +1,248 @@
|
|
1
|
+
//
|
2
|
+
// RsaKey.h
|
3
|
+
//
|
4
|
+
// Created by Sergey Chernov on 02.06.14.
|
5
|
+
// Copyright (c) 2014 thrift. All rights reserved.
|
6
|
+
//
|
7
|
+
|
8
|
+
/*
|
9
|
+
This program is free software: you can redistribute it and/or modify
|
10
|
+
it under the terms of the GNU General Public License as published by
|
11
|
+
the Free Software Foundation, either version 3 of the License, or
|
12
|
+
(at your option) any later version.
|
13
|
+
|
14
|
+
This program is distributed in the hope that it will be useful,
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
GNU General Public License for more details.
|
18
|
+
|
19
|
+
You should have received a copy of the GNU General Public License
|
20
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#ifndef __zcoin__RsaKey__
|
24
|
+
#define __zcoin__RsaKey__
|
25
|
+
|
26
|
+
#include <iostream>
|
27
|
+
#include <unordered_map>
|
28
|
+
#include "byte_buffer.h"
|
29
|
+
#include "big_integer.h"
|
30
|
+
#include "ttcrypt.h"
|
31
|
+
|
32
|
+
namespace ttcrypt {
|
33
|
+
|
34
|
+
using namespace thrift;
|
35
|
+
|
36
|
+
byte_buffer eme_oaep_encode( const byte_buffer& message,size_t emLen, const byte_buffer& p=byte_buffer(), const byte_buffer *seed=nullptr);
|
37
|
+
byte_buffer eme_oaep_decode(const byte_buffer& message,const byte_buffer& p="");
|
38
|
+
|
39
|
+
byte_buffer emsa_pss_encode(const byte_buffer& message,size_t emBits,byte_buffer (*hash)(const byte_buffer&),const byte_buffer* salt);
|
40
|
+
bool emsa_pss_verify(const byte_buffer& source_message,
|
41
|
+
const byte_buffer& encoded_message,
|
42
|
+
size_t emBits,
|
43
|
+
byte_buffer (*hash)(const byte_buffer&),
|
44
|
+
size_t debug_sLen=0);
|
45
|
+
|
46
|
+
/**
|
47
|
+
PKCS#1 v2.2 RSA algorythm (only STRONG encoding e.g. OAEP/PSS, weak 1.5 is NOT supported by purpose!). Full implementation
|
48
|
+
(key generation, construction from parts, encryption, signing).
|
49
|
+
*/
|
50
|
+
class rsa_key {
|
51
|
+
public:
|
52
|
+
|
53
|
+
class error : public invalid_argument {
|
54
|
+
public:
|
55
|
+
error(const char* reason) : invalid_argument(reason){}
|
56
|
+
};
|
57
|
+
|
58
|
+
/**
|
59
|
+
Construct from { {name, value} } paris, like { { "e", 123 }, { "n":data_n } }. @see #set().
|
60
|
+
*/
|
61
|
+
rsa_key(const std::initializer_list<std::pair<string, big_integer>>& params)
|
62
|
+
{
|
63
|
+
set_params(params);
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
Construct from any map-like container that provides pair iterator with pair.first
|
68
|
+
and pair.second members. @see #set()
|
69
|
+
*/
|
70
|
+
template <class Tmap>
|
71
|
+
rsa_key(const Tmap& map)
|
72
|
+
{
|
73
|
+
set_params(map);
|
74
|
+
}
|
75
|
+
|
76
|
+
rsa_key()
|
77
|
+
{}
|
78
|
+
|
79
|
+
/**
|
80
|
+
Set the named parameter to a given value. Supported values are: n, e, d, p, q, dp, dq, qinv.
|
81
|
+
Not case sesitive. Call normalize_key() when done changing parameters.
|
82
|
+
*/
|
83
|
+
void set(string name, const big_integer& value);
|
84
|
+
|
85
|
+
/**
|
86
|
+
Construct private key from parts. If not all parts are provided, recalculates missing ones that
|
87
|
+
is somewhat slow.
|
88
|
+
*/
|
89
|
+
rsa_key(const big_integer& N, const big_integer& E, const big_integer& P,const big_integer& Q,
|
90
|
+
const big_integer& dP=0, const big_integer& dQ=0, const big_integer& qInv=9)
|
91
|
+
: n(N), e(E), p(P), q(Q), dp(dP), dq(dQ), q_inv(qInv)
|
92
|
+
{
|
93
|
+
normalize_key();
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
Construct "slow" ptivate key from parts.
|
98
|
+
*/
|
99
|
+
rsa_key(const big_integer& N,const big_integer& E, const big_integer& D) : n(N), e(E), d(D), fast_key(false) {
|
100
|
+
normalize_key();
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
Construct public key.
|
105
|
+
*/
|
106
|
+
rsa_key(const big_integer& N,const big_integer& E) : n(N), e(E) { normalize_key(); }
|
107
|
+
|
108
|
+
/**
|
109
|
+
Test that private key present
|
110
|
+
*/
|
111
|
+
bool is_private() const {
|
112
|
+
return (p != 0 && q != 0) || d != 0;
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
construct and return public key (strip private component if any)
|
117
|
+
*/
|
118
|
+
rsa_key public_key() const {
|
119
|
+
return rsa_key(n,e);
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
RSAES-OAEP encrypt a message.
|
124
|
+
*/
|
125
|
+
byte_buffer encrypt(const byte_buffer& plaintext) const {
|
126
|
+
return rsaep(eme_oaep_encode(plaintext, byte_size - 1,"", pseed));
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
RSAES-OAEP decrypt a given cipertext. requires private key.
|
131
|
+
*/
|
132
|
+
byte_buffer decrypt(const byte_buffer& ciphertext) const {
|
133
|
+
return eme_oaep_decode( rsadp( ciphertext) );
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
Create RSASSA-PSS signature for a given message. Requires private key.
|
138
|
+
@param message what to sign
|
139
|
+
@param hash default to sha256
|
140
|
+
@param salt to use with a given salt. By default, uses random salt of maximum available length. When
|
141
|
+
using custom salt, you'll need to provide its length on verification (s_len parameter)
|
142
|
+
|
143
|
+
*/
|
144
|
+
byte_buffer sign(const byte_buffer& message, byte_buffer (*hash)(const byte_buffer&)=sha256, const byte_buffer* salt=0) const {
|
145
|
+
return rsasp1(emsa_pss_encode(message, bits_size-1, hash, salt));
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
Verify RSASSA-PSS signature.
|
150
|
+
|
151
|
+
@param message message to verify
|
152
|
+
@param signature PSS signature of the message
|
153
|
+
@param hash sha1, sha256 or other hash function (by default sha256)
|
154
|
+
@param s_len if manual salt was used, provide its length. by default, salt uses
|
155
|
+
all available space left.
|
156
|
+
@return true if the signature is consistent with the message, false otherwise (message is tampered or the signature
|
157
|
+
is broken)
|
158
|
+
*/
|
159
|
+
bool verify(const byte_buffer& message,
|
160
|
+
const byte_buffer& signature,
|
161
|
+
byte_buffer (*hash)(const byte_buffer&)=sha256,
|
162
|
+
size_t s_len=0) const;
|
163
|
+
|
164
|
+
/** :nodoc: set seed to debug OAEP encryption. Please DO NOT use
|
165
|
+
*/
|
166
|
+
void debug_seed(const byte_buffer& s) {
|
167
|
+
pseed = &s;
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
@return key size in bits
|
172
|
+
*/
|
173
|
+
unsigned size_in_bits() const { return bits_size; }
|
174
|
+
|
175
|
+
/**
|
176
|
+
@return key size in bytes
|
177
|
+
*/
|
178
|
+
unsigned size_in_bytes() const { return byte_size; }
|
179
|
+
|
180
|
+
/**
|
181
|
+
Generate new key pair of the specified strength. If the system has more than one CPU core,
|
182
|
+
use 2 cores to generate key parts.
|
183
|
+
@param bits_strength desired strength in bits. it is recommended to use ar least 2048 bits and
|
184
|
+
sizes that are multiplication of 256.
|
185
|
+
@param e public exponent, positive integer, this implementation requires it to be prime >= 3.
|
186
|
+
default of 0 uses "good" value 0x10001.
|
187
|
+
*/
|
188
|
+
static rsa_key generate(unsigned bits_strength,size_t e=0);
|
189
|
+
|
190
|
+
|
191
|
+
/**
|
192
|
+
Update key parameters from map-like container that provides pair iterator with pair.first
|
193
|
+
and pair.second members. @see #set()
|
194
|
+
*/
|
195
|
+
template <class Tmap>
|
196
|
+
void set_params(const Tmap& map) {
|
197
|
+
for( auto pair: map ) {
|
198
|
+
set(pair.first, pair.second);
|
199
|
+
}
|
200
|
+
normalize_key();
|
201
|
+
}
|
202
|
+
|
203
|
+
unordered_map<string,big_integer> get_params(bool include_all = false) const noexcept;
|
204
|
+
|
205
|
+
/**
|
206
|
+
recalculate parts of the key after chaging it with
|
207
|
+
#set().
|
208
|
+
*/
|
209
|
+
void normalize_key();
|
210
|
+
|
211
|
+
/**
|
212
|
+
Turn on or off use of blinding algorithm (that repels timing attack) on decrypt and verify
|
213
|
+
routines only, as if makes it slower the longer the key is used.
|
214
|
+
*/
|
215
|
+
void use_blinding(bool use) noexcept {
|
216
|
+
_use_blinding = use;
|
217
|
+
}
|
218
|
+
|
219
|
+
private:
|
220
|
+
big_integer n, e, p, q, d, dp, dq, q_inv;
|
221
|
+
unsigned byte_size=0, bits_size=0;
|
222
|
+
bool fast_key=false, _use_blinding=false;
|
223
|
+
|
224
|
+
const byte_buffer *pseed = NULL;
|
225
|
+
|
226
|
+
big_integer powmod_sec(const big_integer& x, const big_integer& y, const big_integer& mod) const noexcept {
|
227
|
+
return _use_blinding ? ::powmod_sec(x, y, mod) : ::powmod(x, y, mod);
|
228
|
+
}
|
229
|
+
|
230
|
+
byte_buffer rsaep(const byte_buffer& plaintext) const {
|
231
|
+
auto m = os2ip(plaintext);
|
232
|
+
require_public_key();
|
233
|
+
return i2osp(powmod(m, e, n), byte_size); // Encryption does not need blinding!
|
234
|
+
}
|
235
|
+
|
236
|
+
void require_public_key() const {
|
237
|
+
if( n == 0 || e == 0 )
|
238
|
+
throw error("missing public key");
|
239
|
+
}
|
240
|
+
|
241
|
+
byte_buffer rsasp1(const byte_buffer& m) const;
|
242
|
+
byte_buffer rsavp1(const byte_buffer& s) const;
|
243
|
+
|
244
|
+
byte_buffer rsadp(const byte_buffer& c) const;
|
245
|
+
};
|
246
|
+
}
|
247
|
+
|
248
|
+
#endif /* defined(__zcoin__RsaKey__) */
|
@@ -0,0 +1,66 @@
|
|
1
|
+
/*
|
2
|
+
* ruby_cpp_tools.cpp
|
3
|
+
*
|
4
|
+
* Created on: 18 июня 2014 г.
|
5
|
+
* Author: sergeych
|
6
|
+
* Copyright (C) 2014 Thrift, Sergey S. Chernov
|
7
|
+
*
|
8
|
+
This program is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU General Public License as published by
|
10
|
+
the Free Software Foundation, either version 3 of the License, or
|
11
|
+
(at your option) any later version.
|
12
|
+
|
13
|
+
This program is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU General Public License
|
19
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <iostream>
|
23
|
+
#include "ruby_cpp_tools.h"
|
24
|
+
|
25
|
+
struct unblock_data {
|
26
|
+
unblock_data(const std::function<void*()> &_block) :
|
27
|
+
block(_block) {
|
28
|
+
}
|
29
|
+
const std::function<void*()> █
|
30
|
+
std::exception_ptr exception_ptr = NULL;
|
31
|
+
};
|
32
|
+
|
33
|
+
extern "C" {
|
34
|
+
static void* unblock_executor(void* ptr) {
|
35
|
+
unblock_data *data = (unblock_data*) ptr;
|
36
|
+
try {
|
37
|
+
return data->block();
|
38
|
+
} catch (...) {
|
39
|
+
data->exception_ptr = std::current_exception();
|
40
|
+
}
|
41
|
+
return 0;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
VALUE ruby_unblock2(const std::function<void*()>& block) {
|
46
|
+
unblock_data d(block);
|
47
|
+
VALUE ret = (VALUE) rb_thread_call_without_gvl(unblock_executor, &d,
|
48
|
+
NULL, NULL);
|
49
|
+
|
50
|
+
if (d.exception_ptr)
|
51
|
+
std::rethrow_exception(d.exception_ptr);
|
52
|
+
|
53
|
+
return ret;
|
54
|
+
}
|
55
|
+
|
56
|
+
void ruby_unblock(const std::function<void(void)>& block) {
|
57
|
+
unblock_data d((std::function<void*()>&) block);
|
58
|
+
rb_thread_call_without_gvl(unblock_executor, &d,
|
59
|
+
NULL, NULL);
|
60
|
+
|
61
|
+
if (d.exception_ptr)
|
62
|
+
std::rethrow_exception(d.exception_ptr);
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
|