ttcrypt 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/ext/ttcrypt/big_integer.h +3 -0
- data/ext/ttcrypt/byte_buffer.h +6 -7
- data/ext/ttcrypt/pollard_rho.cpp +0 -19
- data/ext/ttcrypt/rsa_key.cpp +241 -23
- data/ext/ttcrypt/rsa_key.h +9 -5
- data/ext/ttcrypt/text_utils.cpp +7 -2
- data/ext/ttcrypt/text_utils.h +1 -0
- data/ext/ttcrypt/ttcrypt.cpp +1 -1
- data/ext/ttcrypt/ttcrypt_ruby.cpp +20 -0
- data/lib/ttcrypt/version.rb +1 -1
- data/lib/ttcrypt.rb +8 -1
- data/spec/ttcrypt_spec.rb +30 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b88f2dc4431b1ba173947a270240d8fa9108037c
|
4
|
+
data.tar.gz: c5118f3a7a1d341143436cebc6ab5db76bc4281c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54eb96a7ba642dd2ea8c565f8e80c3f9362274cb20577a424cd8ba7058bbc194bcba7209f070a0e198c500d9dd5c9b7ba8d80f90a32a02920fa09ca020301edc
|
7
|
+
data.tar.gz: 35612669bd04001643923078904ed3f2822c0eb533f1b7d0102b38375c63d364816005f317425790d8281ef3d5cbeb8c2dd2df773663a8d7250dd9ac37f37eca
|
data/README.md
CHANGED
@@ -8,9 +8,13 @@ variants and othe cryptoprimitives widely used in Thrift projects, namely:
|
|
8
8
|
* RSAES-OAEP encryption
|
9
9
|
* RSASS-PSS signing
|
10
10
|
* Pollard 'rho' factorization
|
11
|
+
* Fast orime generation
|
11
12
|
* SHA1 and SHA256 hashes (under development)
|
12
13
|
* RJ256/256 (under development)
|
13
14
|
|
15
|
+
All long operation are being preformed releasing GVL so other ruby threads can execute while ttcrypt
|
16
|
+
thinks.
|
17
|
+
|
14
18
|
## Installation
|
15
19
|
|
16
20
|
Current implementation targeted fro MRI ruby 2.0+.
|
data/ext/ttcrypt/big_integer.h
CHANGED
@@ -193,6 +193,9 @@ namespace thrift {
|
|
193
193
|
Convert to BIE ENDIAN bytes array.
|
194
194
|
*/
|
195
195
|
byte_buffer to_byte_buffer() const noexcept {
|
196
|
+
// Workaround for some Andoid targets
|
197
|
+
if( *this == 0 )
|
198
|
+
return byte_buffer::pad(0, 1);
|
196
199
|
size_t count = (mpz_sizeinbase (val, 2) + 7) / 8;
|
197
200
|
byte_buffer res = byte_buffer(count);
|
198
201
|
size_t count2 = count;
|
data/ext/ttcrypt/byte_buffer.h
CHANGED
@@ -26,6 +26,7 @@
|
|
26
26
|
|
27
27
|
#include <iostream>
|
28
28
|
#include <string.h>
|
29
|
+
#include <memory>
|
29
30
|
#include "text_utils.h"
|
30
31
|
|
31
32
|
using namespace std;
|
@@ -110,13 +111,11 @@ namespace thrift {
|
|
110
111
|
}
|
111
112
|
}
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
: buffer(new byte[size]), length(size), _capacity(size) {
|
119
|
-
memset( buffer.get(), fill, size);
|
114
|
+
template<typename T>
|
115
|
+
static byte_buffer pad(T fill, size_t size) {
|
116
|
+
byte_buffer result(size);
|
117
|
+
memset( result.data().get(), (int)fill, size);
|
118
|
+
return result;
|
120
119
|
}
|
121
120
|
|
122
121
|
shared_ptr<byte> data() const noexcept {
|
data/ext/ttcrypt/pollard_rho.cpp
CHANGED
@@ -27,25 +27,6 @@ using namespace thrift;
|
|
27
27
|
using namespace std;
|
28
28
|
|
29
29
|
inline big_integer rho(const big_integer& n) {
|
30
|
-
/*
|
31
|
-
BigInteger divisor;
|
32
|
-
BigInteger c = new BigInteger(N.bitLength(), random);
|
33
|
-
BigInteger x = new BigInteger(N.bitLength(), random);
|
34
|
-
BigInteger xx = x;
|
35
|
-
|
36
|
-
// check divisibility by 2
|
37
|
-
if (N.mod(two).compareTo(BigInteger.ZERO) == 0) return two;
|
38
|
-
|
39
|
-
do {
|
40
|
-
x = x.multiply(x).mod(N).add(c).mod(N);
|
41
|
-
xx = xx.multiply(xx).mod(N).add(c).mod(N);
|
42
|
-
xx = xx.multiply(xx).mod(N).add(c).mod(N);
|
43
|
-
divisor = x.subtract(xx).gcd(N);
|
44
|
-
} while ((divisor.compareTo(BigInteger.ONE)) == 0);
|
45
|
-
|
46
|
-
return divisor;
|
47
|
-
}
|
48
|
-
*/
|
49
30
|
big_integer divisor;
|
50
31
|
auto c = big_integer::random_bits(n.bit_length());
|
51
32
|
auto x = big_integer::random_bits(n.bit_length());
|
data/ext/ttcrypt/rsa_key.cpp
CHANGED
@@ -21,10 +21,9 @@
|
|
21
21
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
22
22
|
*/
|
23
23
|
|
24
|
+
#include <future>
|
24
25
|
#include "rsa_key.h"
|
25
26
|
#include "ttcrypt.h"
|
26
|
-
#include <assert.h>
|
27
|
-
#include <future>
|
28
27
|
|
29
28
|
using namespace ttcrypt;
|
30
29
|
using namespace thrift;
|
@@ -34,13 +33,14 @@ namespace ttcrypt {
|
|
34
33
|
static byte_buffer mgf1(const byte_buffer& z, size_t l) {
|
35
34
|
const size_t hLen = 20;
|
36
35
|
byte_buffer t;
|
37
|
-
for (unsigned i = 0; i <= l / hLen; i++)
|
36
|
+
for (unsigned i = 0; i <= l / hLen; i++) {
|
38
37
|
t += sha1(z + i2osp(i, 4));
|
38
|
+
}
|
39
39
|
return byte_buffer(t, 0, l - 1);
|
40
40
|
}
|
41
41
|
|
42
42
|
byte_buffer eme_oaep_encode(const byte_buffer& message, size_t emLen,
|
43
|
-
const byte_buffer
|
43
|
+
const byte_buffer* p, const byte_buffer* pseed) {
|
44
44
|
const size_t hLen = 20;
|
45
45
|
const size_t hLen2 = 2 * hLen;
|
46
46
|
|
@@ -51,19 +51,19 @@ byte_buffer eme_oaep_encode(const byte_buffer& message, size_t emLen,
|
|
51
51
|
if (mLen >= emLen - 1 - hLen2 || mLen > emLen - 2 * hLen2 - 1)
|
52
52
|
throw rsa_key::error("message too long");
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
auto ps = byte_buffer::pad('\0', emLen - mLen - hLen2 - 1);
|
55
|
+
auto pHash = sha1(p ? *p : "");
|
56
|
+
auto db = pHash + ps + "\001" + message;
|
57
|
+
auto seed = (pseed != 0) ? *pseed : byte_buffer::random(hLen);
|
58
|
+
auto dbMask = mgf1(seed, emLen - hLen);
|
59
|
+
auto maskedDb = db ^ dbMask;
|
60
|
+
auto seedMask = mgf1(maskedDb, hLen);
|
61
|
+
auto maskedSeed = seed ^ seedMask;
|
62
62
|
|
63
63
|
return maskedSeed + maskedDb;
|
64
64
|
}
|
65
65
|
|
66
|
-
byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer
|
66
|
+
byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer* p) {
|
67
67
|
const size_t hLen = 20;
|
68
68
|
if (message.size() < hLen * 2 + 1)
|
69
69
|
throw rsa_key::error("message is too short");
|
@@ -74,11 +74,11 @@ byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer& p) {
|
|
74
74
|
auto seed = maskedSeed ^ seedMask;
|
75
75
|
auto db_mask = mgf1(seed, message.size() - hLen);
|
76
76
|
auto db = maskedDb ^ db_mask;
|
77
|
-
auto pHash = sha1(p);
|
77
|
+
auto pHash = sha1(p ? *p : "");
|
78
78
|
|
79
79
|
int index = db.index_of('\001', hLen);
|
80
80
|
if (index < 0)
|
81
|
-
throw rsa_key::error("message is invalid");
|
81
|
+
throw rsa_key::error("message is invalid (no 1)");
|
82
82
|
|
83
83
|
byte_buffer pHash2(db, 0, hLen - 1);
|
84
84
|
byte_buffer ps(db, hLen, index - 1);
|
@@ -86,7 +86,7 @@ byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer& p) {
|
|
86
86
|
|
87
87
|
for (auto x : ps) {
|
88
88
|
if (x != '\0')
|
89
|
-
throw rsa_key::error("message is invalid");
|
89
|
+
throw rsa_key::error("message is invalid (zero padding)");
|
90
90
|
}
|
91
91
|
|
92
92
|
if (pHash2 != pHash)
|
@@ -96,9 +96,9 @@ byte_buffer eme_oaep_decode(const byte_buffer& message, const byte_buffer& p) {
|
|
96
96
|
}
|
97
97
|
|
98
98
|
byte_buffer rsa_key::rsadp(const byte_buffer& ciphertext) const {
|
99
|
-
big_integer c =
|
99
|
+
big_integer c = ciphertext;
|
100
100
|
if (c >= n - 1)
|
101
|
-
throw rsa_key::error("
|
101
|
+
throw rsa_key::error("ciphertext is too long");
|
102
102
|
if (fast_key) {
|
103
103
|
// Fast
|
104
104
|
auto m1 = powmod_sec((c % p), dp, p);
|
@@ -135,9 +135,9 @@ byte_buffer emsa_pss_encode(const byte_buffer& message, size_t emBits,
|
|
135
135
|
if (emLen < hLen + sLen + 2)
|
136
136
|
throw rsa_key::error("invliad salt length");
|
137
137
|
|
138
|
-
auto M1 = byte_buffer('\0', 8) + mHash + salt;
|
138
|
+
auto M1 = byte_buffer::pad('\0', 8) + mHash + salt;
|
139
139
|
auto H = hash(M1);
|
140
|
-
auto PS = byte_buffer('\0', emLen - sLen - hLen - 2);
|
140
|
+
auto PS = byte_buffer::pad('\0', emLen - sLen - hLen - 2);
|
141
141
|
auto DB = PS.append_byte(1) + salt;
|
142
142
|
auto dbMask = mgf1(H, emLen - hLen - 1);
|
143
143
|
|
@@ -195,7 +195,7 @@ bool emsa_pss_verify(const byte_buffer& source_message,
|
|
195
195
|
|
196
196
|
byte_buffer salt(DB, -sLen, -1);
|
197
197
|
|
198
|
-
auto M1 = byte_buffer('\0', 8) + mHash + salt;
|
198
|
+
auto M1 = byte_buffer::pad('\0', 8) + mHash + salt;
|
199
199
|
auto H1 = hash(M1);
|
200
200
|
return H == H1;
|
201
201
|
}
|
@@ -278,9 +278,14 @@ rsa_key rsa_key::generate(unsigned int k, size_t e) {
|
|
278
278
|
|
279
279
|
// v2.2 Algorithm
|
280
280
|
while (true) {
|
281
|
+
#ifdef NO_FUTURE
|
282
|
+
auto q = prime(k - k / 2);
|
283
|
+
auto p = prime(k/2);
|
284
|
+
#else
|
281
285
|
auto future = std::async(std::launch::async, [k] {return prime(k/2);});
|
282
286
|
auto q = prime(k - k / 2);
|
283
287
|
auto p = future.get();
|
288
|
+
#endif
|
284
289
|
if (p == q)
|
285
290
|
continue;
|
286
291
|
|
@@ -302,8 +307,7 @@ rsa_key rsa_key::generate(unsigned int k, size_t e) {
|
|
302
307
|
throw logic_error("pq generation failed");
|
303
308
|
}
|
304
309
|
|
305
|
-
void rsa_key::set(string name, const thrift::big_integer &value) {
|
306
|
-
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
310
|
+
void rsa_key::set(const string& name, const thrift::big_integer &value) {
|
307
311
|
switch (name[0]) {
|
308
312
|
case 'e':
|
309
313
|
e = value;
|
@@ -369,5 +373,219 @@ unordered_map<string, big_integer> rsa_key::get_params(bool include_all) const
|
|
369
373
|
return params;
|
370
374
|
}
|
371
375
|
|
376
|
+
static ostream *pout;
|
377
|
+
|
378
|
+
#define LHEX(text,data) {*pout<<text<<":\n"<<data.hex(16)<<endl;}
|
379
|
+
|
380
|
+
#define REQUIRE(x) if(!(x)){*pout<<"Failed "<<(#x)<<" @"<<__FILE__<<":"<<__LINE__<<endl; return false;}
|
381
|
+
|
382
|
+
|
383
|
+
bool rsa_key::self_test(ostream& out) {
|
384
|
+
pout = &out;
|
385
|
+
{
|
386
|
+
out << "we start..." << endl;
|
387
|
+
big_integer mi = pow(2_b,1024) - 173_b;
|
388
|
+
|
389
|
+
if( big_integer(mi.to_byte_buffer()) != mi ) {
|
390
|
+
out << "Decoding problem" << endl;
|
391
|
+
return false;
|
392
|
+
}
|
393
|
+
byte_buffer res = i2osp(65537_b);
|
394
|
+
if( res.hex() != "01 00 01") {
|
395
|
+
out << "i2osp fail: " << res.hex() << endl;
|
396
|
+
return false;
|
397
|
+
}
|
398
|
+
|
399
|
+
mi = os2ip(res);
|
400
|
+
if( mi != 65537_b ) {
|
401
|
+
out << "I2OSP/OS2IP failure: Result is not 65537: " << mi << endl;
|
402
|
+
return false;
|
403
|
+
}
|
404
|
+
|
405
|
+
mi = pow(2_b,1023) - 1_b;
|
406
|
+
byte_buffer x = rsadp( rsaep(mi.to_byte_buffer()) );
|
407
|
+
|
408
|
+
if( big_integer(x) != mi ) {
|
409
|
+
out << "Big integer failure: " << big_integer(x) << endl;
|
410
|
+
return false;
|
411
|
+
}
|
412
|
+
|
413
|
+
|
414
|
+
byte_buffer src("hello!");
|
415
|
+
if( i2osp( os2ip(src), 6) != src ) {
|
416
|
+
out << "Failed osp2: " << i2osp( os2ip(src), 6) << endl;
|
417
|
+
return false;
|
418
|
+
}
|
419
|
+
|
420
|
+
string sres = i2osp(254,3).hex();
|
421
|
+
if( sres != "00 00 fe" ) {
|
422
|
+
out << "i20sp padding failure: " << sres << endl;
|
423
|
+
return false;
|
424
|
+
}
|
425
|
+
|
426
|
+
if( sha1("abc") != decode_hex("a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d") ) {
|
427
|
+
out << "SHA1 failed: " << sha1("abc").hex() << endl;
|
428
|
+
return false;
|
429
|
+
}
|
430
|
+
|
431
|
+
if( sha1("") != decode_hex("da39a3ee 5e6b4b0d 3255bfef 95601890 afd80709") ) {
|
432
|
+
out << "SHA1 of empty string failed: " << sha1("").hex() << endl;
|
433
|
+
return false;
|
434
|
+
}
|
435
|
+
|
436
|
+
res = eme_oaep_decode(eme_oaep_encode(src, 127, 0, 0), 0);
|
437
|
+
if( res != src ) {
|
438
|
+
out << "OAEP failed: " << res;
|
439
|
+
return false;
|
440
|
+
}
|
441
|
+
|
442
|
+
}
|
443
|
+
{
|
444
|
+
out << "RSAES test" << endl;
|
445
|
+
auto message = decode_hex("d4 36 e9 95 69 fd 32 a7 c8 a0 5b bc 90 d3 2c 49");
|
446
|
+
|
447
|
+
auto seed = decode_hex("aa fd 12 f6 59 ca e6 34 89 b4 79 e5 07 6d de c2 f0 6c b5 8f");
|
448
|
+
|
449
|
+
auto encoded_message = decode_hex("\
|
450
|
+
eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2 ca 82 31 0b 26 dc d8 7d 5c 68\
|
451
|
+
f1 ee a8 f5 52 67 c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af f9 3e dc\
|
452
|
+
fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db 4c dc fe 4f f4 77 28 b4 a1 b7 c1 36\
|
453
|
+
2b aa d2 9a b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9 82 fb 3e 87 d0\
|
454
|
+
95 ae b4 04 48 db 97 2f 3a c1 4f 7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35\
|
455
|
+
3e 2d");
|
456
|
+
|
457
|
+
auto encrypted_message = decode_hex("\
|
458
|
+
12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 39 a3 3d 1e 99 6f c8 2a 94\
|
459
|
+
cc d3 00 74 c9 5d f7 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 53 c1\
|
460
|
+
1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb 6d 84 b1 c3 1d 65 4a 19 70 e5 78\
|
461
|
+
3b d6 eb 96 a0 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 da 95 36 ad\
|
462
|
+
87 00 c8 4f c9 13 0a de a7 4e 55 8d 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06\
|
463
|
+
3e 09 55");
|
464
|
+
|
465
|
+
auto n = decode_hex("\
|
466
|
+
bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 36 8d 07 ee d4 10 43 a4\
|
467
|
+
40 d6 b6 f0 74 54 f5 1f b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48\
|
468
|
+
76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f af b8 e0 a3 df c7 37 72\
|
469
|
+
3e e6 b4 b7 d9 3a 25 84 ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e\
|
470
|
+
e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f e2 53 72 98 ca 2a 8f 59\
|
471
|
+
46 f8 e5 fd 09 1d bd cb");
|
472
|
+
|
473
|
+
unsigned e = 0x11;
|
474
|
+
|
475
|
+
auto p = decode_hex("\
|
476
|
+
ee cf ae 81 b1 b9 b3 c9 08 81 0b 10 a1 b5 60 01 99 eb 9f 44 ae f4 fd a4\
|
477
|
+
93 b8 1a 9e 3d 84 f6 32 12 4e f0 23 6e 5d 1e 3b 7e 28 fa e7 aa 04 0a 2d\
|
478
|
+
5b 25 21 76 45 9d 1f 39 75 41 ba 2a 58 fb 65 99");
|
479
|
+
|
480
|
+
auto q = decode_hex("\
|
481
|
+
c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35 3f 6c 42 d0 88 66 b1 d0\
|
482
|
+
5a 0f 20 35 02 8b 9d 86 98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf\
|
483
|
+
ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03");
|
484
|
+
|
485
|
+
// auto dP = decode_hex("\
|
486
|
+
// 54 49 4c a6 3e ba 03 37 e4 e2 40 23 fc d6 9a 5a eb 07 dd dc 01 83 a4 d0\
|
487
|
+
// ac 9b 54 b0 51 f2 b1 3e d9 49 09 75 ea b7 74 14 ff 59 c1 f7 69 2e 9a 2e\
|
488
|
+
// 20 2b 38 fc 91 0a 47 41 74 ad c9 3c 1f 67 c9 81");
|
489
|
+
//
|
490
|
+
// auto dQ = decode_hex("\
|
491
|
+
// 47 1e 02 90 ff 0a f0 75 03 51 b7 f8 78 86 4c a9 61 ad bd 3a 8a 7e 99 1c\
|
492
|
+
// 5c 05 56 a9 4c 31 46 a7 f9 80 3f 8f 6f 8a e3 42 e9 31 fd 8a e4 7a 22 0d\
|
493
|
+
// 1b 99 a4 95 84 98 07 fe 39 f9 24 5a 98 36 da 3d");
|
494
|
+
//
|
495
|
+
// auto qInv = decode_hex("\
|
496
|
+
// b0 6c 4f da bb 63 01 19 8d 26 5b db ae 94 23 b3 80 f2 71 f7 34 53 88 50\
|
497
|
+
// 93 07 7f cd 39 e2 11 9f c9 86 32 15 4f 58 83 b1 67 a9 67 bf 40 2b 4e 9e\
|
498
|
+
// 2e 0f 96 56 e6 98 ea 36 66 ed fb 25 79 80 39 f7");
|
499
|
+
|
500
|
+
rsa_key key(n, e, p, q);
|
501
|
+
key.debug_seed(seed);
|
502
|
+
|
503
|
+
REQUIRE( key.encrypt(message).hex() == encrypted_message.hex() );
|
504
|
+
REQUIRE( key.decrypt(encrypted_message).hex() == message.hex() );
|
505
|
+
|
506
|
+
rsa_key key2(n, e, p, q);
|
507
|
+
REQUIRE( key2.is_private() == true);
|
508
|
+
|
509
|
+
REQUIRE( key2.decrypt(encrypted_message).hex() == message.hex() );
|
510
|
+
}
|
511
|
+
{
|
512
|
+
out << "Sign test" << endl;
|
513
|
+
|
514
|
+
auto signing_salt = decode_hex("e3 b5 d5 d0 02 c1 bc e5 0c 2b 65 ef 88 a1 88 d8 3b ce 7e 61");
|
515
|
+
|
516
|
+
auto message = decode_hex("85 9e ef 2f d7 8a ca 00 30 8b dc 47 11 93 bf 55"
|
517
|
+
"bf 9d 78 db 8f 8a 67 2b 48 46 34 f3 c9 c2 6e 64"
|
518
|
+
"78 ae 10 26 0f e0 dd 8c 08 2e 53 a5 29 3a f2 17"
|
519
|
+
"3c d5 0c 6d 5d 35 4f eb f7 8b 26 02 1c 25 c0 27"
|
520
|
+
"12 e7 8c d4 69 4c 9f 46 97 77 e4 51 e7 f8 e9 e0"
|
521
|
+
"4c d3 73 9c 6b bf ed ae 48 7f b5 56 44 e9 ca 74"
|
522
|
+
"ff 77 a5 3c b7 29 80 2f 6e d4 a5 ff a8 ba 15 98"
|
523
|
+
"90 fc");
|
524
|
+
auto EM = decode_hex(
|
525
|
+
"66 e4 67 2e 83 6a d1 21 ba 24 4b ed 65 76 b8 67"
|
526
|
+
"d9 a4 47 c2 8a 6e 66 a5 b8 7d ee 7f bc 7e 65 af"
|
527
|
+
"50 57 f8 6f ae 89 84 d9 ba 7f 96 9a d6 fe 02 a4"
|
528
|
+
"d7 5f 74 45 fe fd d8 5b 6d 3a 47 7c 28 d2 4b a1"
|
529
|
+
"e3 75 6f 79 2d d1 dc e8 ca 94 44 0e cb 52 79 ec"
|
530
|
+
"d3 18 3a 31 1f c8 96 da 1c b3 93 11 af 37 ea 4a"
|
531
|
+
"75 e2 4b db fd 5c 1d a0 de 7c ec df 1a 89 6f 9d"
|
532
|
+
"8b c8 16 d9 7c d7 a2 c4 3b ad 54 6f be 8c fe bc");
|
533
|
+
|
534
|
+
//# RSA modulus n:
|
535
|
+
auto n = decode_hex("\
|
536
|
+
a2 ba 40 ee 07 e3 b2 bd 2f 02 ce 22 7f 36 a1 95\
|
537
|
+
02 44 86 e4 9c 19 cb 41 bb bd fb ba 98 b2 2b 0e\
|
538
|
+
57 7c 2e ea ff a2 0d 88 3a 76 e6 5e 39 4c 69 d4\
|
539
|
+
b3 c0 5a 1e 8f ad da 27 ed b2 a4 2b c0 00 fe 88\
|
540
|
+
8b 9b 32 c2 2d 15 ad d0 cd 76 b3 e7 93 6e 19 95\
|
541
|
+
5b 22 0d d1 7d 4e a9 04 b1 ec 10 2b 2e 4d e7 75\
|
542
|
+
12 22 aa 99 15 10 24 c7 cb 41 cc 5e a2 1d 00 ee\
|
543
|
+
b4 1f 7c 80 08 34 d2 c6 e0 6b ce 3b ce 7e a9 a5");
|
544
|
+
|
545
|
+
//# RSA public exponent e:
|
546
|
+
auto e = 0x010001;
|
547
|
+
//
|
548
|
+
//# Prime p:
|
549
|
+
auto p = decode_hex("\
|
550
|
+
d1 7f 65 5b f2 7c 8b 16 d3 54 62 c9 05 cc 04 a2\
|
551
|
+
6f 37 e2 a6 7f a9 c0 ce 0d ce d4 72 39 4a 0d f7\
|
552
|
+
43 fe 7f 92 9e 37 8e fd b3 68 ed df f4 53 cf 00\
|
553
|
+
7a f6 d9 48 e0 ad e7 57 37 1f 8a 71 1e 27 8f 6b");
|
554
|
+
|
555
|
+
//# Prime q:
|
556
|
+
auto q = decode_hex("\
|
557
|
+
c6 d9 2b 6f ee 74 14 d1 35 8c e1 54 6f b6 29 87\
|
558
|
+
53 0b 90 bd 15 e0 f1 49 63 a5 e2 63 5a db 69 34\
|
559
|
+
7e c0 c0 1b 2a b1 76 3f d8 ac 1a 59 2f b2 27 57\
|
560
|
+
46 3a 98 24 25 bb 97 a3 a4 37 c5 bf 86 d0 3f 2f");
|
561
|
+
|
562
|
+
auto signature = decode_hex("\
|
563
|
+
8d aa 62 7d 3d e7 59 5d 63 05 6c 7e c6 59 e5 44\
|
564
|
+
06 f1 06 10 12 8b aa e8 21 c8 b2 a0 f3 93 6d 54\
|
565
|
+
dc 3b dc e4 66 89 f6 b7 95 1b b1 8e 84 05 42 76\
|
566
|
+
97 18 d5 71 5d 21 0d 85 ef bb 59 61 92 03 2c 42\
|
567
|
+
be 4c 29 97 2c 85 62 75 eb 6d 5a 45 f0 5f 51 87\
|
568
|
+
6f c6 74 3d ed dd 28 ca ec 9b b3 0e a9 9e 02 c3\
|
569
|
+
48 82 69 60 4f e4 97 f7 4c cd 7c 7f ca 16 71 89\
|
570
|
+
71 23 cb d3 0d ef 5d 54 a2 b5 53 6a d9 0a 74 7e");
|
571
|
+
|
572
|
+
auto padded = emsa_pss_encode(message, 1023, sha1, &signing_salt);
|
573
|
+
REQUIRE( padded.hex() == EM.hex() );
|
574
|
+
REQUIRE(true == emsa_pss_verify(message, padded, 1023, sha1, signing_salt.size()));
|
575
|
+
REQUIRE(false == emsa_pss_verify(message+"!", padded, 1023, sha1, signing_salt.size()));
|
576
|
+
padded.set(0, padded[0] ^ 3);
|
577
|
+
REQUIRE(false == emsa_pss_verify(message, padded, 1023, sha1, signing_salt.size()));
|
578
|
+
|
579
|
+
rsa_key key(n, e, p, q);
|
580
|
+
auto s = key.sign(message, sha1, &signing_salt);
|
581
|
+
REQUIRE( s == signature );
|
582
|
+
REQUIRE( key.verify(message, s, sha1, signing_salt.size()) == true );
|
583
|
+
|
584
|
+
s = key.sign(message+"!", sha1, &signing_salt);
|
585
|
+
REQUIRE( s != signature );
|
586
|
+
}
|
587
|
+
return true;
|
588
|
+
}
|
589
|
+
|
372
590
|
}
|
373
591
|
|
data/ext/ttcrypt/rsa_key.h
CHANGED
@@ -33,8 +33,8 @@ namespace ttcrypt {
|
|
33
33
|
|
34
34
|
using namespace thrift;
|
35
35
|
|
36
|
-
byte_buffer eme_oaep_encode( const byte_buffer& message,size_t emLen, const byte_buffer
|
37
|
-
byte_buffer eme_oaep_decode(const byte_buffer& message,const byte_buffer
|
36
|
+
byte_buffer eme_oaep_encode( const byte_buffer& message,size_t emLen, const byte_buffer* p=0, const byte_buffer *seed=nullptr);
|
37
|
+
byte_buffer eme_oaep_decode(const byte_buffer& message,const byte_buffer* p=0);
|
38
38
|
|
39
39
|
byte_buffer emsa_pss_encode(const byte_buffer& message,size_t emBits,byte_buffer (*hash)(const byte_buffer&),const byte_buffer* salt);
|
40
40
|
bool emsa_pss_verify(const byte_buffer& source_message,
|
@@ -80,7 +80,7 @@ namespace ttcrypt {
|
|
80
80
|
Set the named parameter to a given value. Supported values are: n, e, d, p, q, dp, dq, qinv.
|
81
81
|
Not case sesitive. Call normalize_key() when done changing parameters.
|
82
82
|
*/
|
83
|
-
void set(string name, const big_integer& value);
|
83
|
+
void set(const string& name, const big_integer& value);
|
84
84
|
|
85
85
|
/**
|
86
86
|
Construct private key from parts. If not all parts are provided, recalculates missing ones that
|
@@ -123,7 +123,7 @@ namespace ttcrypt {
|
|
123
123
|
RSAES-OAEP encrypt a message.
|
124
124
|
*/
|
125
125
|
byte_buffer encrypt(const byte_buffer& plaintext) const {
|
126
|
-
return rsaep(eme_oaep_encode(plaintext, byte_size - 1,
|
126
|
+
return rsaep(eme_oaep_encode(plaintext, byte_size - 1, 0, pseed));
|
127
127
|
}
|
128
128
|
|
129
129
|
/**
|
@@ -132,7 +132,9 @@ namespace ttcrypt {
|
|
132
132
|
byte_buffer decrypt(const byte_buffer& ciphertext) const {
|
133
133
|
return eme_oaep_decode( rsadp( ciphertext) );
|
134
134
|
}
|
135
|
-
|
135
|
+
|
136
|
+
bool self_test(ostream& os);
|
137
|
+
|
136
138
|
/**
|
137
139
|
Create RSASSA-PSS signature for a given message. Requires private key.
|
138
140
|
@param message what to sign
|
@@ -216,6 +218,8 @@ namespace ttcrypt {
|
|
216
218
|
_use_blinding = use;
|
217
219
|
}
|
218
220
|
|
221
|
+
byte_buffer get_e() const { return e.to_byte_buffer(); }
|
222
|
+
|
219
223
|
private:
|
220
224
|
big_integer n, e, p, q, d, dp, dq, q_inv;
|
221
225
|
unsigned byte_size=0, bits_size=0;
|
data/ext/ttcrypt/text_utils.cpp
CHANGED
@@ -20,8 +20,13 @@
|
|
20
20
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21
21
|
*/
|
22
22
|
|
23
|
+
#include <stdarg.h>
|
23
24
|
#include "text_utils.h"
|
24
25
|
|
26
|
+
template<typename X>
|
27
|
+
X ABS(X val) {
|
28
|
+
return val < 0 ? -val : val;
|
29
|
+
}
|
25
30
|
|
26
31
|
std::string sformat(const std::string fmt_str, ...) {
|
27
32
|
int final_n, n = ((int)fmt_str.size()) * 2; /* reserve 2 times as much as the length of the fmt_str */
|
@@ -35,7 +40,7 @@ std::string sformat(const std::string fmt_str, ...) {
|
|
35
40
|
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
|
36
41
|
va_end(ap);
|
37
42
|
if (final_n < 0 || final_n >= n)
|
38
|
-
n +=
|
43
|
+
n += ABS(final_n - n + 1);
|
39
44
|
else
|
40
45
|
break;
|
41
46
|
}
|
@@ -54,7 +59,7 @@ std::string vsformat(const std::string fmt_str, va_list args) {
|
|
54
59
|
final_n = vsnprintf(&formatted[0], n-1, fmt_str.c_str(), c);
|
55
60
|
va_end(c);
|
56
61
|
if (final_n < 0 || final_n >= n)
|
57
|
-
n +=
|
62
|
+
n += ABS(final_n - n + 1);
|
58
63
|
else
|
59
64
|
break;
|
60
65
|
}
|
data/ext/ttcrypt/text_utils.h
CHANGED
data/ext/ttcrypt/ttcrypt.cpp
CHANGED
@@ -45,7 +45,7 @@ byte_buffer ttcrypt::i2osp(const big_integer& i, size_t block_size) noexcept {
|
|
45
45
|
if( block_size > 0 && res.size() != block_size ) {
|
46
46
|
size_t pad_length = block_size - res.size() % block_size;
|
47
47
|
if( pad_length > 0 )
|
48
|
-
return byte_buffer('\0', pad_length) + res;
|
48
|
+
return byte_buffer::pad('\0', pad_length) + res;
|
49
49
|
}
|
50
50
|
return res;
|
51
51
|
}
|
@@ -118,6 +118,25 @@ static VALUE factorize(VALUE self, VALUE composite) {
|
|
118
118
|
});
|
119
119
|
}
|
120
120
|
|
121
|
+
static VALUE _generate_prime(VALUE self, VALUE bits) {
|
122
|
+
return wrap_exceptions([=] {
|
123
|
+
unsigned nbits = FIX2INT(bits);
|
124
|
+
big_integer prime;
|
125
|
+
ruby_unblock([nbits, &prime] {
|
126
|
+
auto min = pow(2_b, nbits-1);
|
127
|
+
auto max = 2*min - 1;
|
128
|
+
big_integer random;
|
129
|
+
do {
|
130
|
+
random = big_integer::random_between(min, max);
|
131
|
+
prime = next_prime(random);
|
132
|
+
} while( prime > max );
|
133
|
+
if( prime.bit_length() != nbits )
|
134
|
+
throw std::logic_error("random generation logic failed");
|
135
|
+
});
|
136
|
+
return to_hex_value(prime);
|
137
|
+
});
|
138
|
+
}
|
139
|
+
|
121
140
|
typedef byte_buffer (*hash_t)(const byte_buffer &);
|
122
141
|
|
123
142
|
static hash_t hash_provider(VALUE name) {
|
@@ -213,6 +232,7 @@ void Init_ttcrypt(void) {
|
|
213
232
|
VALUE ttcrypt_module = rb_define_module("TTCrypt");
|
214
233
|
|
215
234
|
rb_define_method(ttcrypt_module, "_factorize", (ruby_method) factorize, 1);
|
235
|
+
rb_define_method(ttcrypt_module, "_generate_prime", (ruby_method) _generate_prime, 1);
|
216
236
|
|
217
237
|
rsa_class = rb_define_class_under(ttcrypt_module, "RsaKey", rb_cObject);
|
218
238
|
rb_define_alloc_func(rsa_class, rsa_alloc);
|
data/lib/ttcrypt/version.rb
CHANGED
data/lib/ttcrypt.rb
CHANGED
@@ -13,6 +13,13 @@ module TTCrypt
|
|
13
13
|
_factorize(hex).map { |x| x.to_i(16) }
|
14
14
|
end
|
15
15
|
|
16
|
+
# Generate random probable prime number with a given bits length. This implementation will generate
|
17
|
+
# prime such as 2^(bits-1) < prime < 2 ^ bits.
|
18
|
+
#
|
19
|
+
def generate_prime bits
|
20
|
+
_generate_prime(bits).to_i(16)
|
21
|
+
end
|
22
|
+
|
16
23
|
# Implementation of RSAES-OAEP encryption and RSASSA-PSS signing
|
17
24
|
# accroding to pkcs#1 v2.2 specification. Does NOT implement any previous cryptographically
|
18
25
|
# weak shcemes (like 1.5 signature) - go use openssl for itm but it does compromise private
|
@@ -137,6 +144,6 @@ end
|
|
137
144
|
require 'ttcrypt/ttcrypt'
|
138
145
|
|
139
146
|
module TTCrypt
|
140
|
-
module_function :factorize, :_factorize
|
147
|
+
module_function :factorize, :_factorize, :generate_prime, :_generate_prime
|
141
148
|
end
|
142
149
|
|
data/spec/ttcrypt_spec.rb
CHANGED
@@ -16,9 +16,21 @@ describe 'rsa-oaep' do
|
|
16
16
|
factors[0].should == p2
|
17
17
|
factors[1].should == p1
|
18
18
|
|
19
|
-
val
|
19
|
+
val = 177130
|
20
20
|
factors = TTCrypt.factorize(val)
|
21
|
-
factors.reduce(1){|all, x| x*all}.should == val
|
21
|
+
factors.reduce(1) { |all, x| x*all }.should == val
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should generate primes' do
|
25
|
+
bits = 35
|
26
|
+
primes = 2.times.map {
|
27
|
+
x = TTCrypt.generate_prime bits
|
28
|
+
x.should > (1<<(bits-1))
|
29
|
+
x.should < (1<<(bits))
|
30
|
+
x
|
31
|
+
}
|
32
|
+
primes.sort!
|
33
|
+
TTCrypt.factorize(primes[0] * primes[1]).sort.should == primes
|
22
34
|
end
|
23
35
|
|
24
36
|
it 'should generate keys in background' do
|
@@ -96,7 +108,7 @@ describe 'rsa-oaep' do
|
|
96
108
|
end
|
97
109
|
end
|
98
110
|
|
99
|
-
it 'should construct from components' do
|
111
|
+
it 'should construct from components and decrypt' do
|
100
112
|
init_test_vectors1
|
101
113
|
key = TTCrypt::RsaKey.new e: @e, p: @p, q: @q
|
102
114
|
key.p.should == @p
|
@@ -108,6 +120,20 @@ describe 'rsa-oaep' do
|
|
108
120
|
key.decrypt(key.extract_public.encrypt(@message)).should == @message
|
109
121
|
end
|
110
122
|
|
123
|
+
it 'should properly encrypt' do
|
124
|
+
init_test_vectors1
|
125
|
+
key = TTCrypt::RsaKey.new e: @e, p: @p, q: @q
|
126
|
+
key.p.should == @p
|
127
|
+
key.q.should == @q
|
128
|
+
key.e.should == @e
|
129
|
+
key.should be_private
|
130
|
+
key.n.should_not be_nil
|
131
|
+
key.decrypt(key.encrypt(@message)).should == @message
|
132
|
+
key.decrypt(key.extract_public.encrypt(@message)).should == @message
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should properly sign'
|
136
|
+
|
111
137
|
def init_test_vectors1
|
112
138
|
@n = h2s <<-End
|
113
139
|
bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 36 8d 07 ee d4 10 43 a4
|
@@ -146,7 +172,7 @@ describe 'rsa-oaep' do
|
|
146
172
|
|
147
173
|
def h2s hex
|
148
174
|
hex = hex.gsub(/\s+/, '')
|
149
|
-
hex.chars.each_slice(2).map{|x,y| (x.to_i(16)<<4 | y.to_i(16)).chr}.join
|
175
|
+
hex.chars.each_slice(2).map { |x, y| (x.to_i(16)<<4 | y.to_i(16)).chr }.join
|
150
176
|
end
|
151
177
|
|
152
178
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ttcrypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sergeych
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|