commit cef2847326ad6d2c9006ddad8e58a22828a58556 Author: acetone Date: Sat Jun 18 10:06:39 2022 +0300 x25519 added diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b86bde5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cppcodec"] + path = cppcodec + url = https://github.com/tplgy/cppcodec diff --git a/cppcodec b/cppcodec new file mode 160000 index 0000000..9838f9e --- /dev/null +++ b/cppcodec @@ -0,0 +1 @@ +Subproject commit 9838f9eaf077e42121cb42361e9a1613901fc5e8 diff --git a/x25519.cpp b/x25519.cpp new file mode 100644 index 0000000..523fe29 --- /dev/null +++ b/x25519.cpp @@ -0,0 +1,158 @@ +/* + * Based on + * 1. OpenSSL lib + * 2. PurpleI2P source code + * 3. cppcodec lib + * + * PUBLIC DOMAIN C++ WRAPPER + * acetone, 2022 + */ + +#include "x25519.h" +#include "cppcodec/base64_default_rfc4648.hpp" + +#include +#include + +namespace cppcrypto { + +X25519Keys::X25519Keys() +{ + m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL); + m_Pkey = nullptr; +} + +X25519Keys::X25519Keys (const std::array &priv, const std::array &pub) +{ + m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv.data(), 32); + m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); + if (not pub.empty()) + { + memcpy (m_publicKey.data(), pub.data(), 32); + } + else + { + size_t len = 32; + EVP_PKEY_get_raw_public_key (m_Pkey, m_publicKey.data(), &len); + } +} + +X25519Keys::~X25519Keys() +{ + EVP_PKEY_CTX_free (m_Ctx); + if (m_Pkey) EVP_PKEY_free (m_Pkey); +} + +void X25519Keys::generateKeys() noexcept +{ + if (m_Pkey) + { + EVP_PKEY_free (m_Pkey); + m_Pkey = nullptr; + } + EVP_PKEY_keygen_init (m_Ctx); + EVP_PKEY_keygen (m_Ctx, &m_Pkey); + EVP_PKEY_CTX_free (m_Ctx); + m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); + size_t len = 32; + EVP_PKEY_get_raw_public_key (m_Pkey, m_publicKey.data(), &len); +} + +const std::array X25519Keys::getPublicKey() const noexcept +{ + return m_publicKey; +} + +const std::array X25519Keys::getSecretKey() const noexcept +{ + std::array priv; + size_t len = 32; + EVP_PKEY_get_raw_private_key (m_Pkey, priv.data(), &len); + return priv; +} + +const std::array X25519Keys::agree (const std::array &pub) const noexcept +{ + std::array shared; + if (pub.size() < 32 or (pub[31] & 0x80)) return shared; // not x25519 key + + EVP_PKEY_derive_init (m_Ctx); + auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub.data(), 32); + if (!pkey) return shared; + EVP_PKEY_derive_set_peer (m_Ctx, pkey); + size_t len = 32; + EVP_PKEY_derive (m_Ctx, shared.data(), &len); + EVP_PKEY_free (pkey); + return shared; +} + +const std::array X25519Keys::agree (const std::string &pub) const noexcept +{ + std::vector bytes; + try { + bytes = cppcodec::base64_rfc4648::decode(pub); + } catch (...) { + return std::array(); + } + return agree (bytes.data(), bytes.size()); +} + +const std::array X25519Keys::agree (const uint8_t *pub, size_t size) const noexcept +{ + if (size != 32) + { + return std::array(); + } + + std::array key; + for (int i = 0; i < 32; i++) + { + key[i] = pub[i]; + } + return agree(key); +} + +void X25519Keys::setSecretKey (const uint8_t * priv, bool calculatePublic) noexcept +{ + if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx); + if (m_Pkey) EVP_PKEY_free (m_Pkey); + m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); + m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); + if (calculatePublic) + { + size_t len = 32; + EVP_PKEY_get_raw_public_key (m_Pkey, m_publicKey.data(), &len); + } +} + +void X25519Keys::setSecretKey (const std::string &priv, bool calculatePublic) +{ + std::vector keyBytes = cppcodec::base64_rfc4648::decode(priv); + setSecretKey (keyBytes, calculatePublic); +} + +void X25519Keys::setSecretKey (const std::vector& priv, bool calculatePublic) +{ + if (priv.size() != 32) + { + throw std::runtime_error ("X25519Keys::setPrivateKey priv array size != 32"); + } + setSecretKey (priv.data(), calculatePublic); +} + +void X25519Keys::setSecretKey (const std::array &priv, bool calculatePublic) +{ + setSecretKey (priv.data(), calculatePublic); +} + +std::string X25519Keys::getPublicKeyBase64String() const noexcept +{ + return cppcodec::base64_rfc4648::encode (getPublicKey().data(), getPublicKey().size()); +} + +std::string X25519Keys::getSecretKeyBase64String() const noexcept +{ + return cppcodec::base64_rfc4648::encode (getSecretKey().data(), getSecretKey().size()); +} + +} // namespace diff --git a/x25519.h b/x25519.h new file mode 100644 index 0000000..aecac62 --- /dev/null +++ b/x25519.h @@ -0,0 +1,50 @@ +/* + * Based on + * 1. OpenSSL lib + * 2. PurpleI2P source code + * 3. cppcodec lib + * + * PUBLIC DOMAIN C++ WRAPPER + * acetone, 2022 + */ + +#ifndef X25519_H +#define X25519_H + +#include +#include +#include +#include + +namespace cppcrypto { + +class X25519Keys +{ +public: + X25519Keys (const std::array& priv, const std::array& pub); + X25519Keys(); + ~X25519Keys(); + + void generateKeys() noexcept; + void setSecretKey (const uint8_t * priv, bool calculatePublic = false) noexcept; + void setSecretKey (const std::vector& priv, bool calculatePublic = false) ; + void setSecretKey (const std::array& priv, bool calculatePublic = false) ; + void setSecretKey (const std::string& priv, bool calculatePublic = false) ; + const std::array getPublicKey() const noexcept; + const std::array getSecretKey() const noexcept; + const std::array agree (const std::array& pub) const noexcept; + const std::array agree (const std::string& pub) const noexcept; + const std::array agree (const uint8_t* pub, size_t size = 32) const noexcept; + + std::string getPublicKeyBase64String() const noexcept; + std::string getSecretKeyBase64String() const noexcept; + +private: + std::array m_publicKey; + EVP_PKEY_CTX * m_Ctx; + EVP_PKEY * m_Pkey; +}; + +} // namespace + +#endif // X25519_H