#include #include #include "hmac.hh" #include "security_ecc.hh" #include "loggers.hh" security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(), _pub_key_x(), _pub_key_y(), _eph_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() { loggers::get_instance().log(">>> security_ecc::security_ecc: %d", static_cast(p_elliptic_curve)); const int result = init(); if (result == -1) { loggers::get_instance().error("security_ecc::security_ecc: Unsupported elliptic_curve %d", _elliptic_curve); } } // End of constructor security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve, const std::vector& p_private_key): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(p_private_key), _pub_key_x(), _pub_key_y(), _eph_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() { loggers::get_instance().log(">>> security_ecc::security_ecc (1): %d", static_cast(p_elliptic_curve)); // Sanity checks if ((_elliptic_curve == ec_elliptic_curves::nist_p_256) || (_elliptic_curve == ec_elliptic_curves::brainpool_p_256_r1)) { if (p_private_key.size() != 32) { loggers::get_instance().error("security_ecc::security_ecc: Invalid public keys size"); } } else if (_elliptic_curve == ec_elliptic_curves::brainpool_p_384_r1) { if ((p_private_key.size() != 48)) { loggers::get_instance().error("security_ecc::security_ecc: Invalid public keys size"); } } int result = init(); if (result == -1) { loggers::get_instance().error("security_ecc::security_ecc: Unsupported elliptic_curve %d", _elliptic_curve); } ::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED); // Build private key BIGNUM p; ::BN_init(&p); ::BN_bin2bn(_pri_key.data(), _pri_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("security_ecc::security_ecc (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 v(BN_num_bytes(&xy)); ::BN_bn2bin(&xy, v.data()); const int l = v.size() / 2; _pub_key_x.resize(l); std::copy(v.cbegin(), v.cbegin() + l - 1, _pub_key_x.begin()); _pub_key_y.resize(l); std::copy(v.cbegin() + l, v.cend(), _pub_key_y.begin()); ::EC_POINT_free(ec_point); } // End of constructor security_ecc::security_ecc(const ec_elliptic_curves p_elliptic_curve, const std::vector& p_public_key_x, const std::vector& p_public_key_y): _elliptic_curve(p_elliptic_curve), _encryption_algotithm(encryption_algotithm::aes_128_ccm), _ec_key(nullptr), _ec_group(nullptr), _bn_ctx(nullptr), _pri_key(), _pub_key_x(p_public_key_x), _pub_key_y(p_public_key_y), _eph_key(), _enc_key_x(), _enc_key_y(), _sym_key(), _nonce(), _tag() { loggers::get_instance().log(">>> security_ecc::security_ecc (2): %d", static_cast(p_elliptic_curve)); // Sanity checks if ((_elliptic_curve == ec_elliptic_curves::nist_p_256) || (_elliptic_curve == ec_elliptic_curves::brainpool_p_256_r1)) { if ((p_public_key_x.size() != 32) || (p_public_key_y.size() != 32)) { loggers::get_instance().error("security_ecc::security_ecc: Invalid public keys size"); } } else if (_elliptic_curve == ec_elliptic_curves::brainpool_p_384_r1) { if ((p_public_key_x.size() != 48) || (p_public_key_y.size() != 48)) { loggers::get_instance().error("security_ecc::security_ecc: Invalid public keys size"); } } int result = init(); if (result == -1) { loggers::get_instance().error("security_ecc::security_ecc: Unsupported elliptic_curve %d", _elliptic_curve); } ::EC_KEY_set_conv_form(_ec_key, POINT_CONVERSION_COMPRESSED); // Set public key BIGNUM x; ::BN_init(&x); ::BN_bin2bn(_pub_key_x.data(), _pub_key_x.size(), &x); BIGNUM y; ::BN_init(&y); ::BN_bin2bn(_pub_key_y.data(), _pub_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; default: // Use Binary 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("security_ecc::security_ecc (1): Failed to get coordinates"); } ::EC_KEY_set_public_key(_ec_key, ec_point); ::EC_POINT_free(ec_point); } // End of constructor security_ecc::~security_ecc() { loggers::get_instance().log(">>> security_ecc::~security_ecc"); if(_ec_key != nullptr) { ::EC_KEY_free(_ec_key); } if (_bn_ctx != nullptr) { ::BN_CTX_free(_bn_ctx); } loggers::get_instance().log("<<< security_ecc::~security_ecc"); } // End of Destructor int security_ecc::generate() { loggers::get_instance().log(">>> security_ecc::generate"); // Sanity check if (!::EC_KEY_generate_key(_ec_key)) { // Generate the private and public keys loggers::get_instance().error("security_ecc::generate: Failed to generate private/public keys"); return -1; } BIGNUM x, y, compressed_y; ::BN_init(&x); ::BN_init(&y); ::BN_init(&compressed_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; default: // Use binary 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("security_ecc::generate: Failed to get coordinates"); return -1; } const BIGNUM* p = ::EC_KEY_get0_private_key(_ec_key); _pri_key.resize(BN_num_bytes(p)); ::BN_bn2bin(p, _pri_key.data()); _pub_key_x.resize(BN_num_bytes(&x)); ::BN_bn2bin(&x, _pub_key_x.data()); _pub_key_y.resize(BN_num_bytes(&y)); ::BN_bn2bin(&y, _pub_key_y.data()); // Compressed int len = ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, NULL, 0, _bn_ctx); std::vector cy; cy.resize(len); ::EC_POINT_point2oct(_ec_group, ec_point, POINT_CONVERSION_COMPRESSED, (unsigned char *)cy.data(), len, _bn_ctx); // TODO Create a compressed _pub_key_compressed_y //_pub_key_compressed_y.resize(BN_num_bytes(&compressed_y)); //::BN_bn2bin(&compressed_y, _pub_key_compressed_y.data()); return 0; } //int security_ecc::generate_and_derive_ephemeral_key(const std::vector& p_public_key_x, const std::vector& p_public_key_y) { // loggers::get_instance().log(">>> security_ecc::generate_and_derive_ephemeral_key (1)"); // // // Sanity checks // if ((_pub_key_x.size() != 0) || (_pub_key_y.size() != 0)) { // loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key: Constrictor format #1 shall be used"); // return -1; // } // ::EC_KEY_generate_key(_ec_key); // // // Set buffers size // int len = (EC_GROUP_get_degree(_ec_group) + 7) / 8; // _eph_key.resize(len); // // // Convert the public keys (X,Y) into EC_POINT data structure // EC_POINT *ec_point = nullptr; // bin_to_ec_point(p_public_key_x, p_public_key_y, &ec_point); // // Generate the shared secret key // int result = ::ECDH_compute_key(_eph_key.data(), _eph_key.size(), ec_point, _ec_key, NULL); // if (result == -1) { // ::EC_POINT_free(ec_point); // return -1; // } // ::EC_POINT_free(ec_point); // // Write the ephemeral key's public key to the output buffer // std::vector enc_key; // public_key_to_bin(enc_key); // // Extract X-coordinate and Y-coordinate // _enc_key_x.assign(1 + enc_key.cbegin(), 1 + len + enc_key.cbegin()); // _enc_key_y.assign(1 + len + enc_key.cbegin(), enc_key.cend()); // // return 0; //} // int security_ecc::generate_and_derive_ephemeral_key(const std::vector& p_peer_public_enc_key_x, const std::vector& p_peer_public_enc_key_y) { loggers::get_instance().log(">>> security_ecc::generate_and_derive_ephemeral_key (2)"); // Sanity checks if (_pri_key.size() == 0) { loggers::get_instance().warning("security_ecc::generate_and_derive_ephemeral_key: Constructor format #2 shall be used"); return -1; } // Set buffers size int len = (EC_GROUP_get_degree(_ec_group) + 7) / 8; _eph_key.resize(len); // Convert the peer public encryption key to an EC point EC_POINT *ec_point = nullptr; bin_to_ec_point(p_peer_public_enc_key_x, p_peer_public_enc_key_y, &ec_point); // Generate the shared secret key int result = ::ECDH_compute_key(_eph_key.data(), _eph_key.size(), ec_point, _ec_key, NULL); if (result == -1) { ::EC_POINT_free(ec_point); return -1; } ::EC_POINT_free(ec_point); return 0; } int security_ecc::encrypt(const encryption_algotithm p_enc_algorithm, const std::vector& p_message, std::vector& p_enc_message) { loggers::get_instance().log(">>> security_ecc::encrypt: %d", p_enc_algorithm); // Sanity checks if ((_pub_key_x.size() != 0) || (_pub_key_y.size() != 0)) { loggers::get_instance().warning("security_ecc::encrypt: Constructor format #1 shall be used"); return -1; } _encryption_algotithm = p_enc_algorithm; // Initialize the context and encryption operation EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new(); switch (_encryption_algotithm) { case encryption_algotithm::aes_128_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL); // Allocate buffers size _nonce.resize(12); _tag.resize(16); _sym_key.resize(16); p_enc_message.resize(p_message.size()); break; case encryption_algotithm::aes_256_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_128_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); break; } // End of 'switch' statement // Generate _sym_key ::RAND_pseudo_bytes(_sym_key.data(), _sym_key.size()); loggers::get_instance().log_to_hexa("security_ecc::encrypt: _sym_key: ", _sym_key.data(), _sym_key.size()); // Generate _nonce ::RAND_pseudo_bytes(_nonce.data(), _nonce.size()); loggers::get_instance().log_to_hexa("security_ecc::encrypt: nonce: ", _nonce.data(), _nonce.size()); // Set nonce length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.size(), NULL); // Set tag length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.size(), NULL); // Prime the key and nonce ::EVP_EncryptInit_ex(ctx, NULL, NULL, _sym_key.data(), _nonce.data()); // No authentication data // Encrypt the data int len = 0; ::EVP_EncryptUpdate(ctx, p_enc_message.data(), &len, p_message.data(), p_message.size()); // Finalize the encryption session ::EVP_EncryptFinal_ex(ctx, p_enc_message.data() + len, &len); // Get the authentication tag ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, _tag.size(), _tag.data()); loggers::get_instance().log_to_hexa("security_ecc::encrypt: tag: ", _tag.data(), _tag.size()); ::EVP_CIPHER_CTX_free(ctx); return 0; } int security_ecc::encrypt(const encryption_algotithm p_enc_algorithm, const std::vector& p_symmetric_key, const std::vector& p_nonce, const std::vector& p_message, std::vector& p_enc_message) { loggers::get_instance().log(">>> security_ecc::encrypt (2): %d", p_enc_algorithm); // Sanity checks if ((_pub_key_x.size() != 0) || (_pub_key_y.size() != 0)) { loggers::get_instance().warning("security_ecc::encrypt: Constructor format #1 shall be used"); return -1; } _encryption_algotithm = p_enc_algorithm; _sym_key = p_symmetric_key; _nonce = p_nonce; // Initialize the context and encryption operation EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new(); switch (_encryption_algotithm) { case encryption_algotithm::aes_128_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL); // Allocate buffers size _tag.resize(16); p_enc_message.resize(p_message.size()); break; case encryption_algotithm::aes_256_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_128_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); break; } // End of 'switch' statement loggers::get_instance().log_to_hexa("security_ecc::encrypt: _sym_key: ", _sym_key.data(), _sym_key.size()); loggers::get_instance().log_to_hexa("security_ecc::encrypt: nonce: ", _nonce.data(), _nonce.size()); // Set nonce length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.size(), NULL); // Set tag length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.size(), NULL); // Prime the key and nonce ::EVP_EncryptInit_ex(ctx, NULL, NULL, _sym_key.data(), _nonce.data()); // No authentication data // Encrypt the data int len = 0; ::EVP_EncryptUpdate(ctx, p_enc_message.data(), &len, p_message.data(), p_message.size()); // Finalize the encryption session ::EVP_EncryptFinal_ex(ctx, p_enc_message.data() + len, &len); // Get the authentication tag ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, _tag.size(), _tag.data()); loggers::get_instance().log_to_hexa("security_ecc::encrypt: tag: ", _tag.data(), _tag.size()); ::EVP_CIPHER_CTX_free(ctx); return 0; } int security_ecc::decrypt(const encryption_algotithm p_enc_algorithm, const std::vector& p_key, const std::vector& p_nonce, const std::vector& p_tag, const std::vector& p_enc_message, std::vector& p_message) { loggers::get_instance().log(">>> security_ecc::decrypt"); // Sanity checks if ((_pri_key.size() == 0) || (_sym_key.size() == 0)) { loggers::get_instance().warning("security_ecc::decrypt: Constrictor format #2 shall be used"); return -1; } _encryption_algotithm = p_enc_algorithm; _sym_key = p_key; _nonce = p_nonce; _tag = p_tag; // Initialize the context and decryption operation EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new(); switch (_encryption_algotithm) { case encryption_algotithm::aes_128_ccm: ::EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_ccm: ::EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_128_gcm: ::EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_gcm: ::EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); break; } // End of 'switch' statement // Set nonce length EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.size(), NULL); // Set expected tag value EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.size(), _tag.data()); // Specify key and IV EVP_DecryptInit_ex(ctx, NULL, NULL, _sym_key.data(), _nonce.data()); // Decrypt plaintext, verify tag: can only be called once p_message.resize(p_enc_message.size()); int len = 0; int result = EVP_DecryptUpdate(ctx, p_message.data(), &len, p_enc_message.data(), p_enc_message.size()); ::EVP_CIPHER_CTX_free(ctx); return (result > 0) ? 0 : -1; } /*int security_ecc::encrypt(const std::vector& p_message, std::vector& p_enc_message) { loggers::get_instance().log(">>> security_ecc::encrypt"); // Sanity checks if ((_pub_key_x.size() != 0) || (_pub_key_y.size() != 0)) { loggers::get_instance().error("security_ecc::encrypt: Constructor format #1 shall be used"); return -1; } // Initialize the context and encryption operation EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new(); switch (_encryption_algotithm) { case encryption_algotithm::aes_128_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL); // Allocate buffers size _nonce.resize(12); _tag.resize(16); p_enc_message.resize(p_message.size()); break; case encryption_algotithm::aes_256_ccm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_128_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_gcm: ::EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); break; } // End of 'switch' statement // Generate _nonce ::RAND_pseudo_bytes(_nonce.data(), _nonce.size()); // Set nonce length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.size(), NULL); // Set tag length ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.size(), NULL); // Prime the key and nonce ::EVP_EncryptInit_ex(ctx, NULL, NULL, _eph_key.data(), _nonce.data()); // No authentication data // Encrypt the data int len = 0; ::EVP_EncryptUpdate(ctx, p_enc_message.data(), &len, p_message.data(), p_message.size()); // Finalize the encryption session ::EVP_EncryptFinal_ex(ctx, p_enc_message.data() + len, &len); // Get the authentication tag ::EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, _tag.size(), _tag.data()); ::EVP_CIPHER_CTX_free(ctx); return 0; }*/ int security_ecc::decrypt(const std::vector& p_nonce, const std::vector& p_tag, const std::vector& p_enc_message, std::vector& p_message) { loggers::get_instance().log(">>> security_ecc::decrypt"); // Sanity checks if ((_pri_key.size() == 0) || (_eph_key.size() == 0)) { loggers::get_instance().warning("security_ecc::decrypt: Constrictor format #2 shall be used"); return -1; } _nonce = p_nonce; _tag = p_tag; // Initialize the context and decryption operation EVP_CIPHER_CTX *ctx = ::EVP_CIPHER_CTX_new(); switch (_encryption_algotithm) { case encryption_algotithm::aes_128_ccm: ::EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_ccm: ::EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_128_gcm: ::EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); break; case encryption_algotithm::aes_256_gcm: ::EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); break; } // End of 'switch' statement // Set nonce length EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, _nonce.size(), NULL); // Set expected tag value EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, _tag.size(), _tag.data()); // Specify key and IV EVP_DecryptInit_ex(ctx, NULL, NULL, _eph_key.data(), _nonce.data()); // Decrypt plaintext, verify tag: can only be called once p_message.resize(p_enc_message.size()); int len = 0; int result = EVP_DecryptUpdate(ctx, p_message.data(), &len, p_enc_message.data(), p_enc_message.size()); ::EVP_CIPHER_CTX_free(ctx); return (result > 0) ? 0 : -1; } int security_ecc::sign(const std::vector& p_data, std::vector& p_r_sig, std::vector& p_s_sig) { loggers::get_instance().log(">>> security_ecc::sign"); // Sanity checks if(_pri_key.size() == 0) { // No private key return -1; } if (p_data.size() == 0) { return -1; } ECDSA_SIG *signature = ::ECDSA_do_sign(p_data.data(), p_data.size(), _ec_key); if (signature == nullptr) { loggers::get_instance().warning("security_ecc::sign: Signature failed"); return -1; } loggers::get_instance().log("security_ecc::sign: succeed"); if (::ECDSA_do_verify(p_data.data(), p_data.size(), signature, _ec_key) != 1) { loggers::get_instance().warning("security_ecc::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("security_ecc::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("security_ecc::sign: s=", p_s_sig.data(), p_s_sig.size()); ::ECDSA_SIG_free(signature); return 0; } int security_ecc::sign_verif(const std::vector& p_data, const std::vector& p_signature) { loggers::get_instance().log(">>> security_ecc::sign_verif"); // Sanity checks if (p_data.size() == 0) { return false; } // 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; // Check the signature int result = ::ECDSA_do_verify(p_data.data(), p_data.size(), signature, _ec_key); ::ECDSA_SIG_free(signature); loggers::get_instance().log("security_ecc::sign_verif: %s", (result == 1) ? "succeed": "failed"); return result != 1; } const int security_ecc::init() { loggers::get_instance().log(">>> security_ecc::init: %d", static_cast(_elliptic_curve)); ::OpenSSL_add_all_algorithms(); ::ERR_load_crypto_strings(); int result = -1; 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"); break; case ec_elliptic_curves::brainpool_p_256_r1: result = ::OBJ_txt2nid("brainpoolP256r1"); break; case ec_elliptic_curves::brainpool_p_384_r1: result = ::OBJ_txt2nid("brainpoolP384r1"); break; default: loggers::get_instance().error("security_ecc::security_ecc: Unsupported EC elliptic_curve"); } // End of 'switch' statement if (result < 0) { loggers::get_instance().warning("security_ecc::security_ecc: Unaible to set EC elliptic_curve"); return -1; } _ec_key = ::EC_KEY_new_by_curve_name(result); // Set the elliptic curve ::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 int security_ecc::bin_to_ec_point(const std::vector& p_public_key_x, const std::vector& p_public_key_y, EC_POINT** p_ec_point) { // ec_key_public_key_bin_to_point BIGNUM* pubk_bn; std::vector v(1, 0x04); v.insert(v.end(), std::make_move_iterator(p_public_key_x.begin()), std::make_move_iterator(p_public_key_x.end())); v.insert(v.end(), std::make_move_iterator(p_public_key_y.begin()), std::make_move_iterator(p_public_key_y.end())); pubk_bn = ::BN_bin2bn(v.data(), v.size(), NULL); *p_ec_point = ::EC_POINT_new(_ec_group); ::EC_POINT_bn2point(_ec_group, pubk_bn, *p_ec_point, _bn_ctx); // BIO *bio_out = NULL; /* stdout */ // bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); // BIGNUM *x = BN_new(); // BIGNUM *y = BN_new(); // if (EC_POINT_get_affine_coordinates_GFp(_ec_group, *p_ec_point, x, y, NULL)) { // BN_print_fp(stdout, x); // putc('\n', stdout); // BN_print_fp(stdout, y); // putc('\n', stdout); // } // BN_free(x); BN_free(y); return 0; } int security_ecc::public_key_to_bin(std::vector& p_bin_key) { // ec_key_public_key_to_bin const EC_GROUP *ec_group = EC_KEY_get0_group(_ec_key); const EC_POINT *pub = EC_KEY_get0_public_key(_ec_key); BIGNUM *pub_bn = BN_new(); ::EC_POINT_point2bn(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED, pub_bn, _bn_ctx); p_bin_key.resize(BN_num_bytes(pub_bn)); ::BN_bn2bin(pub_bn, p_bin_key.data()); ::BN_clear_free(pub_bn); return 0; }