| 1117 | } |
| 1118 | |
| 1119 | void SSU2Session::SendSessionConfirmed (const uint8_t * Y) |
| 1120 | { |
| 1121 | // we are Alice |
| 1122 | m_SentHandshakePacket.reset (new HandshakePacket); |
| 1123 | m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch (); |
| 1124 | |
| 1125 | uint8_t kh2[32]; |
| 1126 | i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) |
| 1127 | // fill packet |
| 1128 | Header& header = m_SentHandshakePacket->header; |
| 1129 | header.h.connID = m_DestConnID; // dest id |
| 1130 | header.h.packetNum = 0; // always zero |
| 1131 | header.h.type = eSSU2SessionConfirmed; |
| 1132 | memset (header.h.flags, 0, 3); |
| 1133 | header.h.flags[0] = 1; // frag, total fragments always 1 |
| 1134 | // payload |
| 1135 | size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1 |
| 1136 | uint8_t * payload = m_SentHandshakePacket->payload; |
| 1137 | size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ()); |
| 1138 | if (!payloadSize) |
| 1139 | { |
| 1140 | // split by two fragments |
| 1141 | maxPayloadSize += m_MaxPayloadSize; |
| 1142 | payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ()); |
| 1143 | header.h.flags[0] = 0x02; // frag 0, total fragments 2 |
| 1144 | // TODO: check if we need more fragments |
| 1145 | } |
| 1146 | if (payloadSize < maxPayloadSize) |
| 1147 | payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); |
| 1148 | // KDF for Session Confirmed part 1 |
| 1149 | m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header) |
| 1150 | // Encrypt part 1 |
| 1151 | uint8_t * part1 = m_SentHandshakePacket->headerX; |
| 1152 | m_NoiseState->Encrypt (i2p::context.GetSSU2StaticPublicKey (), part1, 32); |
| 1153 | m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext); |
| 1154 | // KDF for Session Confirmed part 2 |
| 1155 | uint8_t sharedSecret[32]; |
| 1156 | i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret); |
| 1157 | m_NoiseState->MixKey (sharedSecret); |
| 1158 | // Encrypt part2 |
| 1159 | m_NoiseState->Encrypt (payload, payload, payloadSize); |
| 1160 | payloadSize += 16; |
| 1161 | m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext); |
| 1162 | m_SentHandshakePacket->payloadSize = payloadSize; |
| 1163 | if (header.h.flags[0] > 1) |
| 1164 | { |
| 1165 | if (payloadSize > m_MaxPayloadSize - 48) |
| 1166 | { |
| 1167 | payloadSize = m_MaxPayloadSize - 48 - (m_Server.GetRng ()() % 16); |
| 1168 | if (m_SentHandshakePacket->payloadSize - payloadSize < 24) |
| 1169 | payloadSize -= 24; |
| 1170 | } |
| 1171 | else |
| 1172 | header.h.flags[0] = 1; |
| 1173 | } |
| 1174 | // Encrypt header |
| 1175 | header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); |
| 1176 | header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); |
nothing calls this directly
no test coverage detected