Newer
Older
#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();
const int result = init();
if (result == -1) {
loggers::get_instance().error("ec_keys::ec_keys: Unsupported elliptic_curve %d", _elliptic_curve);
}
} // 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));
int result = init();
if (result == -1) {
loggers::get_instance().error("ec_keys::ec_keys: Unsupported elliptic_curve %d", _elliptic_curve);
}
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
::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED);
// 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));
int result = init();
if (result == -1) {
loggers::get_instance().error("ec_keys::ec_keys: Unsupported elliptic_curve %d", _elliptic_curve);
}
::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED);
// 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 primary
// No break;
case ec_elliptic_curves::brainpool_p_256_r1:
// No break;
case ec_elliptic_curves::brainpool_p_384_r1:
result = ::EC_POINT_set_affine_coordinates_GFp(_ec_group, ec_point, &x, &y, _bn_ctx); // Use primary elliptic curve
break;
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");
_pr_key.clear();
_pu_key_x.clear();
_pu_key_y.clear();
if(_ec_key != nullptr) {
::EC_KEY_free(_ec_key);
}
if (_bn_ctx != nullptr) {
BN_CTX_free(_bn_ctx);
}
loggers::get_instance().log("<<< ec_keys::~ec_keys");
} // End of Destructor
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 primary
// No break;
case ec_elliptic_curves::brainpool_p_256_r1:
// No break;
case ec_elliptic_curves::brainpool_p_384_r1:
result = ::EC_POINT_get_affine_coordinates_GFp(_ec_group, ec_point, &x, &y, _bn_ctx); // Use primer on elliptic curve
break;
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
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) {
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;
}
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
const int ec_keys::init() {
loggers::get_instance().log(">>> ec_keys::init: %d", static_cast<int>(_elliptic_curve));
::ERR_load_crypto_strings();
int result;
switch (_elliptic_curve) { // TODO Group this cde into a private method
case ec_elliptic_curves::nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve
result = ::OBJ_txt2nid("prime256v1");
if (result < 0) {
return -1;
}
_ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
break;
case ec_elliptic_curves::brainpool_p_256_r1:
result = ::OBJ_txt2nid("brainpoolP256r1");
if (result < 0) {
return -1;
}
_ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve
break;
case ec_elliptic_curves::brainpool_p_384_r1:
result = ::OBJ_txt2nid("brainpoolP384r1");
if (result < 0) {
return -1;
}
_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();
return 0;
} // End of init