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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f88c032607b33e66a47343f5993bb7884925d17f
4
- data.tar.gz: 7ca31bdfa0f0401b1e6cbd3c4c0ce8b19f0f6a6a
3
+ metadata.gz: b88f2dc4431b1ba173947a270240d8fa9108037c
4
+ data.tar.gz: c5118f3a7a1d341143436cebc6ab5db76bc4281c
5
5
  SHA512:
6
- metadata.gz: 3842c52dc96065852cf4d0cf854e0960f165ddb6421cc3efd7b5eae28a1509928949587dd0241caee0a97875cbe823ab07c86070afd5ac33ab4c0464d1cda2da
7
- data.tar.gz: 0f26cfda18f8aca504cf6a00505fd933326fb03fb4c1262262fb1fc75e02d057d1858cc7a38ba43815d1aa21529265849b0d46b876ece5b7de9e69fbbae7c65b
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+.
@@ -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;
@@ -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
- Fill constructor. Create buffer with specified size and fill value
116
- */
117
- byte_buffer(byte fill, size_t size)
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 {
@@ -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());
@@ -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& p, const byte_buffer* pseed) {
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
- 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;
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& p) {
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 = big_integer(ciphertext);
99
+ big_integer c = ciphertext;
100
100
  if (c >= n - 1)
101
- throw rsa_key::error("cipertext is too long");
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
 
@@ -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& p=byte_buffer(), const byte_buffer *seed=nullptr);
37
- byte_buffer eme_oaep_decode(const byte_buffer& message,const byte_buffer& p="");
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,"", pseed));
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;
@@ -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 += abs(final_n - n + 1);
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 += abs(final_n - n + 1);
62
+ n += ABS(final_n - n + 1);
58
63
  else
59
64
  break;
60
65
  }
@@ -25,6 +25,7 @@
25
25
  #define __zcoin__text_utils__
26
26
 
27
27
  #include <iostream>
28
+ #include <memory>
28
29
 
29
30
  std::string sformat(const std::string fmt_str, ...);
30
31
  std::string vsformat(const std::string fmt_str, va_list args);
@@ -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);
@@ -1,5 +1,5 @@
1
1
  module TTCrypt
2
2
 
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
 
5
5
  end
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 = 177130
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.2
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-06-19 00:00:00.000000000 Z
11
+ date: 2014-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler