ttcrypt 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|