ttcrypt 0.0.2
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 +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,67 @@
|
|
1
|
+
//
|
2
|
+
// sha256.h
|
3
|
+
// iGlomp
|
4
|
+
//
|
5
|
+
// Created by Sergey Chernov on 28.10.11.
|
6
|
+
// Copyright (c) 2011 Thrift. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#ifndef iGlomp_sha256_h
|
10
|
+
#define iGlomp_sha256_h
|
11
|
+
|
12
|
+
/* Declarations of functions and data types used for SHA256 and SHA224 sum
|
13
|
+
library functions.
|
14
|
+
Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
|
15
|
+
|
16
|
+
This program is free software: you can redistribute it and/or modify
|
17
|
+
it under the terms of the GNU General Public License as published by
|
18
|
+
the Free Software Foundation, either version 3 of the License, or
|
19
|
+
(at your option) any later version.
|
20
|
+
|
21
|
+
This program is distributed in the hope that it will be useful,
|
22
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
24
|
+
GNU General Public License for more details.
|
25
|
+
|
26
|
+
You should have received a copy of the GNU General Public License
|
27
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
28
|
+
|
29
|
+
typedef unsigned char uint8;
|
30
|
+
typedef unsigned int uint32;
|
31
|
+
|
32
|
+
#ifndef SHA256_H
|
33
|
+
# define SHA256_H 1
|
34
|
+
|
35
|
+
# include <stdio.h>
|
36
|
+
# include <stdint.h>
|
37
|
+
|
38
|
+
# ifdef __cplusplus
|
39
|
+
extern "C" {
|
40
|
+
# endif
|
41
|
+
|
42
|
+
/* Structure to save state of computation between the single steps. */
|
43
|
+
typedef struct sha256_ctx
|
44
|
+
{
|
45
|
+
uint32_t state[8];
|
46
|
+
|
47
|
+
uint32_t total[2];
|
48
|
+
size_t buflen;
|
49
|
+
uint8 buffer[64];
|
50
|
+
} sha256_context;
|
51
|
+
|
52
|
+
enum { SHA224_DIGEST_SIZE = 224 / 8 };
|
53
|
+
enum { SHA256_DIGEST_SIZE = 256 / 8 };
|
54
|
+
|
55
|
+
void sha256_starts( sha256_context *ctx );
|
56
|
+
void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
|
57
|
+
void sha256_finish( sha256_context *ctx, uint8 digest[32] );
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
# ifdef __cplusplus
|
62
|
+
}
|
63
|
+
# endif
|
64
|
+
|
65
|
+
|
66
|
+
#endif
|
67
|
+
#endif
|
@@ -0,0 +1,63 @@
|
|
1
|
+
//
|
2
|
+
// text_utils.cpp
|
3
|
+
//
|
4
|
+
// Created by Sergey Chernov on 01.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
|
+
#include "text_utils.h"
|
24
|
+
|
25
|
+
|
26
|
+
std::string sformat(const std::string fmt_str, ...) {
|
27
|
+
int final_n, n = ((int)fmt_str.size()) * 2; /* reserve 2 times as much as the length of the fmt_str */
|
28
|
+
std::string str;
|
29
|
+
std::unique_ptr<char[]> formatted;
|
30
|
+
va_list ap;
|
31
|
+
while(1) {
|
32
|
+
formatted.reset(new char[n]); /* wrap the plain char array into the unique_ptr */
|
33
|
+
// strcpy(&formatted[0], fmt_str.c_str());
|
34
|
+
va_start(ap, fmt_str);
|
35
|
+
final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
|
36
|
+
va_end(ap);
|
37
|
+
if (final_n < 0 || final_n >= n)
|
38
|
+
n += abs(final_n - n + 1);
|
39
|
+
else
|
40
|
+
break;
|
41
|
+
}
|
42
|
+
return std::string(formatted.get());
|
43
|
+
}
|
44
|
+
|
45
|
+
std::string vsformat(const std::string fmt_str, va_list args) {
|
46
|
+
int final_n, n = ((int)fmt_str.size()) * 2; /* reserve 2 times as much as the length of the fmt_str */
|
47
|
+
std::string str;
|
48
|
+
std::unique_ptr<char[]> formatted;
|
49
|
+
while(1) {
|
50
|
+
formatted.reset(new char[n]); /* wrap the plain char array into the unique_ptr */
|
51
|
+
// strcpy(&formatted[0], fmt_str.c_str());
|
52
|
+
va_list c;
|
53
|
+
va_copy(c, args);
|
54
|
+
final_n = vsnprintf(&formatted[0], n-1, fmt_str.c_str(), c);
|
55
|
+
va_end(c);
|
56
|
+
if (final_n < 0 || final_n >= n)
|
57
|
+
n += abs(final_n - n + 1);
|
58
|
+
else
|
59
|
+
break;
|
60
|
+
}
|
61
|
+
return std::string(formatted.get());
|
62
|
+
}
|
63
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
//
|
2
|
+
// text_utils.h
|
3
|
+
// zcoin
|
4
|
+
//
|
5
|
+
// Created by Sergey Chernov on 01.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
|
+
#ifndef __zcoin__text_utils__
|
25
|
+
#define __zcoin__text_utils__
|
26
|
+
|
27
|
+
#include <iostream>
|
28
|
+
|
29
|
+
std::string sformat(const std::string fmt_str, ...);
|
30
|
+
std::string vsformat(const std::string fmt_str, va_list args);
|
31
|
+
|
32
|
+
#ifdef DEBUG
|
33
|
+
|
34
|
+
template <class T> void log_d(const T& object,const std::string& msg) {
|
35
|
+
std::cout << (object.to_string() + ": " + msg) << std::endl;
|
36
|
+
}
|
37
|
+
|
38
|
+
template <class T> void log_d(T *const object,const std::string& msg) {
|
39
|
+
log_d(*object, msg);
|
40
|
+
}
|
41
|
+
|
42
|
+
inline void log_d(const std::string format, ...) {
|
43
|
+
va_list ap;
|
44
|
+
va_start(ap, format);
|
45
|
+
std::cout << vsformat(format, ap) << std::endl;
|
46
|
+
va_end(ap);
|
47
|
+
}
|
48
|
+
|
49
|
+
#else
|
50
|
+
|
51
|
+
#define log_d(...)
|
52
|
+
|
53
|
+
#endif
|
54
|
+
|
55
|
+
template <class T>
|
56
|
+
void stopwatch(T text, std::function<void(void)> block) {
|
57
|
+
std::cout << "Starting " << text << "...";
|
58
|
+
std::cout.flush();
|
59
|
+
clock_t start = clock();
|
60
|
+
block();
|
61
|
+
std::cout << " done, " << (clock() - start)/1000.0 << "ms " << std::endl;
|
62
|
+
}
|
63
|
+
|
64
|
+
#endif /* defined(__zcoin__text_utils__) */
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/*
|
2
|
+
ttcrypt.cpp
|
3
|
+
|
4
|
+
Created by Sergey Chernov on 03.06.14.
|
5
|
+
Copyright (c) 2014 thrift. All rights reserved.
|
6
|
+
|
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 "ttcrypt.h"
|
23
|
+
#include "sha1.h"
|
24
|
+
#include "sha256.h"
|
25
|
+
|
26
|
+
using namespace thrift;
|
27
|
+
|
28
|
+
byte_buffer ttcrypt::sha1(const byte_buffer& data) noexcept {
|
29
|
+
byte_buffer res(20);
|
30
|
+
sha1::calc(data.data().get(), (int)data.size(), res.data().get() );
|
31
|
+
return res;
|
32
|
+
}
|
33
|
+
|
34
|
+
byte_buffer ttcrypt::sha256(const thrift::byte_buffer &data) noexcept {
|
35
|
+
byte_buffer res(32);
|
36
|
+
sha256_ctx ctx;
|
37
|
+
sha256_starts(&ctx);
|
38
|
+
sha256_update(&ctx, data.data().get(), (uint32) data.size());
|
39
|
+
sha256_finish(&ctx, res.data().get());
|
40
|
+
return res;
|
41
|
+
}
|
42
|
+
|
43
|
+
byte_buffer ttcrypt::i2osp(const big_integer& i, size_t block_size) noexcept {
|
44
|
+
byte_buffer res = i.to_byte_buffer();
|
45
|
+
if( block_size > 0 && res.size() != block_size ) {
|
46
|
+
size_t pad_length = block_size - res.size() % block_size;
|
47
|
+
if( pad_length > 0 )
|
48
|
+
return byte_buffer('\0', pad_length) + res;
|
49
|
+
}
|
50
|
+
return res;
|
51
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/*
|
2
|
+
ttcrypt.h
|
3
|
+
zcoin
|
4
|
+
|
5
|
+
Created by Sergey Chernov on 03.06.14.
|
6
|
+
Copyright (c) 2014 thrift. All rights reserved.
|
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
|
+
#ifndef __zcoin__ttcrypt__
|
23
|
+
#define __zcoin__ttcrypt__
|
24
|
+
|
25
|
+
#include <iostream>
|
26
|
+
#include "byte_buffer.h"
|
27
|
+
#include "big_integer.h"
|
28
|
+
|
29
|
+
using namespace thrift;
|
30
|
+
|
31
|
+
namespace ttcrypt {
|
32
|
+
|
33
|
+
byte_buffer sha1(const byte_buffer& data) noexcept;
|
34
|
+
byte_buffer sha256(const byte_buffer& data) noexcept;
|
35
|
+
|
36
|
+
byte_buffer i2osp(const big_integer& i, size_t block_size=0) noexcept;
|
37
|
+
|
38
|
+
inline big_integer os2ip(const byte_buffer& buffer) noexcept {
|
39
|
+
return big_integer(buffer);
|
40
|
+
}
|
41
|
+
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
#endif /* defined(__zcoin__ttcrypt__) */
|
@@ -0,0 +1,234 @@
|
|
1
|
+
/*
|
2
|
+
* TTCrypt ruby bindings
|
3
|
+
*
|
4
|
+
* Copyright (C) 2014 Thrift, Sergey S. Chernov
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
*/
|
19
|
+
#include <iostream>
|
20
|
+
#include <stdlib.h>
|
21
|
+
|
22
|
+
#include "ruby_cpp_tools.h"
|
23
|
+
|
24
|
+
#include "byte_buffer.h"
|
25
|
+
#include "pollard_rho.h"
|
26
|
+
#include "rsa_key.h"
|
27
|
+
|
28
|
+
extern "C" {
|
29
|
+
#include <ruby.h>
|
30
|
+
#include <ruby/thread.h>
|
31
|
+
|
32
|
+
void Init_ttcrypt(void);
|
33
|
+
}
|
34
|
+
|
35
|
+
using namespace thrift;
|
36
|
+
using namespace ttcrypt;
|
37
|
+
|
38
|
+
using namespace std;
|
39
|
+
|
40
|
+
static VALUE rsa_exception;
|
41
|
+
static VALUE rsa_class;
|
42
|
+
|
43
|
+
VALUE wrap_exceptions(const std::function<VALUE()>& block) {
|
44
|
+
try {
|
45
|
+
return block();
|
46
|
+
} catch (const rsa_key::error& e) {
|
47
|
+
rb_raise(rsa_exception, "%s", e.what());
|
48
|
+
} catch (const std::exception& e) {
|
49
|
+
rb_raise(rb_eStandardError, "%s", e.what());
|
50
|
+
} catch (...) {
|
51
|
+
rb_raise(rsa_exception, "unknown exception");
|
52
|
+
}
|
53
|
+
return Qnil;
|
54
|
+
}
|
55
|
+
|
56
|
+
rsa_key* rsa_ptr(VALUE self) {
|
57
|
+
rsa_key *pkey;
|
58
|
+
Data_Get_Struct(self, rsa_key, pkey);
|
59
|
+
return pkey;
|
60
|
+
}
|
61
|
+
|
62
|
+
rsa_key& rsa(VALUE self) {
|
63
|
+
return *rsa_ptr(self);
|
64
|
+
}
|
65
|
+
|
66
|
+
extern "C" {
|
67
|
+
|
68
|
+
static VALUE rsa_generate(VALUE self, VALUE length) {
|
69
|
+
return wrap_exceptions([=] {
|
70
|
+
unsigned l = NUM2UINT(length);
|
71
|
+
rsa_key *pkey = rsa_ptr(self);
|
72
|
+
ruby_unblock([=] {*pkey = rsa_key::generate(l);});
|
73
|
+
return self;
|
74
|
+
});
|
75
|
+
}
|
76
|
+
|
77
|
+
static VALUE rsa_bits(VALUE self) {
|
78
|
+
return INT2NUM(rsa(self).size_in_bits());
|
79
|
+
}
|
80
|
+
|
81
|
+
static VALUE rsa_encrypt(VALUE self, VALUE rb_data) {
|
82
|
+
return wrap_exceptions([=] {
|
83
|
+
byte_buffer res;
|
84
|
+
auto data = value_to_byte_buffer(rb_data);
|
85
|
+
ruby_unblock([&] {
|
86
|
+
res = rsa(self).encrypt(data);
|
87
|
+
});
|
88
|
+
return to_rb_string(res);
|
89
|
+
});
|
90
|
+
}
|
91
|
+
|
92
|
+
static VALUE rsa_decrypt(VALUE self, VALUE rb_data) {
|
93
|
+
return wrap_exceptions([=] {
|
94
|
+
byte_buffer res;
|
95
|
+
rsa_key& key = rsa(self);
|
96
|
+
auto data = value_to_byte_buffer(rb_data);
|
97
|
+
ruby_unblock([&res,&data,&key] {
|
98
|
+
res = key.decrypt(data);
|
99
|
+
});
|
100
|
+
return to_rb_string(res);
|
101
|
+
});
|
102
|
+
}
|
103
|
+
|
104
|
+
static VALUE factorize(VALUE self, VALUE composite) {
|
105
|
+
return wrap_exceptions([=] {
|
106
|
+
string s = value_to_string(composite);
|
107
|
+
|
108
|
+
vector<big_integer> factors;
|
109
|
+
ruby_unblock([s,&factors] {
|
110
|
+
factors = pollard_rho::factorize(decode_hex(s));
|
111
|
+
});
|
112
|
+
|
113
|
+
VALUE result = rb_ary_new();
|
114
|
+
for (auto factor : factors) {
|
115
|
+
rb_ary_push(result, to_hex_value(factor));
|
116
|
+
}
|
117
|
+
return result;
|
118
|
+
});
|
119
|
+
}
|
120
|
+
|
121
|
+
typedef byte_buffer (*hash_t)(const byte_buffer &);
|
122
|
+
|
123
|
+
static hash_t hash_provider(VALUE name) {
|
124
|
+
string n = value_to_string(name);
|
125
|
+
if (n == "sha256")
|
126
|
+
return sha256;
|
127
|
+
else if (n == "sha1")
|
128
|
+
return sha1;
|
129
|
+
else
|
130
|
+
throw invalid_argument("not supported hash: " + n);
|
131
|
+
}
|
132
|
+
|
133
|
+
static VALUE rsa_sign(VALUE self, VALUE message, VALUE signature_method) {
|
134
|
+
return wrap_exceptions([=] {
|
135
|
+
byte_buffer m = value_to_byte_buffer(message);
|
136
|
+
byte_buffer res;
|
137
|
+
hash_t hash = hash_provider(signature_method);
|
138
|
+
|
139
|
+
ruby_unblock([&] {
|
140
|
+
res = rsa(self).sign(m, hash);
|
141
|
+
});
|
142
|
+
|
143
|
+
return to_value(res);
|
144
|
+
});
|
145
|
+
}
|
146
|
+
|
147
|
+
static VALUE rsa_verify(VALUE self, VALUE message, VALUE signature,
|
148
|
+
VALUE signature_method) {
|
149
|
+
return wrap_exceptions([=] {
|
150
|
+
byte_buffer m = value_to_byte_buffer(message);
|
151
|
+
byte_buffer s = value_to_byte_buffer(signature);
|
152
|
+
bool res;
|
153
|
+
hash_t hash = hash_provider(signature_method);
|
154
|
+
|
155
|
+
ruby_unblock([&] {
|
156
|
+
res = rsa(self).verify(m, s, hash);
|
157
|
+
});
|
158
|
+
|
159
|
+
return res ? Qtrue : Qfalse;
|
160
|
+
});
|
161
|
+
}
|
162
|
+
|
163
|
+
static VALUE rsa_extract_public(VALUE self) {
|
164
|
+
return wrap_exceptions([=] {
|
165
|
+
rsa_key &me = rsa(self);
|
166
|
+
VALUE res = rb_class_new_instance(0,NULL,rsa_class);
|
167
|
+
rsa_key &pub = rsa(res);
|
168
|
+
pub = me.public_key();
|
169
|
+
return res;
|
170
|
+
});
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE rsa_components(VALUE self) {
|
174
|
+
return wrap_exceptions([=] {
|
175
|
+
rsa_key& key = rsa(self);
|
176
|
+
VALUE hash = rb_hash_new();
|
177
|
+
for(auto x: key.get_params()) {
|
178
|
+
rb_hash_aset(hash,to_rb_sym(x.first),to_rb_string(x.second.to_byte_buffer()));
|
179
|
+
}
|
180
|
+
return hash;
|
181
|
+
});
|
182
|
+
}
|
183
|
+
|
184
|
+
static int do_set_param(VALUE key,VALUE data,VALUE obj) {
|
185
|
+
rsa(obj).set(value_to_string(key), value_to_byte_buffer(data));
|
186
|
+
return ST_CONTINUE;
|
187
|
+
}
|
188
|
+
|
189
|
+
static VALUE rsa_set_params(VALUE self,VALUE hash) {
|
190
|
+
return wrap_exceptions([=]{
|
191
|
+
rb_hash_foreach(hash, (int (*)(...)) do_set_param, self);
|
192
|
+
rsa(self).normalize_key();
|
193
|
+
return Qnil;
|
194
|
+
});
|
195
|
+
}
|
196
|
+
|
197
|
+
static VALUE rsa_is_private(VALUE self) {
|
198
|
+
return rsa(self).is_private() ? Qtrue : Qfalse;
|
199
|
+
}
|
200
|
+
|
201
|
+
static void rsa_free(void* ptr) {
|
202
|
+
delete (ttcrypt::rsa_key*) ptr;
|
203
|
+
}
|
204
|
+
|
205
|
+
static VALUE rsa_alloc(VALUE klass) {
|
206
|
+
return Data_Wrap_Struct(klass, 0, rsa_free, new ttcrypt::rsa_key);
|
207
|
+
}
|
208
|
+
|
209
|
+
}
|
210
|
+
|
211
|
+
void Init_ttcrypt(void) {
|
212
|
+
|
213
|
+
VALUE ttcrypt_module = rb_define_module("TTCrypt");
|
214
|
+
|
215
|
+
rb_define_method(ttcrypt_module, "_factorize", (ruby_method) factorize, 1);
|
216
|
+
|
217
|
+
rsa_class = rb_define_class_under(ttcrypt_module, "RsaKey", rb_cObject);
|
218
|
+
rb_define_alloc_func(rsa_class, rsa_alloc);
|
219
|
+
rb_define_method(rsa_class, "_generate", (ruby_method) rsa_generate, 1);
|
220
|
+
rb_define_method(rsa_class, "_bits", (ruby_method) rsa_bits, 0);
|
221
|
+
rb_define_method(rsa_class, "_encrypt", (ruby_method) rsa_encrypt, 1);
|
222
|
+
rb_define_method(rsa_class, "_decrypt", (ruby_method) rsa_decrypt, 1);
|
223
|
+
rb_define_method(rsa_class, "_sign", (ruby_method) rsa_sign, 2);
|
224
|
+
rb_define_method(rsa_class, "_verify", (ruby_method) rsa_verify, 3);
|
225
|
+
rb_define_method(rsa_class, "extract_public",
|
226
|
+
(ruby_method) rsa_extract_public, 0);
|
227
|
+
rb_define_method(rsa_class, "_is_private", (ruby_method) rsa_is_private, 0);
|
228
|
+
rb_define_method(rsa_class, "_components", (ruby_method) rsa_components, 0);
|
229
|
+
rb_define_method(rsa_class, "_set_params", (ruby_method) rsa_set_params, 1);
|
230
|
+
|
231
|
+
rsa_exception = rb_define_class_under(rsa_class, "Error",
|
232
|
+
rb_eStandardError);
|
233
|
+
}
|
234
|
+
|
data/lib/ttcrypt.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# Thrift cryptographics primitives: fast c++ implementation, only strong schemes,
|
2
|
+
# releases GVL on long operations so other threads can be executed in parallel.
|
3
|
+
module TTCrypt
|
4
|
+
# Your code goes here...
|
5
|
+
|
6
|
+
# Pollard 'rho' prime factorization. Allows execution of other ruby
|
7
|
+
# threads in parallel (releases GVL)
|
8
|
+
#
|
9
|
+
# @return [int] array of prime factors
|
10
|
+
def factorize composite
|
11
|
+
hex = composite.to_i.to_s(16)
|
12
|
+
hex = '0' + hex if (hex.length & 1) == 1
|
13
|
+
_factorize(hex).map { |x| x.to_i(16) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Implementation of RSAES-OAEP encryption and RSASSA-PSS signing
|
17
|
+
# accroding to pkcs#1 v2.2 specification. Does NOT implement any previous cryptographically
|
18
|
+
# weak shcemes (like 1.5 signature) - go use openssl for itm but it does compromise private
|
19
|
+
# key.
|
20
|
+
#
|
21
|
+
# All time consuming operations are executed releasing GVL so other threads can run in parallel
|
22
|
+
# in the multicore hardware.
|
23
|
+
#
|
24
|
+
class RsaKey
|
25
|
+
|
26
|
+
# raised when some parameters of RSAES are invalid, e.g.
|
27
|
+
# message/representation is too long, encrypted message or representation
|
28
|
+
# is not properly padded
|
29
|
+
class Error < StandardError
|
30
|
+
end
|
31
|
+
|
32
|
+
ACCEPTED_PARAMS = %i|n e p q d|
|
33
|
+
|
34
|
+
def initialize ** params
|
35
|
+
set_params(params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_params ** params
|
39
|
+
res = {}
|
40
|
+
params.each { |k, v|
|
41
|
+
ACCEPTED_PARAMS.include?(k) or raise ArgumentError, "unknown key component"
|
42
|
+
res[k.to_s] = v.to_s.force_encoding(Encoding::BINARY)
|
43
|
+
}
|
44
|
+
_set_params res
|
45
|
+
end
|
46
|
+
|
47
|
+
# Generate private key (that contains public key too) of the desired bit
|
48
|
+
# length (recommended at least 2048).
|
49
|
+
def self.generate bits_strength
|
50
|
+
k = RsaKey.new
|
51
|
+
k._generate(bits_strength)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get key size in bits
|
55
|
+
def bits
|
56
|
+
_bits
|
57
|
+
end
|
58
|
+
|
59
|
+
# Encrypt message with public key using RSAES-OAEP scheme
|
60
|
+
# (pkcs#1 v.2.2).
|
61
|
+
def encrypt message
|
62
|
+
message.force_encoding Encoding::BINARY
|
63
|
+
_encrypt message
|
64
|
+
end
|
65
|
+
|
66
|
+
# Decrypt message with private key using RSAES-OAEP scheme
|
67
|
+
# (pkcs#1 v.2.2). Requires private key
|
68
|
+
#
|
69
|
+
def decrypt message
|
70
|
+
message.force_encoding Encoding::BINARY
|
71
|
+
_decrypt message
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sign the message using pkcs#1 v2.2 RSASSA-PSS
|
75
|
+
# process. Requires private key.
|
76
|
+
#
|
77
|
+
#@param [String] message to sign
|
78
|
+
#@param [Symbol|String] hash function used (:sha1 or :sha256)
|
79
|
+
#@return [bool] true if the signature is consistent
|
80
|
+
def sign message, hash_name
|
81
|
+
message.force_encoding Encoding::BINARY
|
82
|
+
_sign message, hash_name.to_s.downcase
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check message signature signed with pkcs#1 v2.2 RSASSA-PSS
|
86
|
+
# process
|
87
|
+
#
|
88
|
+
#@param [String] message to verify
|
89
|
+
#@param [String] signature
|
90
|
+
#@param [Symbol|String] hash function used (:sha1 or :sha256)
|
91
|
+
#@return [bool] true if the signature is consistent
|
92
|
+
def verify message, signature, hash_name=:sha1
|
93
|
+
message.force_encoding Encoding::BINARY
|
94
|
+
signature.force_encoding Encoding::BINARY
|
95
|
+
_verify message, signature, hash_name.to_s.downcase
|
96
|
+
end
|
97
|
+
|
98
|
+
# Extract public key from a private (or public) key
|
99
|
+
# @return [RsaKey] public key instance
|
100
|
+
def extract_public
|
101
|
+
# native implementation: this is for indexing only
|
102
|
+
end
|
103
|
+
|
104
|
+
# true if self contains private key
|
105
|
+
def private?
|
106
|
+
_is_private
|
107
|
+
end
|
108
|
+
|
109
|
+
# Get key components as hash. Components are binary strings, indexes are symbols
|
110
|
+
# e.g. :n, :e
|
111
|
+
def components
|
112
|
+
@components ||= _components
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [String] P component or nil
|
116
|
+
def p
|
117
|
+
components[:p]
|
118
|
+
end
|
119
|
+
|
120
|
+
def q
|
121
|
+
components[:q]
|
122
|
+
end
|
123
|
+
|
124
|
+
def n
|
125
|
+
components[:n]
|
126
|
+
end
|
127
|
+
|
128
|
+
def e
|
129
|
+
components[:e]
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# it should require native lib after module definition above
|
136
|
+
# otherwise won't work!
|
137
|
+
require 'ttcrypt/ttcrypt'
|
138
|
+
|
139
|
+
module TTCrypt
|
140
|
+
module_function :factorize, :_factorize
|
141
|
+
end
|
142
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
end
|