mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-08-14 15:50:27 +00:00
common HKDF context for ratchets tags
This commit is contained in:
+26
-10
@@ -779,26 +779,42 @@ namespace crypto
|
||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, std::string_view info,
|
||||
uint8_t * out, size_t outLen)
|
||||
{
|
||||
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||
EVP_PKEY_derive_init (pctx);
|
||||
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
||||
HKDFContext ctx;
|
||||
ctx (salt, key, keyLen, info, out, outLen);
|
||||
}
|
||||
|
||||
HKDFContext::HKDFContext ()
|
||||
{
|
||||
m_Ctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||
}
|
||||
|
||||
HKDFContext::~HKDFContext ()
|
||||
{
|
||||
if (m_Ctx)
|
||||
EVP_PKEY_CTX_free (m_Ctx);
|
||||
}
|
||||
|
||||
void HKDFContext::operator ()(const uint8_t * salt, const uint8_t * key, size_t keyLen,
|
||||
std::string_view info, uint8_t * out, size_t outLen)
|
||||
{
|
||||
EVP_PKEY_derive_init (m_Ctx);
|
||||
EVP_PKEY_CTX_set_hkdf_md (m_Ctx, EVP_sha256());
|
||||
if (key && keyLen)
|
||||
{
|
||||
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
||||
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
||||
EVP_PKEY_CTX_set1_hkdf_salt (m_Ctx, salt, 32);
|
||||
EVP_PKEY_CTX_set1_hkdf_key (m_Ctx, key, keyLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
// zerolen
|
||||
EVP_PKEY_CTX_hkdf_mode (pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
|
||||
EVP_PKEY_CTX_hkdf_mode (m_Ctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
|
||||
uint8_t tempKey[32]; unsigned int len;
|
||||
HMAC(EVP_sha256(), salt, 32, nullptr, 0, tempKey, &len);
|
||||
EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len);
|
||||
EVP_PKEY_CTX_set1_hkdf_key (m_Ctx, tempKey, len);
|
||||
}
|
||||
if (info.length () > 0)
|
||||
EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.data (), info.length ());
|
||||
EVP_PKEY_derive (pctx, out, &outLen);
|
||||
EVP_PKEY_CTX_free (pctx);
|
||||
EVP_PKEY_CTX_add1_hkdf_info (m_Ctx, (const uint8_t *)info.data (), info.length ());
|
||||
EVP_PKEY_derive (m_Ctx, out, &outLen);
|
||||
}
|
||||
|
||||
// Noise
|
||||
|
||||
+42
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2025, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2026, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -46,7 +46,7 @@ namespace crypto
|
||||
EVP_PKEY * CreateDSA (BIGNUM * pubKey = nullptr, BIGNUM * privKey = nullptr);
|
||||
#else
|
||||
DSA * CreateDSA ();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// RSA
|
||||
const BIGNUM * GetRSAE ();
|
||||
@@ -89,21 +89,21 @@ namespace crypto
|
||||
|
||||
// AES
|
||||
typedef i2p::data::Tag<32> AESKey;
|
||||
|
||||
|
||||
class ECBEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
ECBEncryption ();
|
||||
~ECBEncryption ();
|
||||
|
||||
|
||||
void SetKey (const uint8_t * key) { m_Key = key; };
|
||||
void Encrypt(const uint8_t * in, uint8_t * out);
|
||||
|
||||
private:
|
||||
|
||||
AESKey m_Key;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
class ECBDecryption
|
||||
@@ -112,14 +112,14 @@ namespace crypto
|
||||
|
||||
ECBDecryption ();
|
||||
~ECBDecryption ();
|
||||
|
||||
|
||||
void SetKey (const uint8_t * key) { m_Key = key; };
|
||||
void Decrypt (const uint8_t * in, uint8_t * out);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
AESKey m_Key;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
class CBCEncryption
|
||||
@@ -129,13 +129,13 @@ namespace crypto
|
||||
CBCEncryption ();
|
||||
~CBCEncryption ();
|
||||
|
||||
void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
|
||||
void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
|
||||
void Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
AESKey m_Key;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
class CBCDecryption
|
||||
@@ -144,14 +144,14 @@ namespace crypto
|
||||
|
||||
CBCDecryption ();
|
||||
~CBCDecryption ();
|
||||
|
||||
|
||||
void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
|
||||
void Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);
|
||||
|
||||
private:
|
||||
|
||||
AESKey m_Key;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
class TunnelEncryption // with double IV encryption
|
||||
@@ -203,11 +203,11 @@ namespace crypto
|
||||
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag
|
||||
|
||||
void Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
class AEADChaCha20Poly1305Decryptor
|
||||
{
|
||||
@@ -218,35 +218,49 @@ namespace crypto
|
||||
|
||||
bool Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
|
||||
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
|
||||
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
|
||||
|
||||
|
||||
// ChaCha20
|
||||
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
|
||||
|
||||
class ChaCha20Context
|
||||
class ChaCha20Context final
|
||||
{
|
||||
public:
|
||||
|
||||
ChaCha20Context ();
|
||||
~ChaCha20Context ();
|
||||
void operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
EVP_CIPHER_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
|
||||
// HKDF
|
||||
|
||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, std::string_view info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
||||
|
||||
class HKDFContext final
|
||||
{
|
||||
public:
|
||||
|
||||
HKDFContext ();
|
||||
~HKDFContext ();
|
||||
|
||||
void operator ()(const uint8_t * salt, const uint8_t * key, size_t keyLen, std::string_view info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
||||
|
||||
private:
|
||||
|
||||
EVP_PKEY_CTX * m_Ctx;
|
||||
};
|
||||
|
||||
// Noise
|
||||
|
||||
struct NoiseSymmetricState
|
||||
@@ -255,7 +269,7 @@ namespace crypto
|
||||
uint64_t m_N;
|
||||
|
||||
void Init (const uint8_t * ck, const uint8_t * hh, const uint8_t * pub);
|
||||
|
||||
|
||||
void MixHash (const uint8_t * buf, size_t len);
|
||||
void MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
|
||||
void MixKey (const uint8_t * sharedSecret);
|
||||
@@ -268,7 +282,7 @@ namespace crypto
|
||||
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
|
||||
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2)
|
||||
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
|
||||
|
||||
|
||||
// init and terminate
|
||||
void InitCrypto (bool precomputation);
|
||||
void TerminateCrypto ();
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace garlic
|
||||
m_NextIndex = 0;
|
||||
}
|
||||
|
||||
uint64_t RatchetTagSet::GetNextSessionTag ()
|
||||
uint64_t RatchetTagSet::GetNextSessionTag (i2p::crypto::HKDFContext& hkdfCtx)
|
||||
{
|
||||
m_NextIndex++;
|
||||
if (m_NextIndex >= 65535)
|
||||
@@ -52,7 +52,7 @@ namespace garlic
|
||||
LogPrint (eLogError, "Garlic: Tagset ", GetTagSetID (), " is empty");
|
||||
return 0;
|
||||
}
|
||||
i2p::crypto::HKDF (m_SessionTagKeyData, m_SessTagConstant, 32, "SessionTagKeyGen", m_SessionTagKeyData); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64)
|
||||
hkdfCtx (m_SessionTagKeyData, m_SessTagConstant, 32, "SessionTagKeyGen", m_SessionTagKeyData); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64)
|
||||
return m_SessionTagKeyData.GetLL ()[4]; // tag = keydata[32:39]
|
||||
}
|
||||
|
||||
@@ -648,7 +648,7 @@ namespace garlic
|
||||
// we are Bob
|
||||
m_NSRSendTagset = std::make_shared<RatchetTagSet>();
|
||||
InitNewSessionTagset (m_NSRSendTagset);
|
||||
uint64_t tag = m_NSRSendTagset->GetNextSessionTag ();
|
||||
uint64_t tag = m_NSRSendTagset->GetNextSessionTag (GetOwner ()->GetHKDFContext ());
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy (out + offset, &tag, 8);
|
||||
@@ -733,7 +733,7 @@ namespace garlic
|
||||
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||
{
|
||||
// we are Bob and sent NSR already
|
||||
uint64_t tag = m_NSRSendTagset->GetNextSessionTag (); // next tag
|
||||
uint64_t tag = m_NSRSendTagset->GetNextSessionTag (GetOwner ()->GetHKDFContext ()); // next tag
|
||||
memcpy (out, &tag, 8);
|
||||
memcpy (out + 8, m_NSREncodedKey, 32);
|
||||
// recalculate h with new tag
|
||||
@@ -908,7 +908,7 @@ namespace garlic
|
||||
uint8_t nonce[12];
|
||||
auto index = m_SendTagset->GetNextIndex ();
|
||||
CreateNonce (index, nonce); // tag's index
|
||||
uint64_t tag = m_SendTagset->GetNextSessionTag ();
|
||||
uint64_t tag = m_SendTagset->GetNextSessionTag (GetOwner ()->GetHKDFContext ());
|
||||
if (!tag)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset");
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace garlic
|
||||
|
||||
void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
|
||||
void NextSessionTagRatchet ();
|
||||
uint64_t GetNextSessionTag ();
|
||||
uint64_t GetNextSessionTag (i2p::crypto::HKDFContext& hkdfCtx);
|
||||
const uint8_t * GetNextRootKey () const { return m_NextRootKey; };
|
||||
int GetNextIndex () const { return m_NextIndex; };
|
||||
void GetSymmKey (int index, uint8_t * key);
|
||||
|
||||
+1
-1
@@ -1067,7 +1067,7 @@ namespace garlic
|
||||
uint64_t GarlicDestination::AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset)
|
||||
{
|
||||
auto index = tagset->GetNextIndex ();
|
||||
uint64_t tag = tagset->GetNextSessionTag ();
|
||||
uint64_t tag = tagset->GetNextSessionTag (m_HKDFContext);
|
||||
if (tag)
|
||||
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset});
|
||||
return tag;
|
||||
|
||||
@@ -257,6 +257,7 @@ namespace garlic
|
||||
int GetNumTags () const { return m_NumTags; };
|
||||
void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; };
|
||||
int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; };
|
||||
i2p::crypto::HKDFContext& GetHKDFContext () { return m_HKDFContext; }
|
||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||
bool attachLeaseSet, bool requestNewIfNotFound = true);
|
||||
void CleanupExpiredTags ();
|
||||
@@ -333,6 +334,7 @@ namespace garlic
|
||||
// encryption
|
||||
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
|
||||
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
|
||||
i2p::crypto::HKDFContext m_HKDFContext;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user