| 496 | } |
| 497 | |
| 498 | void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg) |
| 499 | { |
| 500 | uint8_t * buf = msg->GetPayload (); |
| 501 | uint32_t length = bufbe32toh (buf); |
| 502 | if (length > msg->GetLength ()) |
| 503 | { |
| 504 | LogPrint (eLogWarning, "Garlic: Message length ", length, " exceeds I2NP message length ", msg->GetLength ()); |
| 505 | return; |
| 506 | } |
| 507 | auto mod = length & 0x0f; // %16 |
| 508 | buf += 4; // length |
| 509 | |
| 510 | bool found = false; |
| 511 | bool supportsRatchets = SupportsRatchets (); |
| 512 | if (supportsRatchets) |
| 513 | // try ECIESx25519 tag |
| 514 | found = HandleECIESx25519TagMessage (buf, length); |
| 515 | if (!found) |
| 516 | { |
| 517 | auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16 |
| 518 | // AES tag might be used even if encryption type is not ElGamal/AES |
| 519 | if (it != m_Tags.end ()) // try AES tag |
| 520 | { |
| 521 | // tag found. Use AES |
| 522 | auto decryption = it->second; |
| 523 | m_Tags.erase (it); // tag might be used only once |
| 524 | if (length >= 32) |
| 525 | { |
| 526 | uint8_t iv[32]; // IV is first 16 bytes |
| 527 | SHA256(buf, 32, iv); |
| 528 | decryption->Decrypt (buf + 32, length - 32, iv, buf + 32); |
| 529 | HandleAESBlock (buf + 32, length - 32, decryption, msg->from); |
| 530 | found = true; |
| 531 | } |
| 532 | else |
| 533 | LogPrint (eLogWarning, "Garlic: Message length ", length, " is less than 32 bytes"); |
| 534 | } |
| 535 | if (!found) // assume new session |
| 536 | { |
| 537 | // AES tag not found. Handle depending on encryption type |
| 538 | // try ElGamal/AES first if leading block is 514 |
| 539 | ElGamalBlock elGamal; |
| 540 | if (mod == 2 && length >= 514 && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) && |
| 541 | Decrypt (buf, (uint8_t *)&elGamal, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)) |
| 542 | { |
| 543 | auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey); |
| 544 | uint8_t iv[32]; // IV is first 16 bytes |
| 545 | SHA256(elGamal.preIV, 32, iv); |
| 546 | decryption->Decrypt(buf + 514, length - 514, iv, buf + 514); |
| 547 | HandleAESBlock (buf + 514, length - 514, decryption, msg->from); |
| 548 | } |
| 549 | else if (supportsRatchets) |
| 550 | { |
| 551 | // otherwise ECIESx25519 |
| 552 | auto ts = i2p::util::GetMillisecondsSinceEpoch (); |
| 553 | if (ts > m_LastIncomingSessionTimestamp + INCOMING_SESSIONS_MINIMAL_INTERVAL) |
| 554 | { |
| 555 | auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming |
no test coverage detected