mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 21:37:17 +01:00
extract and verify LS2 transient key
This commit is contained in:
parent
812e2814bc
commit
bce4224d6e
|
@ -64,7 +64,8 @@ namespace data
|
||||||
i2p::crypto::bn2buf (x, signingKey, 32);
|
i2p::crypto::bn2buf (x, signingKey, 32);
|
||||||
i2p::crypto::bn2buf (y, signingKey + 32, 32);
|
i2p::crypto::bn2buf (y, signingKey + 32, 32);
|
||||||
BN_free (x); BN_free (y);
|
BN_free (x); BN_free (y);
|
||||||
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey);
|
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>();
|
||||||
|
verifier->SetPublicKey (signingKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||||
|
|
|
@ -318,62 +318,56 @@ namespace data
|
||||||
return CRYPTO_KEY_TYPE_ELGAMAL;
|
return CRYPTO_KEY_TYPE_ELGAMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdentityEx::CreateVerifier () const
|
i2p::crypto::Verifier * IdentityEx::CreateVerifier (uint16_t keyType)
|
||||||
{
|
{
|
||||||
if (m_Verifier) return; // don't create again
|
|
||||||
auto keyType = GetSigningKeyType ();
|
|
||||||
switch (keyType)
|
switch (keyType)
|
||||||
{
|
{
|
||||||
case SIGNING_KEY_TYPE_DSA_SHA1:
|
case SIGNING_KEY_TYPE_DSA_SHA1:
|
||||||
UpdateVerifier (new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey));
|
return new i2p::crypto::DSAVerifier ();
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||||
{
|
return new i2p::crypto::ECDSAP256Verifier ();
|
||||||
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
|
|
||||||
UpdateVerifier (new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
||||||
{
|
return new i2p::crypto::ECDSAP384Verifier ();
|
||||||
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
|
|
||||||
UpdateVerifier (new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
||||||
{
|
return new i2p::crypto::ECDSAP521Verifier ();
|
||||||
uint8_t signingKey[i2p::crypto::ECDSAP521_KEY_LENGTH];
|
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||||
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
|
return new i2p::crypto::EDDSA25519Verifier ();
|
||||||
size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128
|
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
||||||
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
|
return new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA);
|
||||||
UpdateVerifier (new i2p::crypto::ECDSAP521Verifier (signingKey));
|
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
||||||
break;
|
return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512);
|
||||||
}
|
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||||
LogPrint (eLogError, "Identity: RSA signing key type ", (int)keyType, " is not supported");
|
LogPrint (eLogError, "Identity: RSA signing key type ", (int)keyType, " is not supported");
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
|
||||||
{
|
|
||||||
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
|
|
||||||
UpdateVerifier (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
|
||||||
{
|
|
||||||
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
|
|
||||||
UpdateVerifier (new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA, m_StandardIdentity.signingKey + padding));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
|
||||||
{
|
|
||||||
// zero padding
|
|
||||||
UpdateVerifier (new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512, m_StandardIdentity.signingKey));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
|
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityEx::CreateVerifier () const
|
||||||
|
{
|
||||||
|
if (m_Verifier) return; // don't create again
|
||||||
|
auto verifier = CreateVerifier (GetSigningKeyType ());
|
||||||
|
if (verifier)
|
||||||
|
{
|
||||||
|
auto keyLen = verifier->GetPublicKeyLen ();
|
||||||
|
if (keyLen <= 128)
|
||||||
|
verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// for P521
|
||||||
|
uint8_t * signingKey = new uint8_t[keyLen];
|
||||||
|
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
|
||||||
|
size_t excessLen = keyLen - 128;
|
||||||
|
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
|
||||||
|
verifier->SetPublicKey (signingKey);
|
||||||
|
delete[] signingKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateVerifier (verifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
||||||
|
|
|
@ -91,11 +91,11 @@ namespace data
|
||||||
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
||||||
size_t FromBase64(const std::string& s);
|
size_t FromBase64(const std::string& s);
|
||||||
std::string ToBase64 () const;
|
std::string ToBase64 () const;
|
||||||
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
|
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
|
||||||
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
|
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
|
||||||
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
||||||
size_t GetSigningPublicKeyLen () const;
|
size_t GetSigningPublicKeyLen () const;
|
||||||
|
@ -107,10 +107,11 @@ namespace data
|
||||||
CryptoKeyType GetCryptoKeyType () const;
|
CryptoKeyType GetCryptoKeyType () const;
|
||||||
void DropVerifier () const; // to save memory
|
void DropVerifier () const; // to save memory
|
||||||
|
|
||||||
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
|
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
|
||||||
|
void RecalculateIdentHash(uint8_t * buff=nullptr);
|
||||||
void RecalculateIdentHash(uint8_t * buff=nullptr);
|
|
||||||
|
|
||||||
|
static i2p::crypto::Verifier * CreateVerifier (uint16_t keyType);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateVerifier () const;
|
void CreateVerifier () const;
|
||||||
|
|
|
@ -245,14 +245,34 @@ namespace data
|
||||||
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
||||||
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
|
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
|
||||||
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
||||||
if (flags) return; // offline keys not supported
|
std::unique_ptr<i2p::crypto::Verifier> offlineVerifier;
|
||||||
|
if (flags & 0x0001)
|
||||||
|
{
|
||||||
|
// offline key
|
||||||
|
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
|
||||||
|
offlineVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType));
|
||||||
|
if (!offlineVerifier) return;
|
||||||
|
auto keyLen = offlineVerifier->GetPublicKeyLen ();
|
||||||
|
if (offset + keyLen >= len) return;
|
||||||
|
offlineVerifier->SetPublicKey (buf + offset); offset += keyLen;
|
||||||
|
if (offset + offlineVerifier->GetSignatureLen () >= len) return;
|
||||||
|
uint8_t * signedData = new uint8_t[keyLen + 6];
|
||||||
|
htobe32buf (signedData, timestamp + expires);
|
||||||
|
htobe16buf (signedData + 4, keyType);
|
||||||
|
memcpy (signedData + 6, buf + offset - keyLen, keyLen);
|
||||||
|
bool verified = identity->Verify (signedData, keyLen + 6, buf + offset);
|
||||||
|
delete[] signedData;
|
||||||
|
if (!verified) return;
|
||||||
|
offset += offlineVerifier->GetSignatureLen ();
|
||||||
|
}
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
if (offset + 1 >= len) return;
|
if (offset + 1 >= len) return;
|
||||||
// key sections
|
// key sections
|
||||||
//int numKeySections = buf[offset]; offset++;
|
int numKeySections = buf[offset]; offset++;
|
||||||
//for (int i = 0; i < numKeySections; i++)
|
for (int i = 0; i < numKeySections; i++)
|
||||||
{
|
{
|
||||||
// skip key for now. TODO: implement encryption key
|
// skip key for now. TODO: implement encryption key
|
||||||
offset += 2; // encryption key type
|
offset += 2; // encryption key type
|
||||||
|
@ -269,7 +289,7 @@ namespace data
|
||||||
uint8_t * buf1 = new uint8_t[offset + 1];
|
uint8_t * buf1 = new uint8_t[offset + 1];
|
||||||
buf1[0] = m_StoreType;
|
buf1[0] = m_StoreType;
|
||||||
memcpy (buf1 + 1, buf, offset); // TODO: implement it better
|
memcpy (buf1 + 1, buf, offset); // TODO: implement it better
|
||||||
bool verified = identity->Verify (buf1, offset + 1, buf + offset); // assume online keys
|
bool verified = offlineVerifier ? offlineVerifier->Verify (buf1, offset + 1, buf + offset) : identity->Verify (buf1, offset + 1, buf + offset);
|
||||||
delete[] buf1;
|
delete[] buf1;
|
||||||
if (!verified)
|
if (!verified)
|
||||||
LogPrint (eLogWarning, "LeaseSet2: verification failed");
|
LogPrint (eLogWarning, "LeaseSet2: verification failed");
|
||||||
|
|
|
@ -7,35 +7,43 @@ namespace i2p
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
#if OPENSSL_EDDSA
|
#if OPENSSL_EDDSA
|
||||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
|
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||||
{
|
{
|
||||||
m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
|
|
||||||
m_MDCtx = EVP_MD_CTX_create ();
|
m_MDCtx = EVP_MD_CTX_create ();
|
||||||
EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
||||||
{
|
{
|
||||||
EVP_MD_CTX_destroy (m_MDCtx);
|
EVP_MD_CTX_destroy (m_MDCtx);
|
||||||
EVP_PKEY_free (m_Pkey);
|
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
|
||||||
|
{
|
||||||
|
m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
|
||||||
|
EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
|
||||||
|
}
|
||||||
|
|
||||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
{
|
{
|
||||||
return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
|
return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
|
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
}
|
|
||||||
|
|
||||||
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace crypto
|
||||||
virtual size_t GetPublicKeyLen () const = 0;
|
virtual size_t GetPublicKeyLen () const = 0;
|
||||||
virtual size_t GetSignatureLen () const = 0;
|
virtual size_t GetSignatureLen () const = 0;
|
||||||
virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; };
|
virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; };
|
||||||
|
virtual void SetPublicKey (const uint8_t * signingKey) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Signer
|
class Signer
|
||||||
|
@ -41,9 +42,13 @@ namespace crypto
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DSAVerifier (const uint8_t * signingKey)
|
DSAVerifier ()
|
||||||
{
|
{
|
||||||
m_PublicKey = CreateDSA ();
|
m_PublicKey = CreateDSA ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPublicKey (const uint8_t * signingKey)
|
||||||
|
{
|
||||||
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +159,13 @@ namespace crypto
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECDSAVerifier (const uint8_t * signingKey)
|
ECDSAVerifier ()
|
||||||
{
|
{
|
||||||
m_PublicKey = EC_KEY_new_by_curve_name (curve);
|
m_PublicKey = EC_KEY_new_by_curve_name (curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPublicKey (const uint8_t * signingKey)
|
||||||
|
{
|
||||||
BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL);
|
BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL);
|
||||||
BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL);
|
BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL);
|
||||||
EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y);
|
EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y);
|
||||||
|
@ -275,7 +284,8 @@ namespace crypto
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EDDSA25519Verifier (const uint8_t * signingKey);
|
EDDSA25519Verifier ();
|
||||||
|
void SetPublicKey (const uint8_t * signingKey);
|
||||||
~EDDSA25519Verifier ();
|
~EDDSA25519Verifier ();
|
||||||
|
|
||||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
||||||
|
@ -386,15 +396,22 @@ namespace crypto
|
||||||
|
|
||||||
enum { keyLen = Hash::hashLen };
|
enum { keyLen = Hash::hashLen };
|
||||||
|
|
||||||
GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey):
|
GOSTR3410Verifier (GOSTR3410ParamSet paramSet):
|
||||||
m_ParamSet (paramSet)
|
m_ParamSet (paramSet), m_PublicKey (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPublicKey (const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL);
|
BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL);
|
||||||
BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL);
|
BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL);
|
||||||
m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y);
|
m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y);
|
||||||
BN_free (x); BN_free (y);
|
BN_free (x); BN_free (y);
|
||||||
}
|
}
|
||||||
~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); }
|
~GOSTR3410Verifier ()
|
||||||
|
{
|
||||||
|
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue