| 127 | } |
| 128 | |
| 129 | std::shared_ptr<I2NPMessage> ElGamalAESSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) |
| 130 | { |
| 131 | auto m = NewI2NPMessage (); |
| 132 | m->Align (12); // in order to get buf aligned to 16 (12 + 4) |
| 133 | size_t len = 0; |
| 134 | uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length |
| 135 | |
| 136 | // find non-expired tag |
| 137 | bool tagFound = false; |
| 138 | SessionTag tag; |
| 139 | if (m_NumTags > 0) |
| 140 | { |
| 141 | uint32_t ts = i2p::util::GetSecondsSinceEpoch (); |
| 142 | while (!m_SessionTags.empty ()) |
| 143 | { |
| 144 | if (ts < m_SessionTags.front ().creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) |
| 145 | { |
| 146 | tag = m_SessionTags.front (); |
| 147 | m_SessionTags.pop_front (); // use same tag only once |
| 148 | tagFound = true; |
| 149 | break; |
| 150 | } |
| 151 | else |
| 152 | m_SessionTags.pop_front (); // remove expired tag |
| 153 | } |
| 154 | } |
| 155 | // create message |
| 156 | if (!tagFound) // new session |
| 157 | { |
| 158 | LogPrint (eLogInfo, "Garlic: No tags available, will use ElGamal"); |
| 159 | if (!m_Destination) |
| 160 | { |
| 161 | LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination"); |
| 162 | return nullptr; |
| 163 | } |
| 164 | // create ElGamal block |
| 165 | ElGamalBlock elGamal; |
| 166 | memcpy (elGamal.sessionKey, m_SessionKey, 32); |
| 167 | RAND_bytes (elGamal.preIV, 32); // Pre-IV |
| 168 | uint8_t iv[32]; // IV is first 16 bytes |
| 169 | SHA256(elGamal.preIV, 32, iv); |
| 170 | m_Destination->Encrypt ((uint8_t *)&elGamal, buf); |
| 171 | m_IV = iv; |
| 172 | buf += 514; |
| 173 | len += 514; |
| 174 | } |
| 175 | else // existing session |
| 176 | { |
| 177 | // session tag |
| 178 | memcpy (buf, tag, 32); |
| 179 | uint8_t iv[32]; // IV is first 16 bytes |
| 180 | SHA256(tag, 32, iv); |
| 181 | m_IV = iv; |
| 182 | buf += 32; |
| 183 | len += 32; |
| 184 | } |
| 185 | // AES block |
| 186 | len += CreateAESBlock (buf, msg); |