/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ECCGeneric.cpp Date: 2021-9-17 Author: Reece ***/ #include #include "ECC.hpp" #include "ECCGeneric.hpp" #include "ECCCurves.hpp" namespace Aurora::Crypto::ECC { static bool ExportECCKey(const ecc_key &key, bool pub, DerBuffer &out) { if (!AuTryResize(out, 4096)) { return false; } unsigned long actualSize = out.size(); auto ret = ecc_export_openssl(out.data(), &actualSize, pub ? PK_PUBLIC : PK_PRIVATE, &key); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } if (!AuTryResize(out, actualSize)) { SysPushErrorMem(); return false; } return true; } class PublicECCImpl : public IECCPublic { public: PublicECCImpl(EECCCurve type, ecc_key &key); ~PublicECCImpl(); bool Verify(const Memory::MemoryViewRead &hash, const Memory::MemoryViewRead &signature) override; bool Verify(const Memory::MemoryViewRead &plaintext, const Memory::MemoryViewRead &signature, EHashType method) override; bool AsPublicECC(AuList &out) override; bool Export(bool pub, DerBuffer &out); EECCCurve GetType() override; const ecc_key &GetKey(); private: ecc_key _key; EECCCurve _type; }; PublicECCImpl::PublicECCImpl(EECCCurve type, ecc_key &key) : _key(key), _type(_type) { } PublicECCImpl::~PublicECCImpl() { ecc_free(&_key); } EECCCurve PublicECCImpl::GetType() { return _type; } bool PublicECCImpl::Verify(const Memory::MemoryViewRead &hash, const Memory::MemoryViewRead &signature) { int ok = 0; if (!hash.HasMemory()) { SysPushErrorParam(); return {}; } if (!signature.HasMemory()) { SysPushErrorParam(); return {}; } auto ret = ecc_verify_hash_ex(reinterpret_cast(hash.ptr), hash.length, reinterpret_cast(signature.ptr), signature.length, LTC_ECCSIG_ETH27, &ok, &_key); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } return ok == 1; } bool PublicECCImpl::Verify(const Memory::MemoryViewRead &plaintext, const Memory::MemoryViewRead &signature, EHashType method) { if (!plaintext.HasMemory()) { SysPushErrorParam(); return {}; } if (!signature.HasMemory()) { SysPushErrorParam(); return {}; } int hash = HashMethodToId(method); if (hash == 0xFF) { SysPushErrorCrypt("invalid hash {}", method); return false; } AuList hashVec; if (!AuTryResize(hashVec, 128)) { SysPushErrorMem(); return false; } unsigned long hashSize = hashVec.size(); auto ret = hash_memory(hash, reinterpret_cast(plaintext.ptr), plaintext.length, reinterpret_cast(hashVec.data()), &hashSize); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } return Verify({hashVec}, signature); } bool PublicECCImpl::AsPublicECC(AuList &out) { return Export(true, out); } bool PublicECCImpl::Export(bool pub, DerBuffer &out) { return ExportECCKey(_key, pub, out); } const ecc_key &PublicECCImpl::GetKey() { return _key; } class PrivateECCImpl : public IECCPrivate { public: PrivateECCImpl(EECCCurve type, ecc_key &key); ~PrivateECCImpl(); bool Sign(const Memory::MemoryViewRead &plainText, EHashType method, AuList &out) override; bool Sign(const Memory::MemoryViewRead &hash, AuList &out) override; bool ECDH(const AuSPtr &partnerPublic, AuList &sharedKey) override; bool AsPublicECC(AuList &out) override; bool AsPrivateECC(AuList &out) override; EECCCurve GetType() override; private: ecc_key _key; EECCCurve _type; }; PrivateECCImpl::PrivateECCImpl(EECCCurve type, ecc_key &key) : _key(key) { } PrivateECCImpl::~PrivateECCImpl() { ecc_free(&_key); } EECCCurve PrivateECCImpl::GetType() { return _type; } bool PrivateECCImpl::Sign(const Memory::MemoryViewRead &plainText, EHashType method, AuList &out) { prng_state yarrow_prng; const int salt = 0; if (!plainText.HasMemory()) { SysPushErrorParam(); return {}; } int hash = HashMethodToId(method); if (hash == 0xFF) { SysPushErrorCrypt("invalid hash {}", method); return false; } if (!AuTryResize(out, 1024)) { SysPushErrorMem(); return false; } AuList hashVec; if (!AuTryResize(hashVec, 128)) { SysPushErrorMem(); return false; } unsigned long hashSize = hashVec.size(); auto ret = hash_memory(hash, reinterpret_cast(plainText.ptr), plainText.length, reinterpret_cast(hashVec.data()), &hashSize); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } return Sign(hashVec, out); } bool PrivateECCImpl::Sign(const Memory::MemoryViewRead &hash, AuList &out) { prng_state yarrow_prng; const int salt = 0; if (!hash.HasMemory()) { SysPushErrorParam(); return {}; } if (!AuTryResize(out, 1024)) { SysPushErrorMem(); return false; } unsigned long len = out.size(); auto ret = ecc_sign_hash_ex(reinterpret_cast(hash.ptr), hash.length, out.data(), &len, &yarrow_prng, ::Crypto::gPrngYarrow, LTC_ECCSIG_ETH27, nullptr, &_key); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } if (!AuTryResize(out, len)) { SysPushErrorMem(); return false; } return true; } bool PrivateECCImpl::ECDH(const AuSPtr &partnerPublic, AuList &sharedKey) { AuList sharedSecret; if (!AuTryResize(sharedSecret, 128)) { SysPushErrorMem(); return false; } if (partnerPublic->GetType() == this->GetType()) { SysPushErrorCrypto("Can not EDCH with incompatible curve curve type (noting, ed25519 requires translation to x25519)"); return false; } unsigned long actualSize = sharedSecret.size(); auto ret = ecc_shared_secret(&_key, &(std::reinterpret_pointer_cast(partnerPublic)->GetKey()), sharedSecret.data(), &actualSize); if (ret != CRYPT_OK) { SysPushErrorCrypt("{}", ret); return false; } sharedSecret.resize(actualSize); return true; } bool PrivateECCImpl::AsPublicECC(AuList &out) { return ExportECCKey(_key, true, out); } bool PrivateECCImpl::AsPrivateECC(AuList &out) { return ExportECCKey(_key, false, out); } template static Type_t *NewECC(EECCCurve curve, const AuList &pub) { ecc_key in {}; auto ret = ecc_import_openssl(pub.data(), pub.size(), &in); if (ret != CRYPT_OK) { SysPushErrorCrypto("{}", ret); return nullptr; } auto out = _new Type_t(curve, in); if (!out) { ecc_free(&in); } return out; } }