Beispiel #1
0
	void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
	{
		if (key)
		{
			uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
			m_Tags[SessionTag(tag, ts)] = std::make_shared<AESDecryption>(key);
		}
	}
Beispiel #2
0
	void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
	{
		if (key)
		{
			uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
			auto decryption = std::make_shared<i2p::crypto::CBCDecryption>();
			decryption->SetKey (key);
			m_Tags[SessionTag(tag, ts)] = decryption;
		}
	}
Beispiel #3
0
	void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
	{
		uint8_t * buf = msg->GetPayload ();
		uint32_t length = bufbe32toh (buf);
		if (length > msg->GetLength ())
		{
			LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
			return;
		}
		buf += 4; // length
		auto it = m_Tags.find (SessionTag(buf));
		if (it != m_Tags.end ())
		{
			// tag found. Use AES
			auto decryption = it->second;
			m_Tags.erase (it); // tag might be used only once
			if (length >= 32)
			{
				uint8_t iv[32]; // IV is first 16 bytes
				SHA256(buf, 32, iv);
				decryption->SetIV (iv);
				decryption->Decrypt (buf + 32, length - 32, buf + 32);
				HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
			}
			else
				LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
		}
		else
		{
			// tag not found. Use ElGamal
			ElGamalBlock elGamal;
			if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
			{
				auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
				uint8_t iv[32]; // IV is first 16 bytes
				SHA256(elGamal.preIV, 32, iv);
				decryption->SetIV (iv);
				decryption->Decrypt(buf + 514, length - 514, buf + 514);
				HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
			}
			else
				LogPrint (eLogError, "Garlic: Failed to decrypt message");
		}
	}
Beispiel #4
0
	void GarlicDestination::LoadTags ()
	{
		std::string ident = GetIdentHash().ToBase32();
		std::string path  = i2p::fs::DataDirPath("tags", (ident + ".tags"));
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
		{
			// might contain non-expired tags
			std::ifstream f (path, std::ifstream::binary);
			if (f)
			{
				std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
				// 4 bytes timestamp, 32 bytes tag, 32 bytes key
				while (!f.eof ())
				{
					uint32_t t;
					uint8_t tag[32], key[32];
					f.read ((char *)&t, 4); if (f.eof ()) break;
					if (ts < t + INCOMING_TAGS_EXPIRATION_TIMEOUT)
					{
						f.read ((char *)tag, 32);
						f.read ((char *)key, 32);
					}
					else
						f.seekg (64, std::ios::cur); // skip
					if (f.eof ()) break;

					std::shared_ptr<AESDecryption> decryption;
					auto it = keys.find (key);
					if (it != keys.end ())
						decryption = it->second;
					else
						decryption = std::make_shared<AESDecryption>(key);
					m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
				}
				if (!m_Tags.empty ())
					LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
			}
		}
		i2p::fs::Remove (path);
	}
Beispiel #5
0
	void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
		std::shared_ptr<i2p::tunnel::InboundTunnel> from)
	{
		uint16_t tagCount = bufbe16toh (buf);
		buf += 2; len -= 2;
		if (tagCount > 0)
		{
			if (tagCount*32 > len)
			{
				LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
				return ;
			}
			uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
			for (int i = 0; i < tagCount; i++)
				m_Tags[SessionTag(buf + i*32, ts)] = decryption;
		}
		buf += tagCount*32;
		len -= tagCount*32;
		uint32_t payloadSize = bufbe32toh (buf);
		if (payloadSize > len)
		{
			LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
			return;
		}
		buf += 4;
		uint8_t * payloadHash = buf;
		buf += 32;// payload hash.
		if (*buf) // session key?
			buf += 32; // new session key
		buf++; // flag

		// payload
		uint8_t digest[32];
		SHA256 (buf, payloadSize, digest);
		if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match
		{
			LogPrint (eLogError, "Garlic: wrong payload hash");
			return;
		}
		HandleGarlicPayload (buf, payloadSize, from);
	}
Beispiel #6
0
	void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
	{
		uint8_t * buf = msg->GetPayload ();
		uint32_t length = bufbe32toh (buf);
		if (length > msg->GetLength ())
		{
			LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ());
			return;
		}	
		buf += 4; // length
		auto it = m_Tags.find (SessionTag(buf));
		if (it != m_Tags.end ())
		{
			// tag found. Use AES
			if (length >= 32)
			{	
				uint8_t iv[32]; // IV is first 16 bytes
				CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
				it->second->SetIV (iv);
				it->second->Decrypt (buf + 32, length - 32, buf + 32);
				HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
			}	
			else
				LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes");
			m_Tags.erase (it); // tag might be used only once	
		}
		else
		{
			// tag not found. Use ElGamal
			ElGamalBlock elGamal;
			if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true))
			{	
				auto decryption = std::make_shared<i2p::crypto::CBCDecryption>();
				decryption->SetKey (elGamal.sessionKey);
				uint8_t iv[32]; // IV is first 16 bytes
				CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); 
				decryption->SetIV (iv);
				decryption->Decrypt(buf + 514, length - 514, buf + 514);
				HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
			}	
			else
				LogPrint (eLogError, "Failed to decrypt garlic");
		}

		// cleanup expired tags
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		if (ts > m_LastTagsCleanupTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
		{
			if (m_LastTagsCleanupTime)
			{
				int numExpiredTags = 0;
				for (auto it = m_Tags.begin (); it != m_Tags.end ();)
				{
					if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
					{
						numExpiredTags++;
						it = m_Tags.erase (it);
					}	
					else
						it++;
				}
				LogPrint (numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
			}	
			m_LastTagsCleanupTime = ts;
		}	
	}