| 944 | } |
| 945 | |
| 946 | void SSU2Session::SendSessionCreated (const uint8_t * X) |
| 947 | { |
| 948 | // we are Bob |
| 949 | m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); |
| 950 | m_SentHandshakePacket.reset (new HandshakePacket); |
| 951 | auto ts = i2p::util::GetMillisecondsSinceEpoch (); |
| 952 | m_SentHandshakePacket->sendTime = ts; |
| 953 | |
| 954 | uint8_t kh2[32]; |
| 955 | i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) |
| 956 | // fill packet |
| 957 | Header& header = m_SentHandshakePacket->header; |
| 958 | uint8_t * headerX = m_SentHandshakePacket->headerX, |
| 959 | * payload = m_SentHandshakePacket->payload; |
| 960 | header.h.connID = m_DestConnID; // dest id |
| 961 | RAND_bytes (header.buf + 8, 4); // random packet num |
| 962 | header.h.type = eSSU2SessionCreated; |
| 963 | header.h.flags[0] = m_Version; // ver |
| 964 | header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID |
| 965 | header.h.flags[2] = 0; // flag |
| 966 | memcpy (headerX, &m_SourceConnID, 8); // source id |
| 967 | memset (headerX + 8, 0, 8); // token = 0 |
| 968 | memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y |
| 969 | // KDF for SessionCreated |
| 970 | m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) |
| 971 | m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); |
| 972 | uint8_t sharedSecret[32]; |
| 973 | m_EphemeralKeys->Agree (X, sharedSecret); |
| 974 | m_NoiseState->MixKey (sharedSecret); |
| 975 | // payload |
| 976 | size_t maxPayloadSize = m_MaxPayloadSize - 48; |
| 977 | size_t payloadSize = 0, offset = 0; |
| 978 | #if OPENSSL_PQ |
| 979 | if (m_Version > 2 && m_PQKeys) |
| 980 | { |
| 981 | size_t cipherTextLen = m_PQKeys->GetCTLen (); |
| 982 | std::vector<uint8_t> kemCiphertext(cipherTextLen); |
| 983 | m_PQKeys->Encaps (kemCiphertext.data (), sharedSecret); |
| 984 | if (!m_NoiseState->Encrypt (kemCiphertext.data (), payload, cipherTextLen)) |
| 985 | { |
| 986 | LogPrint (eLogWarning, "SSU2: SessionCreated ML-KEM ciphertext section AEAD encryption failed"); |
| 987 | return; |
| 988 | } |
| 989 | offset = cipherTextLen + 16; |
| 990 | m_NoiseState->MixHash (payload, offset); // encrypt ML-KEM frame |
| 991 | m_NoiseState->MixKey (sharedSecret); |
| 992 | payloadSize += offset; |
| 993 | } |
| 994 | #endif |
| 995 | payload[payloadSize] = eSSU2BlkDateTime; |
| 996 | htobe16buf (payload + payloadSize + 1, 4); |
| 997 | htobe32buf (payload + payloadSize + 3, (ts + 500)/1000); |
| 998 | payloadSize += 7; |
| 999 | payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint); |
| 1000 | if (m_RelayTag) |
| 1001 | { |
| 1002 | payload[payloadSize] = eSSU2BlkRelayTag; |
| 1003 | htobe16buf (payload + payloadSize + 1, 4); |
nothing calls this directly
no test coverage detected