Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <openssl/ecdsa.h>
#include "ec_keys.hh"
#include "loggers.hh" // To be remove to build a security shared library
ec_keys::ec_keys(const ec_elliptic_curves p_elliptic_curve): _elliptic_curve(p_elliptic_curve), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pr_key(), _pu_key_x(), _pu_key_y() {
loggers::get_instance().log(">>> ec_keys::ec_keys: %d", static_cast<int>(p_elliptic_curve));
::ERR_load_crypto_strings();
int result;
switch (p_elliptic_curve) {
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve
result = ::OBJ_txt2nid("prime256v1");
if (result < 0) {
loggers::get_instance().error("ec_keys::ec_keys: Unsupported EC prime256v1 elliptic_curve");
}
_ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
break;
default:
loggers::get_instance().error("ec_keys::ec_keys: Unsupported EC elliptic_curve");
} // End of 'switch' statement
::EC_KEY_set_asn1_flag(_ec_key, OPENSSL_EC_NAMED_CURVE); // Used to save and retrieve keys
_ec_group = ::EC_KEY_get0_group(_ec_key); // Get pointer to the EC_GROUP
_bn_ctx = ::BN_CTX_new();
} // End of constructor
ec_keys::ec_keys(const ec_elliptic_curves p_elliptic_curve, const std::vector<unsigned char>& p_private_key): _elliptic_curve(p_elliptic_curve), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pr_key(p_private_key), _pu_key_x(), _pu_key_y() {
loggers::get_instance().log(">>> ec_keys::ec_keys (1): %d", static_cast<int>(p_elliptic_curve));
::ERR_load_crypto_strings();
int result;
switch (p_elliptic_curve) {
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve
result = ::OBJ_txt2nid("prime256v1");
if (result < 0) {
loggers::get_instance().error("ec_keys::ec_keys (1): Unsupported EC prime256v1 elliptic_curve");
}
_ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
break;
default:
loggers::get_instance().error("ec_keys::ec_keys (1): Unsupported EC elliptic_curve");
} // End of 'switch' statement
::EC_KEY_set_asn1_flag(_ec_key, OPENSSL_EC_NAMED_CURVE); // Used to save and retrieve keys
::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED);
_ec_group = ::EC_KEY_get0_group(_ec_key); // Get pointer to the EC_GROUP
_bn_ctx = ::BN_CTX_new();
// TODO Sanity checks on key size
// Build private key
BIGNUM p;
::BN_init(&p);
::BN_bin2bn(_pr_key.data(), _pr_key.size(), &p);
// Build public keys
EC_POINT* ec_point = ::EC_POINT_new(_ec_group);
::EC_POINT_mul(_ec_group, ec_point, &p, NULL, NULL, _bn_ctx);
// Set private key
::EC_KEY_set_private_key(_ec_key, &p);
if (::EC_KEY_check_key(_ec_key) != 0) {
loggers::get_instance().error("ec_keys::ec_keys (1): Invalid private key");
}
// Private key is correct, set public keys
::EC_KEY_set_public_key(_ec_key, ec_point);
BIGNUM xy;
::BN_init(&xy);
::EC_POINT_point2bn(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, &xy, _bn_ctx);
std::vector<unsigned char> v(BN_num_bytes(&xy));
BN_bn2bin(&xy, v.data());
const int l = v.size() / 2;
_pu_key_x.resize(l);
std::copy(v.cbegin(), v.cbegin() + l - 1, _pu_key_x.begin());
_pu_key_y.resize(l);
std::copy(v.cbegin() + l, v.cend(), _pu_key_y.begin());
::EC_POINT_free(ec_point);
} // End of constructor
ec_keys::ec_keys(const ec_elliptic_curves p_elliptic_curve, const std::vector<unsigned char>& p_public_key_x, const std::vector<unsigned char>& p_public_key_y): _elliptic_curve(p_elliptic_curve), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pr_key(), _pu_key_x(p_public_key_x), _pu_key_y(p_public_key_y) {
loggers::get_instance().log(">>> ec_keys::ec_keys (2): %d", static_cast<int>(p_elliptic_curve));
::ERR_load_crypto_strings();
int result;
switch (p_elliptic_curve) {
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve
result = ::OBJ_txt2nid("prime256v1");
if (result < 0) {
loggers::get_instance().error("ec_keys::ec_keys (2): Unsupported EC prime256v1 elliptic_curve");
}
_ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
break;
default:
loggers::get_instance().error("ec_keys::ec_keys (2): Unsupported EC elliptic_curve");
} // End of 'switch' statement
::EC_KEY_set_asn1_flag(_ec_key, OPENSSL_EC_NAMED_CURVE); // Used to save and retrieve keys
::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED);
_ec_group = ::EC_KEY_get0_group(_ec_key); // Get pointer to the EC_GROUP
_bn_ctx = ::BN_CTX_new();
// TODO Sanity checks on key size
// Set public key
BIGNUM x;
::BN_init(&x);
::BN_bin2bn(_pu_key_x.data(), _pu_key_x.size(), &x);
BIGNUM y;
::BN_init(&y);
::BN_bin2bn(_pu_key_y.data(), _pu_key_y.size(), &y);
EC_POINT* ec_point = ::EC_POINT_new(_ec_group);
result = 0;
switch (_elliptic_curve) {
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve: Use primary
result = ::EC_POINT_set_affine_coordinates_GFp(_ec_group, ec_point, &x, &y, _bn_ctx); // Use primary elliptic curve
break;
default:
result = ::EC_POINT_set_affine_coordinates_GF2m(_ec_group, ec_point, &x, &y, _bn_ctx);
} // End of 'switch' statement
if (result == 0) {
loggers::get_instance().error("ec_keys::ec_keys (1): Failed to get coordinates");
}
::EC_KEY_set_public_key(_ec_key, ec_point);
::EC_POINT_free(ec_point);
} // End of constructor
ec_keys::~ec_keys() {
loggers::get_instance().log(">>> ec_keys::~ec_keys");
if(_ec_key != nullptr) {
::EC_KEY_free(_ec_key);
}
BN_CTX_free(_bn_ctx);
}
int ec_keys::generate() {
loggers::get_instance().log(">>> ec_keys::generate");
// Sanity check
if (!::EC_KEY_generate_key(_ec_key)) { // Generate the private and public key
loggers::get_instance().error("ec_keys::generate: Wrong parameters");
return -1;
}
BIGNUM x, y;
::BN_init(&x);
::BN_init(&y);
const EC_POINT* ec_point = EC_KEY_get0_public_key(_ec_key);
int result = 0;
switch (_elliptic_curve) {
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve: Use primary
result = ::EC_POINT_get_affine_coordinates_GFp(_ec_group, ec_point, &x, &y, _bn_ctx); // Use primer on elliptic curve
break;
default:
result = ::EC_POINT_get_affine_coordinates_GF2m(_ec_group, ec_point, &x, &y, _bn_ctx);
} // End of 'switch' statement
if (result == 0) {
loggers::get_instance().error("ec_keys::generate: Failed to get coordinates");
}
const BIGNUM* p = ::EC_KEY_get0_private_key(_ec_key);
_pr_key.resize(BN_num_bytes(p));
::BN_bn2bin(p, _pr_key.data());
_pu_key_x.resize(BN_num_bytes(&x));
::BN_bn2bin(&x, _pu_key_x.data());
_pu_key_y.resize(BN_num_bytes(&y));
::BN_bn2bin(&y, _pu_key_y.data());
// TODO Compressed
// int len = ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, NULL, 0, _bn_ctx);
// std::vector<unsigned char> cy;
// cy.resize(len);
// ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, (unsigned char *)cy.data(), len, _bn_ctx);
return 0;
}
int ec_keys::sign(const std::vector<unsigned char>& p_data, std::vector<unsigned char>& p_r_sig, std::vector<unsigned char>& p_s_sig) {
loggers::get_instance().log(">>> ec_keys::sign");
// Sanity checks
if(_pr_key.size() == 0) { // No private key
return -1;
}
// TODO Check data length
ECDSA_SIG *signature = ::ECDSA_do_sign(p_data.data(), p_data.size(), _ec_key);
if (signature == nullptr) {
loggers::get_instance().warning("ec_keys::sign: Signature failed");
return -1;
}
loggers::get_instance().log("ec_keys::sign: succeed");
if (::ECDSA_do_verify(p_data.data(), p_data.size(), signature, _ec_key) != 1) {
loggers::get_instance().warning("ec_keys::sign: Signature not verified");
return -1;
}
p_r_sig.resize(BN_num_bytes(signature->r));
::BN_bn2bin(signature->r, p_r_sig.data());
loggers::get_instance().log_to_hexa("ec_keys::sign: r=", p_r_sig.data(), p_r_sig.size());
p_s_sig.resize(BN_num_bytes(signature->r));
::BN_bn2bin(signature->s, p_s_sig.data());
loggers::get_instance().log_to_hexa("ec_keys::sign: s=", p_s_sig.data(), p_s_sig.size());
::ECDSA_SIG_free(signature);
return 0;
}
int ec_keys::sign_verif(const std::vector<unsigned char>& p_data, const std::vector<unsigned char>& p_signature, const std::vector<unsigned char>& p_ublic_key_x, const std::vector<unsigned char>& p_ublic_key_y) {
loggers::get_instance().log(">>> ec_keys::sign_verif");
// Sanity checks
// TODO Check data length
// Build the EC_POINT
// Build the signature
BIGNUM r, s;
::BN_init(&r);
::BN_init(&s);
::BN_bin2bn(p_signature.data(), p_signature.size() / 2, &r);
::BN_bin2bn(p_signature.data() + p_signature.size() / 2, p_signature.size() / 2, &s);
ECDSA_SIG *signature = ECDSA_SIG_new();
signature->r = &r;
signature->s = &s;
int result = ::ECDSA_do_verify(p_data.data(), p_data.size(), signature, _ec_key);
::ECDSA_SIG_free(signature);
loggers::get_instance().log("ec_keys::sign_verif: %s", (result == 1) ? "succeed": "failed");
return result != 1;
}