* limitations under the License
*/
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include "crypto/common.h"
#include "crypto/ec_key.h"
#include "crypto/openssl_error.h"
+#include "log/log.h"
#include <cstring>
#include <openssl/ec.h>
+#include <openssl/evp.h>
#include <openssl/obj_mac.h> // for NID_X9_62_prime256v1
namespace Crypto {
-CryptoBuffer GenerateCompressedX9_62_P_256_Key()
+X9_62_P_256_Key X9_62_P_256_Key::Create()
{
- EC_KEY *key = nullptr;
- CryptoBuffer res(33);
- size_t buffLen;
- unsigned char *buff = nullptr;
+ EVP_PKEY_CTX *ctx = nullptr;
+ EVP_PKEY *pkey = nullptr;
+
+ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
+ if (!ctx) {
+ TRY_LOG_ERROR("EVP_PKEY_CTX_new_id() error");
+ goto opensslError;
+ }
+ if (EVP_PKEY_keygen_init(ctx) != 1) {
+ TRY_LOG_ERROR("EVP_PKEY_keygen_init() error");
+ goto opensslError;
+ }
+ if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1) != 1) {
+ TRY_LOG_ERROR("EVP_PKEY_CTX_set_ec_paramgen_curve_nid() error");
+ goto opensslError;
+ }
+ if (EVP_PKEY_keygen(ctx, &pkey) != 1) {
+ TRY_LOG_ERROR("EVP_PKEY_keygen() error");
+ goto opensslError;
+ }
+
+ EVP_PKEY_CTX_free(ctx);
+ return X9_62_P_256_Key{pkey};
+
+opensslError:
+ EVP_PKEY_CTX_free(ctx);
+ throw OpensslError{};
+}
+
+X9_62_P_256_Key X9_62_P_256_Key::ImportPrivateKey(const CryptoBuffer &input)
+{
+ EVP_PKEY *pkey = nullptr;
+ EC_KEY *ec = nullptr;
+ EC_GROUP *group = nullptr;
+ EC_POINT *point = nullptr;
+ const BIGNUM *bn = nullptr;
- key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- if (!key)
+ pkey = EVP_PKEY_new();
+ if (!pkey) {
+ TRY_LOG_ERROR("EVP_PKEY_new() error");
goto opensslError;
- if (EC_KEY_generate_key(key) != 1)
+ }
+ ec = EC_KEY_new();
+ if (!ec) {
+ TRY_LOG_ERROR("EC_KEY_new() error");
goto opensslError;
- buffLen = EC_KEY_key2buf(key, POINT_CONVERSION_COMPRESSED, &buff, nullptr);
- if (buffLen == 0)
+ }
+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ if (!group) {
+ TRY_LOG_ERROR("EC_GROUP_new_by_curve_name() error");
goto opensslError;
- if (buffLen != res.size())
+ }
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_set_group(ec, group) != 1) {
+ TRY_LOG_ERROR("EC_KEY_set_group() error");
goto opensslError;
+ }
+ if (EC_KEY_oct2priv(ec, input.data(), input.size()) != 1) {
+ TRY_LOG_ERROR("EC_KEY_oct2priv() error");
+ goto opensslError;
+ }
+ point = EC_POINT_new(group);
+ if (!point) {
+ TRY_LOG_ERROR("EC_POINT_new() error");
+ goto opensslError;
+ }
+ bn = EC_KEY_get0_private_key(ec);
+ if (!bn) {
+ TRY_LOG_ERROR("EC_KEY_get0_private_key() error");
+ goto opensslError;
+ }
+ if (EC_POINT_mul(group, point, bn, nullptr, nullptr, nullptr) != 1) {
+ TRY_LOG_ERROR("EC_POINT_mul() error");
+ goto opensslError;
+ }
+ if (EC_KEY_set_public_key(ec, point) != 1) {
+ TRY_LOG_ERROR("EC_KEY_set_public_key() error");
+ goto opensslError;
+ }
+ if (EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ TRY_LOG_ERROR("EVP_PKEY_assign_EC_KEY() error");
+ goto opensslError;
+ }
+
+ EC_GROUP_clear_free(group);
+ EC_POINT_clear_free(point);
+ return X9_62_P_256_Key{pkey};
+
+opensslError:
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec);
+ EC_GROUP_clear_free(group);
+ EC_POINT_clear_free(point);
+ throw OpensslError{};
+}
+
+X9_62_P_256_Key X9_62_P_256_Key::ImportPublicKey(const CryptoBuffer &input)
+{
+ EVP_PKEY *pkey = nullptr;
+ EC_KEY *ec = nullptr;
+ EC_GROUP *group = nullptr;
+
+ pkey = EVP_PKEY_new();
+ if (!pkey) {
+ TRY_LOG_ERROR("EVP_PKEY_new() error");
+ goto opensslError;
+ }
+ ec = EC_KEY_new();
+ if (!ec) {
+ TRY_LOG_ERROR("EC_KEY_new() error");
+ goto opensslError;
+ }
+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ if (!group) {
+ TRY_LOG_ERROR("EC_GROUP_new_by_curve_name() error");
+ goto opensslError;
+ }
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_set_group(ec, group) != 1) {
+ TRY_LOG_ERROR("EC_KEY_set_group() error");
+ goto opensslError;
+ }
+ if (EC_KEY_oct2key(ec, input.data(), input.size(), nullptr) != 1) {
+ TRY_LOG_ERROR("EC_KEY_oct2key() error");
+ goto opensslError;
+ }
+ if (EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ TRY_LOG_ERROR("EVP_PKEY_assign_EC_KEY() error");
+ goto opensslError;
+ }
+
+ EC_GROUP_clear_free(group);
+ return X9_62_P_256_Key{pkey};
+
+opensslError:
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec);
+ EC_GROUP_clear_free(group);
+ throw OpensslError{};
+}
+
+CryptoBuffer X9_62_P_256_Key::ExportPrivateKey() const
+{
+ CryptoBuffer res(32);
+ size_t buffLen;
+ unsigned char *buff = nullptr;
+
+ const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(m_key);
+ buffLen = EC_KEY_priv2buf(ec, &buff);
+ if (buffLen == 0 || buffLen != res.size()) {
+ TRY_LOG_ERROR("EC_KEY_priv2buf() error");
+ OPENSSL_free(buff);
+ throw OpensslError{};
+ }
+
std::memcpy(res.data(), buff, buffLen);
OPENSSL_free(buff);
- EC_KEY_free(key);
return res;
+}
-opensslError:
+CryptoBuffer X9_62_P_256_Key::ExportPublicKey(bool compressed) const
+{
+ CryptoBuffer res(compressed ? 33 : 65);
+ point_conversion_form_t form =
+ compressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED;
+ size_t buffLen;
+ unsigned char *buff = nullptr;
+
+ const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(m_key);
+ buffLen = EC_KEY_key2buf(ec, form, &buff, nullptr);
+ if (buffLen == 0 || buffLen != res.size()) {
+ TRY_LOG_ERROR("EC_KEY_key2buf() error");
+ OPENSSL_free(buff);
+ throw OpensslError{};
+ }
+
+ std::memcpy(res.data(), buff, buffLen);
OPENSSL_free(buff);
- EC_KEY_free(key);
- throw OpensslError{};
+ return res;
}
} // namespace Crypto
+
+#pragma GCC diagnostic pop
#include "crypto/common.h"
+#include <openssl/evp.h>
+
namespace Crypto {
-CryptoBuffer GenerateCompressedX9_62_P_256_Key();
+class X9_62_P_256_Key {
+public:
+ X9_62_P_256_Key(const X9_62_P_256_Key &) = delete;
+
+ X9_62_P_256_Key(X9_62_P_256_Key &&other) noexcept : m_key(other.m_key)
+ {
+ other.m_key = nullptr;
+ }
+
+ X9_62_P_256_Key &operator=(const X9_62_P_256_Key &) = delete;
+ X9_62_P_256_Key &operator=(X9_62_P_256_Key &&) = delete;
+
+ ~X9_62_P_256_Key() { EVP_PKEY_free(m_key); }
+
+ static X9_62_P_256_Key Create();
+ static X9_62_P_256_Key ImportPrivateKey(const CryptoBuffer &input);
+ static X9_62_P_256_Key ImportPublicKey(const CryptoBuffer &input);
+
+ CryptoBuffer ExportPrivateKey() const;
+ CryptoBuffer ExportPublicKey(bool compressed) const;
+
+ EVP_PKEY *get() const noexcept { return m_key; }
+
+private:
+ explicit X9_62_P_256_Key(EVP_PKEY *key) noexcept { m_key = key; }
+
+ EVP_PKEY *m_key = nullptr;
+};
} // namespace Crypto
{
if (QRInitiated()) {
auto qrSecret = Crypto::RandomBytes(16);
- auto identityKeyCompressed = Crypto::GenerateCompressedX9_62_P_256_Key();
+ auto identityKey = Crypto::X9_62_P_256_Key::Create();
+ auto identityKeyCompressed = identityKey.ExportPublicKey(true);
ShowQRCode(qrSecret, identityKeyCompressed);
#include <gtest/gtest.h>
-TEST(ECKey, GenerateCompressedX9_62_P_256_Key)
+TEST(X9_62_P_256_KeyTest, CreateExportImportTest)
{
- auto key1 = Crypto::GenerateCompressedX9_62_P_256_Key();
- ASSERT_EQ(key1.size(), 33);
+ auto key1 = Crypto::X9_62_P_256_Key::Create();
+ auto privKey1 = key1.ExportPrivateKey();
+ auto pubKey1 = key1.ExportPublicKey(false);
+ auto pubKeyCompressed1 = key1.ExportPublicKey(true);
- auto key2 = Crypto::GenerateCompressedX9_62_P_256_Key();
- ASSERT_EQ(key2.size(), 33);
+ ASSERT_EQ(privKey1.size(), 32);
+ ASSERT_EQ(pubKey1.size(), 65);
+ ASSERT_EQ(pubKeyCompressed1.size(), 33);
- ASSERT_NE(key1, key2);
+ auto key2 = Crypto::X9_62_P_256_Key::ImportPrivateKey(privKey1);
+ auto privKey2 = key2.ExportPrivateKey();
+ auto pubKey2 = key2.ExportPublicKey(false);
+ auto pubKeyCompressed2 = key2.ExportPublicKey(true);
+
+ EXPECT_EQ(privKey1, privKey2);
+ EXPECT_EQ(pubKey1, pubKey2);
+ EXPECT_EQ(pubKeyCompressed1, pubKeyCompressed2);
+
+ auto key3 = Crypto::X9_62_P_256_Key::ImportPublicKey(pubKey1);
+ auto pubKey3 = key3.ExportPublicKey(false);
+ auto pubKeyCompressed3 = key3.ExportPublicKey(true);
+ EXPECT_EQ(pubKey1, pubKey3);
+ EXPECT_EQ(pubKeyCompressed1, pubKeyCompressed3);
+
+ auto key4 = Crypto::X9_62_P_256_Key::ImportPublicKey(pubKeyCompressed1);
+ auto pubKey4 = key4.ExportPublicKey(false);
+ auto pubKeyCompressed4 = key4.ExportPublicKey(true);
+ EXPECT_EQ(pubKey1, pubKey4);
+ EXPECT_EQ(pubKeyCompressed1, pubKeyCompressed4);
+}
+
+TEST(X9_62_P_256_KeyTest, CreateExportRandomTest)
+{
+ auto key1 = Crypto::X9_62_P_256_Key::Create();
+ auto key2 = Crypto::X9_62_P_256_Key::Create();
+
+ EXPECT_NE(key1.ExportPrivateKey(), key2.ExportPrivateKey());
+ EXPECT_NE(key1.ExportPublicKey(false), key2.ExportPublicKey(false));
+ EXPECT_NE(key1.ExportPublicKey(true), key2.ExportPublicKey(true));
+}
+
+TEST(X9_62_P_256_KeyTest, ImportExportTestVector)
+{
+ const CryptoBuffer PRIV_KEY = {0xcb, 0x6f, 0xc4, 0xd8, 0x99, 0x34, 0x03, 0x6d, 0x35, 0xa3, 0x60,
+ 0x5a, 0xae, 0x36, 0x63, 0x6d, 0xe4, 0x8f, 0x62, 0xa7, 0x64, 0xf7,
+ 0xfd, 0xdc, 0x61, 0xc1, 0x12, 0x36, 0xa6, 0xf7, 0x79, 0x76};
+
+ const CryptoBuffer PUB_KEY = {0x04, 0x52, 0x6a, 0x35, 0xdf, 0x37, 0x0f, 0xf3, 0x5e, 0x56, 0x22,
+ 0x96, 0xc9, 0x55, 0xbf, 0x33, 0xdb, 0x75, 0x52, 0x24, 0xad, 0x63,
+ 0x20, 0xfc, 0x8c, 0xa9, 0x14, 0x97, 0xe3, 0x85, 0x14, 0x3e, 0xed,
+ 0xbd, 0x1d, 0x73, 0x10, 0xe8, 0x20, 0xb8, 0xfb, 0xe0, 0xc3, 0x5f,
+ 0x97, 0x36, 0x69, 0xa3, 0x40, 0x83, 0x4c, 0xae, 0xf2, 0xf0, 0x89,
+ 0xfa, 0x8a, 0xb4, 0xc1, 0x9e, 0xca, 0xf6, 0xb9, 0x11, 0x39};
+
+ const CryptoBuffer PUB_KEY_COMPRESSED = {0x03, 0x52, 0x6a, 0x35, 0xdf, 0x37, 0x0f, 0xf3, 0x5e,
+ 0x56, 0x22, 0x96, 0xc9, 0x55, 0xbf, 0x33, 0xdb, 0x75,
+ 0x52, 0x24, 0xad, 0x63, 0x20, 0xfc, 0x8c, 0xa9, 0x14,
+ 0x97, 0xe3, 0x85, 0x14, 0x3e, 0xed};
+
+ auto key = Crypto::X9_62_P_256_Key::ImportPrivateKey(PRIV_KEY);
+ auto privKey = key.ExportPrivateKey();
+ auto pubKey = key.ExportPublicKey(false);
+ auto pubKeyCompressed = key.ExportPublicKey(true);
+
+ EXPECT_EQ(privKey, PRIV_KEY);
+ EXPECT_EQ(pubKey, PUB_KEY);
+ EXPECT_EQ(pubKeyCompressed, PUB_KEY_COMPRESSED);
}