From ba23cf7e3768b81c679cbdeef31b4d06f0b07062 Mon Sep 17 00:00:00 2001 From: Dario Date: Fri, 28 Aug 2020 12:33:11 +0200 Subject: [PATCH] add KeyPairHedera mostly copied from KeyPairEd25519 but not testet yet. Maybe I must use the iroha ed25519 implementation because in the past sodium don't work together with hedera --- src/cpp/Crypto/KeyPairHedera.cpp | 148 +++++++++++++++++++++++++++++++ src/cpp/Crypto/KeyPairHedera.h | 82 +++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 src/cpp/Crypto/KeyPairHedera.cpp create mode 100644 src/cpp/Crypto/KeyPairHedera.h diff --git a/src/cpp/Crypto/KeyPairHedera.cpp b/src/cpp/Crypto/KeyPairHedera.cpp new file mode 100644 index 000000000..80c4649b1 --- /dev/null +++ b/src/cpp/Crypto/KeyPairHedera.cpp @@ -0,0 +1,148 @@ +#include "KeyPairHedera.h" +#include "../lib/DataTypeConverter.h" +#include + +#include "../SingletonManager/ErrorManager.h" + +KeyPairHedera::KeyPairHedera() + : mPrivateKey(nullptr) +{ + +} + + +KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey /* = nullptr*/) + : mPrivateKey(nullptr) +{ + auto derPrefixPriv = DataTypeConverter::hexToBin("302e020100300506032b657004220420"); + auto derPrefixPub = DataTypeConverter::hexToBin("302a300506032b6570032100"); + + auto mm = MemoryManager::getInstance(); + + if (privateKey) { + switch (privateKey->size()) { + case 48: + // key with prefix + if (0 == sodium_memcmp(*privateKey, *derPrefixPriv, derPrefixPriv->size())) { + //int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed); + auto seed = mm->getFreeMemory(crypto_sign_ed25519_SEEDBYTES); + memcpy(*seed, privateKey->data(derPrefixPriv->size()), crypto_sign_ed25519_SEEDBYTES); + createKeyFromSeed(seed); + break; + } + case 32: + createKeyFromSeed(privateKey); + break; + case 64: + //mPrivateKey = privateKey; + if (!mPrivateKey || mPrivateKey->size() != privateKey->size()) { + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + } + mPrivateKey = mm->getFreeMemory(privateKey->size()); + memcpy(*mPrivateKey, *privateKey, privateKey->size()); + } + break; + default: + throw std::exception("[KeyPairHedera] invalid private key"); + } + crypto_sign_ed25519_sk_to_pk(mPublicKey, *mPrivateKey); + } + else if (publicKey) { + switch (publicKey->size()) + { + case 32: { // raw public key + memcpy(mPublicKey, *publicKey, publicKey->size()); + break; + } + case 44: // DER encoded public key + if (0 == sodium_memcmp(*publicKey, *derPrefixPub, derPrefixPub->size())) { + memcpy(mPublicKey, publicKey->data(derPrefixPub->size()), ed25519_pubkey_SIZE); + } + break; + default: + throw std::exception("[KeyPairHedera] invalid public key"); + } + } + + + mm->releaseMemory(derPrefixPriv); + mm->releaseMemory(derPrefixPub); +} + +KeyPairHedera::~KeyPairHedera() +{ + auto mm = MemoryManager::getInstance(); + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + mPrivateKey = nullptr; + } +} + + +void KeyPairHedera::createKeyFromSeed(const MemoryBin* seed) +{ + assert(seed && seed->size() == crypto_sign_ed25519_SEEDBYTES); + + auto mm = MemoryManager::getInstance(); + auto secret_key = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); + crypto_sign_seed_keypair(mPublicKey, *secret_key, *seed); + + if (mPrivateKey) { + mm->releaseMemory(mPrivateKey); + } + mPrivateKey = secret_key; + + // iroha + //ed25519_privkey_SIZE + //ed25519_derive_public_key(const private_key_t* sk,public_key_t* pk); +} + +MemoryBin* KeyPairHedera::sign(const unsigned char* message, size_t messageSize) const +{ + if (!message || !messageSize) return nullptr; + if (!mPrivateKey) return nullptr; + auto mm = MemoryManager::getInstance(); + auto em = ErrorManager::getInstance(); + + const static char functionName[] = "KeyPairHedera::sign"; + + auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); + unsigned long long actualSignLength = 0; + + if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *mPrivateKey)) { + em->addError(new Error(functionName, "sign failed")); + auto messageHex = DataTypeConverter::binToHex(message, messageSize); + em->addError(new ParamError(functionName, "message as hex", messageHex)); + mm->releaseMemory(signBinBuffer); + return nullptr; + } + + if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mPublicKey) != 0) { + // Incorrect signature! + //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); + em->addError(new Error(functionName, "sign verify failed")); + auto messageHex = DataTypeConverter::binToHex(message, messageSize); + em->addError(new ParamError(functionName, "message as hex", messageHex)); + mm->releaseMemory(signBinBuffer); + return nullptr; + } + + // debug + /*const size_t hex_sig_size = crypto_sign_BYTES * 2 + 1; + char sig_hex[hex_sig_size]; + sodium_bin2hex(sig_hex, hex_sig_size, *signBinBuffer, crypto_sign_BYTES); + printf("[User::sign] signature hex: %s\n", sig_hex); + */ + + return signBinBuffer; + +} + +bool KeyPairHedera::verify(const unsigned char* message, size_t messageSize, MemoryBin* signature) const +{ + if (crypto_sign_verify_detached(*signature, message, messageSize, mPublicKey) != 0) { + return false; + } + return true; +} \ No newline at end of file diff --git a/src/cpp/Crypto/KeyPairHedera.h b/src/cpp/Crypto/KeyPairHedera.h new file mode 100644 index 000000000..358a3b680 --- /dev/null +++ b/src/cpp/Crypto/KeyPairHedera.h @@ -0,0 +1,82 @@ +#ifndef __GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H +#define __GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H + +#include "IKeyPair.h" + +/*! +* \author: Dario Rekowski +* +* \date: 2020-08-28 +* +* \brief: Key Pairs class for ed25519 keys, used by hedera for transaction sign +*/ + + +#include "sodium.h" +#include "iroha-ed25519/include/ed25519/ed25519.h" + +class KeyPairHedera : public IKeyPair +{ +public: + //! \param privateKey: copy + //! \param publicKey: copy + //! + KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey = nullptr); + + ~KeyPairHedera(); + + + //! \return caller take ownership of return value + MemoryBin* sign(const MemoryBin* message) const { return sign(message->data(), message->size()); } + inline MemoryBin* sign(const std::string& bodyBytes) const { return sign((const unsigned char*)bodyBytes.data(), bodyBytes.size()); } + MemoryBin* sign(const unsigned char* message, size_t messageSize) const; + + bool verify(const unsigned char* message, size_t messageSize, MemoryBin* signature) const; + + inline const unsigned char* getPublicKey() const { return mPublicKey; } + + inline bool isTheSame(const KeyPairHedera& b) const { + return 0 == sodium_memcmp(mPublicKey, b.mPublicKey, ed25519_pubkey_SIZE); + } + inline bool isTheSame(const unsigned char* pubkey) const { + if (!pubkey) + return false; + return 0 == sodium_memcmp(mPublicKey, pubkey, ed25519_pubkey_SIZE); + } + //! \return 0 if the same + //! \return -1 if not the same + //! \return 1 if hasn't private key + inline int isTheSame(const MemoryBin* privkey) const { + if (!mPrivateKey) return 1; + if (privkey->size() != mPrivateKey->size()) return -1; + return sodium_memcmp(*mPrivateKey, *privkey, privkey->size()); + } + + inline bool operator == (const KeyPairHedera& b) const { return isTheSame(b); } + inline bool operator != (const KeyPairHedera& b) const { return !isTheSame(b); } + + inline bool operator == (const unsigned char* b) const { return isTheSame(b); } + inline bool operator != (const unsigned char* b) const { return !isTheSame(b); } + + inline bool hasPrivateKey() const { return mPrivateKey != nullptr; } + + + +protected: + + KeyPairHedera(); + void createKeyFromSeed(const MemoryBin* seed); + +private: + // 64 Byte + //! \brief ed25519 libsodium private key + //! + //! TODO: replace MemoryBin by a memory obfuscation class which make it hard to steal the private key from memory + MemoryBin* mPrivateKey; + + // 32 Byte + //! \brief ed25519 libsodium public key + unsigned char mPublicKey[ed25519_pubkey_SIZE]; +}; + +#endif //__GRADIDO_LOGIN_SERVER_CRYPTO_HEDERA_KEYS_H \ No newline at end of file