2021-09-17 19:26:05 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
|
|
|
File: ECCGeneric.cpp
|
|
|
|
Date: 2021-9-17
|
|
|
|
Author: Reece
|
|
|
|
***/
|
|
|
|
#include <RuntimeInternal.hpp>
|
|
|
|
#include "ECC.hpp"
|
|
|
|
#include "ECCGeneric.hpp"
|
|
|
|
#include "ECCCurves.hpp"
|
|
|
|
|
|
|
|
namespace Aurora::Crypto::ECC
|
|
|
|
{
|
2021-09-18 20:10:25 +00:00
|
|
|
static bool ExportECCKey(const ecc_key &key, bool pub, DerBuffer &out)
|
|
|
|
{
|
|
|
|
if (!AuTryResize(out, 4096))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2021-09-17 19:26:05 +00:00
|
|
|
|
2021-09-18 20:10:25 +00:00
|
|
|
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<AuUInt8> &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<const unsigned char *>(hash.ptr), hash.length,
|
|
|
|
reinterpret_cast<const unsigned char *>(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<AuUInt8> hashVec;
|
|
|
|
if (!AuTryResize(hashVec, 128))
|
|
|
|
{
|
|
|
|
SysPushErrorMem();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long hashSize = hashVec.size();
|
|
|
|
auto ret = hash_memory(hash,
|
|
|
|
reinterpret_cast<const unsigned char *>(plaintext.ptr), plaintext.length,
|
|
|
|
reinterpret_cast<unsigned char *>(hashVec.data()), &hashSize);
|
|
|
|
if (ret != CRYPT_OK)
|
|
|
|
{
|
|
|
|
SysPushErrorCrypt("{}", ret);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Verify({hashVec}, signature);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PublicECCImpl::AsPublicECC(AuList<AuUInt8> &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<AuUInt8> &out) override;
|
|
|
|
|
|
|
|
bool Sign(const Memory::MemoryViewRead &hash,
|
|
|
|
AuList<AuUInt8> &out) override;
|
|
|
|
|
|
|
|
bool ECDH(const AuSPtr<IECCPublic> &partnerPublic,
|
|
|
|
AuList<AuUInt8> &sharedKey) override;
|
|
|
|
|
|
|
|
bool AsPublicECC(AuList<AuUInt8> &out) override;
|
|
|
|
|
|
|
|
bool AsPrivateECC(AuList<AuUInt8> &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<AuUInt8> &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<AuUInt8> hashVec;
|
|
|
|
|
|
|
|
if (!AuTryResize(hashVec, 128))
|
|
|
|
{
|
|
|
|
SysPushErrorMem();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long hashSize = hashVec.size();
|
|
|
|
auto ret = hash_memory(hash,
|
|
|
|
reinterpret_cast<const unsigned char *>(plainText.ptr), plainText.length,
|
|
|
|
reinterpret_cast<unsigned char *>(hashVec.data()), &hashSize);
|
|
|
|
if (ret != CRYPT_OK)
|
|
|
|
{
|
|
|
|
SysPushErrorCrypt("{}", ret);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Sign(hashVec, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrivateECCImpl::Sign(const Memory::MemoryViewRead &hash,
|
|
|
|
AuList<AuUInt8> &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<const unsigned char *>(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<IECCPublic> &partnerPublic,
|
|
|
|
AuList<AuUInt8> &sharedKey)
|
|
|
|
{
|
|
|
|
AuList<AuUInt8> 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<PublicECCImpl>(partnerPublic)->GetKey()), sharedSecret.data(), &actualSize);
|
|
|
|
if (ret != CRYPT_OK)
|
|
|
|
{
|
|
|
|
SysPushErrorCrypt("{}", ret);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
sharedSecret.resize(actualSize);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrivateECCImpl::AsPublicECC(AuList<AuUInt8> &out)
|
|
|
|
{
|
|
|
|
return ExportECCKey(_key, true, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrivateECCImpl::AsPrivateECC(AuList<AuUInt8> &out)
|
|
|
|
{
|
|
|
|
return ExportECCKey(_key, false, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Type_t>
|
|
|
|
static Type_t *NewECC(EECCCurve curve, const AuList<AuUInt8> &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;
|
|
|
|
}
|
2021-09-17 19:26:05 +00:00
|
|
|
}
|