ECDH算法封装,基于openssl。
#pragma once #include <string> #include <openssl/ec.h> #include <openssl/ecdh.h> #include <openssl/evp.h> class ECDHEncoder { private: EC_KEY* m_ecKey{ nullptr }; EC_KEY* m_ecPeerPubKey{ nullptr }; public: ECDHEncoder() {}; ~ECDHEncoder() { if (m_ecKey) EC_KEY_free(m_ecKey); if (m_ecPeerPubKey) EC_KEY_free(m_ecPeerPubKey); }; bool GenerateKey(int nid) { m_ecKey = EC_KEY_new_by_curve_name(nid); if (m_ecKey == nullptr) return false; if (1 != EC_KEY_generate_key(m_ecKey)) { EC_KEY_free(m_ecKey); m_ecKey = nullptr; return false; } return true; } std::string GetMyEncodedPoint(point_conversion_form_t type = POINT_CONVERSION_UNCOMPRESSED) { const EC_GROUP* group = EC_KEY_get0_group(m_ecKey); const EC_POINT* pubKey = EC_KEY_get0_public_key(m_ecKey); size_t field_len = EC_GROUP_get_degree(group); size_t byte_len = (field_len + 7) / 8; unsigned char* point_data = (unsigned char*)malloc(byte_len * 2 + 1); if (!point_data) return {}; size_t point_data_len = EC_POINT_point2oct(group, pubKey, type, point_data, byte_len * 2 + 1, nullptr); if (0 == point_data_len) { free(point_data); return {}; } std::string strPointData((char*)point_data, point_data_len); free(point_data); return strPointData; } std::string GetMyPublicKey() { BIO* out = BIO_new(BIO_s_mem()); i2d_EC_PUBKEY_bio(out, m_ecKey); char* p; long length = BIO_get_mem_data(out, &p); std::string strECPubKey(p, length); BIO_free_all(out); return strECPubKey; } bool SetPeerPublicKey(const std::string& strPeerPublicKey) { if (m_ecPeerPubKey) { EC_KEY_free(m_ecPeerPubKey); m_ecPeerPubKey = nullptr; } const unsigned char* szBuf = (unsigned char*)strPeerPublicKey.c_str(); m_ecPeerPubKey = d2i_EC_PUBKEY(nullptr, &szBuf, (long)strPeerPublicKey.size()); if (m_ecPeerPubKey == nullptr) return false; return true; } bool SetPeerEncodedPoint(const std::string& strPointData) { if (m_ecPeerPubKey) { EC_KEY_free(m_ecPeerPubKey); m_ecPeerPubKey = nullptr; } const EC_GROUP* group = EC_KEY_get0_group(m_ecKey); EC_POINT* peerPubKey = EC_POINT_new(group); if (peerPubKey == nullptr) return false; const unsigned char* p = (const unsigned char*)strPointData.c_str(); if (0 == EC_POINT_oct2point(group, peerPubKey, p, strPointData.size(), nullptr)) { EC_POINT_free(peerPubKey); return false; } m_ecPeerPubKey = EC_KEY_new_by_curve_name(EC_GROUP_get_curve_name(group)); if (m_ecPeerPubKey == nullptr) { EC_POINT_free(peerPubKey); return false; } if (1 != EC_KEY_set_public_key(m_ecPeerPubKey, peerPubKey)) { EC_POINT_free(peerPubKey); EC_KEY_free(m_ecPeerPubKey); m_ecPeerPubKey = nullptr; return false; } EC_POINT_free(peerPubKey); return true; } std::string ComputeSecretKey() { if (m_ecPeerPubKey == nullptr) return {}; int field_size = EC_GROUP_get_degree(EC_KEY_get0_group(m_ecKey)); size_t secret_len = (field_size + 7) / 8; unsigned char* secret = new unsigned char[secret_len]; if (secret == nullptr) return {}; secret_len = ECDH_compute_key(secret, secret_len, EC_KEY_get0_public_key(m_ecPeerPubKey), m_ecKey, nullptr); if (secret_len == 0) { delete[] secret; return {}; } std::string strSecretKey((const char*)secret, secret_len); delete[] secret; return strSecretKey; } };