LeaseSet.cpp
1 /* 2 * Copyright (c) 2013-2025, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #include <string.h> 10 #include "I2PEndian.h" 11 #include "Crypto.h" 12 #include "Log.h" 13 #include "Tag.h" 14 #include "Timestamp.h" 15 #include "NetDb.hpp" 16 #include "Tunnel.h" 17 #include "CryptoKey.h" 18 #include "LeaseSet.h" 19 20 namespace i2p 21 { 22 namespace data 23 { 24 LeaseSet::LeaseSet (bool storeLeases): 25 m_IsValid (false), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr), 26 m_Buffer (nullptr), m_BufferLen (0) 27 { 28 } 29 30 LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases): 31 m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr) 32 { 33 m_Buffer = new uint8_t[len]; 34 memcpy (m_Buffer, buf, len); 35 m_BufferLen = len; 36 ReadFromBuffer (); 37 } 38 39 void LeaseSet::Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature) 40 { 41 SetBuffer (buf, len); 42 ReadFromBuffer (false, verifySignature); 43 } 44 45 void LeaseSet::PopulateLeases () 46 { 47 m_StoreLeases = true; 48 ReadFromBuffer (false); 49 } 50 51 void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature) 52 { 53 if (readIdentity || !m_Identity) 54 m_Identity = netdb.NewIdentity (m_Buffer, m_BufferLen); 55 size_t size = m_Identity->GetFullLen (); 56 if (size + 256 > m_BufferLen) 57 { 58 LogPrint (eLogError, "LeaseSet: Identity length ", int(size), " exceeds buffer size ", int(m_BufferLen)); 59 m_IsValid = false; 60 return; 61 } 62 if (m_StoreLeases) 63 { 64 if (!m_EncryptionKey) m_EncryptionKey = new uint8_t[256]; 65 memcpy (m_EncryptionKey, m_Buffer + size, 256); 66 } 67 size += 256; // encryption key 68 size += m_Identity->GetSigningPublicKeyLen (); // unused signing key 69 if (size + 1 > m_BufferLen) 70 { 71 LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen)); 72 m_IsValid = false; 73 return; 74 } 75 uint8_t num = m_Buffer[size]; 76 size++; // num 77 LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num); 78 if (!num || num > MAX_NUM_LEASES) 79 { 80 LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)num); 81 m_IsValid = false; 82 return; 83 } 84 if (size + num*LEASE_SIZE > m_BufferLen) 85 { 86 LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen)); 87 m_IsValid = false; 88 return; 89 } 90 91 UpdateLeasesBegin (); 92 // process leases 93 m_ExpirationTime = 0; 94 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 95 const uint8_t * leases = m_Buffer + size; 96 for (int i = 0; i < num; i++) 97 { 98 Lease lease; 99 lease.tunnelGateway = leases; 100 leases += 32; // gateway 101 lease.tunnelID = bufbe32toh (leases); 102 leases += 4; // tunnel ID 103 lease.endDate = bufbe64toh (leases); 104 leases += 8; // end date 105 UpdateLease (lease, ts); 106 } 107 if (!m_ExpirationTime) 108 { 109 LogPrint (eLogWarning, "LeaseSet: All leases are expired. Dropped"); 110 m_IsValid = false; 111 return; 112 } 113 m_ExpirationTime += LEASE_ENDDATE_THRESHOLD; 114 UpdateLeasesEnd (); 115 116 // verify 117 if (verifySignature) 118 { 119 auto signedSize = leases - m_Buffer; 120 if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen) 121 { 122 LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", int(m_BufferLen)); 123 m_IsValid = false; 124 } 125 else if (!m_Identity->Verify (m_Buffer, signedSize, leases)) 126 { 127 LogPrint (eLogWarning, "LeaseSet: Verification failed"); 128 m_IsValid = false; 129 } 130 } 131 } 132 133 void LeaseSet::UpdateLeasesBegin () 134 { 135 // reset existing leases 136 if (m_StoreLeases) 137 for (auto& it: m_Leases) 138 it->isUpdated = false; 139 else 140 m_Leases.clear (); 141 } 142 143 void LeaseSet::UpdateLeasesEnd () 144 { 145 // delete old leases 146 if (m_StoreLeases) 147 { 148 for (auto it = m_Leases.begin (); it != m_Leases.end ();) 149 { 150 if (!(*it)->isUpdated) 151 { 152 (*it)->endDate = 0; // somebody might still hold it 153 m_Leases.erase (it++); 154 } 155 else 156 ++it; 157 } 158 } 159 } 160 161 void LeaseSet::UpdateLease (const Lease& lease, uint64_t ts) 162 { 163 if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD) 164 { 165 if (lease.endDate > m_ExpirationTime) 166 m_ExpirationTime = lease.endDate; 167 if (m_StoreLeases) 168 { 169 auto ret = m_Leases.insert (i2p::data::netdb.NewLease (lease)); 170 if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing 171 (*ret.first)->isUpdated = true; 172 } 173 } 174 else 175 LogPrint (eLogWarning, "LeaseSet: Lease is expired already"); 176 } 177 178 uint64_t LeaseSet::ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const 179 { 180 if (!m_Identity) return 0; 181 size_t size = m_Identity->GetFullLen (); 182 if (size > len) return 0; 183 size += 256; // encryption key 184 size += m_Identity->GetSigningPublicKeyLen (); // unused signing key 185 if (size > len) return 0; 186 uint8_t num = buf[size]; 187 size++; // num 188 if (size + num*LEASE_SIZE > len) return 0; 189 uint64_t timestamp= 0 ; 190 for (int i = 0; i < num; i++) 191 { 192 size += 36; // gateway (32) + tunnelId(4) 193 auto endDate = bufbe64toh (buf + size); 194 size += 8; // end date 195 if (!timestamp || endDate < timestamp) 196 timestamp = endDate; 197 } 198 return timestamp; 199 } 200 201 bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const 202 { 203 return ExtractExpirationTimestamp (buf, len) > ExtractExpirationTimestamp (m_Buffer, m_BufferLen); 204 } 205 206 bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const 207 { 208 auto now = i2p::util::GetMillisecondsSinceEpoch (); 209 if (fudge) now += rand() % fudge; 210 if (now >= m_ExpirationTime) return true; 211 return m_ExpirationTime - now <= dlt; 212 } 213 214 const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const 215 { 216 return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold); 217 } 218 219 const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const 220 { 221 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 222 std::vector<std::shared_ptr<const Lease> > leases; 223 for (const auto& it: m_Leases) 224 { 225 auto endDate = it->endDate; 226 if (withThreshold) 227 endDate += LEASE_ENDDATE_THRESHOLD; 228 else 229 endDate -= LEASE_ENDDATE_THRESHOLD; 230 if (ts < endDate && !exclude(*it)) 231 leases.push_back (it); 232 } 233 return leases; 234 } 235 236 bool LeaseSet::HasExpiredLeases () const 237 { 238 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 239 for (const auto& it: m_Leases) 240 if (ts >= it->endDate) return true; 241 return false; 242 } 243 244 bool LeaseSet::IsExpired () const 245 { 246 if (m_StoreLeases && IsEmpty ()) return true; 247 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 248 return ts > m_ExpirationTime; 249 } 250 251 void LeaseSet::Encrypt (const uint8_t * data, uint8_t * encrypted) const 252 { 253 if (!m_EncryptionKey) return; 254 auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey); 255 if (encryptor) 256 encryptor->Encrypt (data, encrypted); 257 } 258 259 void LeaseSet::SetBuffer (const uint8_t * buf, size_t len) 260 { 261 if (len > MAX_LS_BUFFER_SIZE) 262 { 263 LogPrint (eLogError, "LeaseSet: Buffer is too long ", len); 264 len = MAX_LS_BUFFER_SIZE; 265 } 266 if (m_Buffer && len > m_BufferLen) 267 { 268 delete[] m_Buffer; 269 m_Buffer = nullptr; 270 } 271 if (!m_Buffer) 272 m_Buffer = new uint8_t[len]; 273 m_BufferLen = len; 274 memcpy (m_Buffer, buf, len); 275 } 276 277 void LeaseSet::SetBufferLen (size_t len) 278 { 279 if (len <= m_BufferLen) m_BufferLen = len; 280 else 281 LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen)); 282 } 283 284 LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, 285 bool storeLeases, std::shared_ptr<LocalDestination> dest, CryptoKeyType preferredCrypto): 286 LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) 287 { 288 SetBuffer (buf, len); 289 if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) 290 ReadFromBufferEncrypted (buf, len, nullptr, dest, nullptr); 291 else 292 ReadFromBuffer (buf, len, dest); 293 } 294 295 LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, 296 std::shared_ptr<LocalDestination> dest, const uint8_t * secret, CryptoKeyType preferredCrypto): 297 LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) 298 { 299 ReadFromBufferEncrypted (buf, len, key, dest, secret); 300 } 301 302 void LeaseSet2::Update (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, bool verifySignature) 303 { 304 SetBuffer (buf, len); 305 if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) 306 ReadFromBuffer (buf, len, dest, false, verifySignature); 307 // TODO: implement encrypted 308 } 309 310 bool LeaseSet2::IsNewer (const uint8_t * buf, size_t len) const 311 { 312 uint64_t expiration; 313 return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp; 314 } 315 316 void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, std::shared_ptr<LocalDestination> dest, 317 bool readIdentity, bool verifySignature) 318 { 319 // standard LS2 header 320 std::shared_ptr<const IdentityEx> identity; 321 if (readIdentity || !GetIdentity ()) 322 { 323 identity = netdb.NewIdentity (buf, len); 324 SetIdentity (identity); 325 } 326 else 327 identity = GetIdentity (); 328 size_t offset = identity->GetFullLen (); 329 if (offset + 8 > len) return; 330 m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds) 331 uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) 332 SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds 333 uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags 334 if (flags & LEASESET2_FLAG_OFFLINE_KEYS) 335 { 336 // transient key 337 m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset); 338 if (!m_TransientVerifier) 339 { 340 LogPrint (eLogError, "LeaseSet2: Offline signature failed"); 341 return; 342 } 343 } 344 if (flags & LEASESET2_FLAG_UNPUBLISHED_LEASESET) m_IsPublic = false; 345 if (flags & LEASESET2_FLAG_PUBLISHED_ENCRYPTED) 346 { 347 m_IsPublishedEncrypted = true; 348 m_IsPublic = true; 349 } 350 // type specific part 351 size_t s = 0; 352 switch (m_StoreType) 353 { 354 case NETDB_STORE_TYPE_STANDARD_LEASESET2: 355 s = ReadStandardLS2TypeSpecificPart (buf + offset, len - offset, dest); 356 break; 357 case NETDB_STORE_TYPE_META_LEASESET2: 358 s = ReadMetaLS2TypeSpecificPart (buf + offset, len - offset); 359 break; 360 default: 361 LogPrint (eLogWarning, "LeaseSet2: Unexpected store type ", (int)m_StoreType); 362 } 363 if (!s) return; 364 offset += s; 365 if (verifySignature || m_TransientVerifier) 366 { 367 // verify signature 368 bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) : 369 VerifySignature (identity, buf, len, offset); 370 SetIsValid (verified); 371 } 372 else 373 SetIsValid (true); 374 offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen (); 375 if (offset > len) { 376 LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len)); 377 return; 378 } 379 SetBufferLen (offset); 380 } 381 382 template<typename Verifier> 383 bool LeaseSet2::VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset) 384 { 385 if (signatureOffset + verifier->GetSignatureLen () > len) return false; 386 // we assume buf inside DatabaseStore message, so buf[-1] is valid memory 387 // change it for signature verification, and restore back 388 uint8_t c = buf[-1]; 389 const_cast<uint8_t *>(buf)[-1] = m_StoreType; 390 bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset); 391 const_cast<uint8_t *>(buf)[-1] = c; 392 if (!verified) 393 LogPrint (eLogWarning, "LeaseSet2: Verification failed"); 394 return verified; 395 } 396 397 size_t LeaseSet2::ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len, 398 std::shared_ptr<LocalDestination> dest) 399 { 400 size_t offset = 0; 401 // properties 402 uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; 403 offset += propertiesLen; // skip for now. TODO: implement properties 404 // key sections 405 CryptoKeyType preferredKeyType = m_EncryptionType; 406 m_EncryptionType = 0; 407 bool preferredKeyFound = false; 408 if (offset + 1 > len) return 0; 409 int numKeySections = buf[offset]; offset++; 410 for (int i = 0; i < numKeySections; i++) 411 { 412 if (offset + 4 > len) return 0; 413 uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type 414 uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2; 415 if (offset + encryptionKeyLen > len) return 0; 416 if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only 417 { 418 // we pick max key type if preferred not found 419 #if !OPENSSL_PQ 420 if (keyType <= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // skip PQ keys if not supported 421 #endif 422 { 423 if ((keyType == preferredKeyType || !m_Encryptor || keyType > m_EncryptionType) && 424 (!dest || dest->SupportsEncryptionType (keyType))) 425 { 426 auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); 427 if (encryptor) 428 { 429 m_Encryptor = encryptor; // TODO: atomic 430 m_EncryptionType = keyType; 431 if (keyType == preferredKeyType) preferredKeyFound = true; 432 } 433 } 434 } 435 } 436 offset += encryptionKeyLen; 437 } 438 // leases 439 if (offset + 1 > len) return 0; 440 int numLeases = buf[offset]; offset++; 441 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 442 if (GetExpirationTime () > ts + LEASESET_EXPIRATION_TIME_THRESHOLD) 443 { 444 LogPrint (eLogWarning, "LeaseSet2: Expiration time is from future ", GetExpirationTime ()/1000LL); 445 return 0; 446 } 447 if (ts > m_PublishedTimestamp*1000LL + LEASESET_EXPIRATION_TIME_THRESHOLD) 448 { 449 LogPrint (eLogWarning, "LeaseSet2: Published time is too old ", m_PublishedTimestamp); 450 return 0; 451 } 452 if (IsStoreLeases ()) 453 { 454 UpdateLeasesBegin (); 455 for (int i = 0; i < numLeases; i++) 456 { 457 if (offset + LEASE2_SIZE > len) return 0; 458 Lease lease; 459 lease.tunnelGateway = buf + offset; offset += 32; // gateway 460 lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID 461 lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date 462 if (lease.endDate > ts + LEASESET_EXPIRATION_TIME_THRESHOLD) 463 { 464 LogPrint (eLogWarning, "LeaseSet2: Lease end date is from future ", lease.endDate); 465 return 0; 466 } 467 UpdateLease (lease, ts); 468 } 469 UpdateLeasesEnd (); 470 } 471 else 472 offset += numLeases*LEASE2_SIZE; // 40 bytes per lease 473 474 return (offset > len ? 0 : offset); 475 } 476 477 size_t LeaseSet2::ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len) 478 { 479 size_t offset = 0; 480 // properties 481 uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; 482 offset += propertiesLen; // skip for now. TODO: implement properties 483 // entries 484 if (offset + 1 > len) return 0; 485 int numEntries = buf[offset]; offset++; 486 for (int i = 0; i < numEntries; i++) 487 { 488 if (offset + LEASE2_SIZE > len) return 0; 489 offset += 32; // hash 490 offset += 3; // flags 491 offset += 1; // cost 492 offset += 4; // expires 493 } 494 // revocations 495 if (offset + 1 > len) return 0; 496 int numRevocations = buf[offset]; offset++; 497 for (int i = 0; i < numRevocations; i++) 498 { 499 if (offset + 32 > len) return 0; 500 offset += 32; // hash 501 } 502 return offset; 503 } 504 505 void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, 506 std::shared_ptr<const BlindedPublicKey> key, std::shared_ptr<LocalDestination> dest, const uint8_t * secret) 507 { 508 size_t offset = 0; 509 // blinded key 510 if (len < 2) return; 511 const uint8_t * stA1 = buf + offset; // stA1 = blinded signature type, 2 bytes big endian 512 uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2; 513 std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType)); 514 if (!blindedVerifier) return; 515 auto blindedKeyLen = blindedVerifier->GetPublicKeyLen (); 516 if (offset + blindedKeyLen >= len) return; 517 const uint8_t * blindedPublicKey = buf + offset; 518 blindedVerifier->SetPublicKey (blindedPublicKey); offset += blindedKeyLen; 519 // expiration 520 if (offset + 8 >= len) return; 521 const uint8_t * publishedTimestamp = buf + offset; 522 m_PublishedTimestamp = bufbe32toh (publishedTimestamp); offset += 4; // published timestamp (seconds) 523 uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) 524 SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds 525 uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags 526 if (flags & LEASESET2_FLAG_OFFLINE_KEYS) 527 { 528 // transient key 529 m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset); 530 if (!m_TransientVerifier) 531 { 532 LogPrint (eLogError, "LeaseSet2: Offline signature failed"); 533 return; 534 } 535 } 536 // outer ciphertext 537 if (offset + 2 > len) return; 538 uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2; 539 const uint8_t * outerCiphertext = buf + offset; 540 offset += lenOuterCiphertext; 541 // verify signature 542 bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) : 543 VerifySignature (blindedVerifier, buf, len, offset); 544 SetIsValid (verified); 545 // handle ciphertext 546 if (verified && key && lenOuterCiphertext >= 32) 547 { 548 SetIsValid (false); // we must verify it again in Layer 2 549 if (blindedKeyType == key->GetBlindedSigType ()) 550 { 551 // verify blinding 552 char date[9]; 553 i2p::util::GetDateString (m_PublishedTimestamp, date); 554 std::vector<uint8_t> blinded (blindedKeyLen); 555 key->GetBlindedKey (date, blinded.data ()); 556 if (memcmp (blindedPublicKey, blinded.data (), blindedKeyLen)) 557 { 558 LogPrint (eLogError, "LeaseSet2: Blinded public key doesn't match"); 559 return; 560 } 561 } 562 else 563 { 564 LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ()); 565 return; 566 } 567 // outer key 568 // outerInput = subcredential || publishedTimestamp 569 uint8_t subcredential[36]; 570 key->GetSubcredential (blindedPublicKey, blindedKeyLen, subcredential); 571 memcpy (subcredential + 32, publishedTimestamp, 4); 572 // outerSalt = outerCiphertext[0:32] 573 // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44) 574 uint8_t keys[64]; // 44 bytes actual data 575 i2p::crypto::HKDF (outerCiphertext, subcredential, 36, "ELS2_L1K", keys); 576 // decrypt Layer 1 577 // outerKey = keys[0:31] 578 // outerIV = keys[32:43] 579 size_t lenOuterPlaintext = lenOuterCiphertext - 32; 580 std::vector<uint8_t> outerPlainText (lenOuterPlaintext); 581 i2p::crypto::ChaCha20 (outerCiphertext + 32, lenOuterPlaintext, keys, keys + 32, outerPlainText.data ()); 582 // inner key 583 // innerInput = authCookie || subcredential || publishedTimestamp 584 // innerSalt = innerCiphertext[0:32] 585 // keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44) 586 uint8_t innerInput[68]; 587 size_t authDataLen = ExtractClientAuthData (outerPlainText.data (), lenOuterPlaintext, secret, subcredential, innerInput); 588 if (authDataLen > 0) 589 { 590 memcpy (innerInput + 32, subcredential, 36); 591 i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys); 592 } 593 else 594 // no authData presented, innerInput = subcredential || publishedTimestamp 595 // skip 1 byte flags 596 i2p::crypto::HKDF (outerPlainText.data () + 1, subcredential, 36, "ELS2_L2K", keys); // no authCookie 597 // decrypt Layer 2 598 // innerKey = keys[0:31] 599 // innerIV = keys[32:43] 600 size_t lenInnerPlaintext = lenOuterPlaintext - 32 - 1 - authDataLen; 601 std::vector<uint8_t> innerPlainText (lenInnerPlaintext); 602 i2p::crypto::ChaCha20 (outerPlainText.data () + 32 + 1 + authDataLen, lenInnerPlaintext, keys, keys + 32, innerPlainText.data ()); 603 if (innerPlainText[0] == NETDB_STORE_TYPE_STANDARD_LEASESET2 || innerPlainText[0] == NETDB_STORE_TYPE_META_LEASESET2) 604 { 605 // override store type and buffer 606 m_StoreType = innerPlainText[0]; 607 SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); 608 // parse and verify Layer 2 609 ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1, dest); 610 } 611 else 612 LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); 613 } 614 else 615 { 616 // we set actual length of encrypted buffer 617 offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : blindedVerifier->GetSignatureLen (); 618 SetBufferLen (offset); 619 } 620 } 621 622 // helper for ExtractClientAuthData 623 static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie) 624 { 625 // try to find clientCookie_i for clientID_i = okm[44:51] 626 for (int i = 0; i < numClients; i++) 627 { 628 if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i 629 { 630 // clientKey_i = okm[0:31] 631 // clientIV_i = okm[32:43] 632 i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i 633 return true; 634 } 635 } 636 return false; 637 } 638 639 size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const 640 { 641 size_t offset = 0; 642 uint8_t flag = buf[offset]; offset++; // flag 643 if (flag & 0x01) // client auth 644 { 645 if (!(flag & 0x0E)) // DH, bit 1-3 all zeroes 646 { 647 const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey 648 uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients 649 const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients 650 if (offset > len) 651 { 652 LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data"); 653 return 0; 654 } 655 // calculate authCookie 656 if (secret) 657 { 658 i2p::crypto::X25519Keys ck (secret, nullptr); // derive cpk_i from csk_i 659 uint8_t authInput[100]; 660 ck.Agree (ephemeralPublicKey, authInput); // sharedSecret is first 32 bytes of authInput 661 memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i 662 memcpy (authInput + 64, subcredential, 36); 663 uint8_t okm[64]; // 52 actual data 664 i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm); 665 if (!GetAuthCookie (authClients, numClients, okm, authCookie)) 666 LogPrint (eLogError, "LeaseSet2: Client cookie DH not found"); 667 } 668 else 669 LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided"); 670 } 671 else if (flag & 0x02) // PSK, bit 1 is set to 1 672 { 673 const uint8_t * authSalt = buf + offset; offset += 32; // authSalt 674 uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients 675 const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients 676 if (offset > len) 677 { 678 LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data"); 679 return 0; 680 } 681 // calculate authCookie 682 if (secret) 683 { 684 uint8_t authInput[68]; 685 memcpy (authInput, secret, 32); 686 memcpy (authInput + 32, subcredential, 36); 687 uint8_t okm[64]; // 52 actual data 688 i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); 689 if (!GetAuthCookie (authClients, numClients, okm, authCookie)) 690 LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found"); 691 } 692 else 693 LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided"); 694 } 695 else 696 LogPrint (eLogError, "LeaseSet2: Unknown client auth type ", (int)flag); 697 } 698 return offset - 1; 699 } 700 701 void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted) const 702 { 703 auto encryptor = m_Encryptor; // TODO: atomic 704 if (encryptor) 705 encryptor->Encrypt (data, encrypted); 706 } 707 708 uint64_t LeaseSet2::ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const 709 { 710 uint64_t expiration = 0; 711 ExtractPublishedTimestamp (buf, len, expiration); 712 return expiration; 713 } 714 715 uint64_t LeaseSet2::ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const 716 { 717 if (len < 8) return 0; 718 if (m_StoreType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) 719 { 720 // encrypted LS2 721 size_t offset = 0; 722 uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2; 723 std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType)); 724 if (!blindedVerifier) return 0 ; 725 auto blindedKeyLen = blindedVerifier->GetPublicKeyLen (); 726 if (offset + blindedKeyLen + 6 >= len) return 0; 727 offset += blindedKeyLen; 728 uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; 729 uint16_t expires = bufbe16toh (buf + offset); offset += 2; 730 expiration = (timestamp + expires)* 1000LL; 731 return timestamp; 732 } 733 else 734 { 735 auto identity = GetIdentity (); 736 if (!identity) return 0; 737 size_t offset = identity->GetFullLen (); 738 if (offset + 6 >= len) return 0; 739 uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; 740 uint16_t expires = bufbe16toh (buf + offset); offset += 2; 741 expiration = (timestamp + expires)* 1000LL; 742 return timestamp; 743 } 744 } 745 746 LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels): 747 m_ExpirationTime (0), m_Identity (identity) 748 { 749 int num = tunnels.size (); 750 if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; 751 // identity 752 auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); 753 m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen (); 754 m_Buffer = new uint8_t[m_BufferLen]; 755 auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen); 756 memcpy (m_Buffer + offset, encryptionPublicKey, 256); 757 offset += 256; 758 memset (m_Buffer + offset, 0, signingKeyLen); 759 offset += signingKeyLen; 760 // num leases 761 auto numLeasesPos = offset; 762 m_Buffer[offset] = num; 763 offset++; 764 // leases 765 m_Leases = m_Buffer + offset; 766 auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); 767 int skipped = 0; 768 for (int i = 0; i < num; i++) 769 { 770 uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration 771 ts *= 1000; // in milliseconds 772 if (ts <= currentTime) 773 { 774 // already expired, skip 775 skipped++; 776 continue; 777 } 778 if (ts > m_ExpirationTime) m_ExpirationTime = ts; 779 // make sure leaseset is newer than previous, but adding some time to expiration date 780 ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs 781 memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); 782 offset += 32; // gateway id 783 htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ()); 784 offset += 4; // tunnel id 785 htobe64buf (m_Buffer + offset, ts); 786 offset += 8; // end date 787 } 788 if (skipped > 0) 789 { 790 // adjust num leases 791 if (skipped > num) skipped = num; 792 num -= skipped; 793 m_BufferLen -= skipped*LEASE_SIZE; 794 m_Buffer[numLeasesPos] = num; 795 } 796 // we don't sign it yet. must be signed later on 797 } 798 799 LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len): 800 m_ExpirationTime (0), m_Identity (identity) 801 { 802 if (buf) 803 { 804 m_BufferLen = len; 805 m_Buffer = new uint8_t[m_BufferLen]; 806 memcpy (m_Buffer, buf, len); 807 } 808 else 809 { 810 m_Buffer = nullptr; 811 m_BufferLen = 0; 812 } 813 } 814 815 bool LocalLeaseSet::IsExpired () const 816 { 817 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 818 return ts > m_ExpirationTime; 819 } 820 821 bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires) 822 { 823 IdentityEx ident(ptr, sz); 824 size_t size = ident.GetFullLen (); 825 if (size > sz) 826 { 827 LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", sz); 828 return false; 829 } 830 // encryption key 831 size += 256; 832 // signing key (unused) 833 size += ident.GetSigningPublicKeyLen (); 834 uint8_t numLeases = ptr[size]; 835 ++size; 836 if (!numLeases || numLeases > MAX_NUM_LEASES) 837 { 838 LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)numLeases); 839 return false; 840 } 841 const uint8_t * leases = ptr + size; 842 expires = 0; 843 /** find lease with the max expiration timestamp */ 844 for (int i = 0; i < numLeases; i++) 845 { 846 leases += 36; // gateway + tunnel ID 847 uint64_t endDate = bufbe64toh (leases); 848 leases += 8; // end date 849 if(endDate > expires) 850 expires = endDate; 851 } 852 return ident.Verify(ptr, leases - ptr, leases); 853 } 854 855 LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, 856 const EncryptionKeys& encryptionKeys, const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels, 857 bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted): 858 LocalLeaseSet (keys.GetPublic (), nullptr, 0) 859 { 860 auto identity = keys.GetPublic (); 861 // assume standard LS2 862 int num = tunnels.size (); 863 if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; 864 size_t keySectionsLen = 0; 865 for (const auto& it: encryptionKeys) 866 keySectionsLen += 2/*key type*/ + 2/*key len*/ + it->pub.size()/*key*/; 867 m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ + 868 1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen (); 869 uint16_t flags = 0; 870 if (keys.IsOfflineSignature ()) 871 { 872 flags |= LEASESET2_FLAG_OFFLINE_KEYS; 873 m_BufferLen += keys.GetOfflineSignature ().size (); 874 } 875 if (isPublishedEncrypted) 876 { 877 flags |= LEASESET2_FLAG_PUBLISHED_ENCRYPTED; 878 isPublic = true; 879 } 880 if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET; 881 882 m_Buffer = new uint8_t[m_BufferLen + 1]; 883 m_Buffer[0] = storeType; 884 // LS2 header 885 auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1; 886 htobe32buf (m_Buffer + offset, publishedTimestamp); offset += 4; // published timestamp (seconds) 887 uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later 888 htobe16buf (m_Buffer + offset, flags); offset += 2; // flags 889 if (keys.IsOfflineSignature ()) 890 { 891 // offline signature 892 const auto& offlineSignature = keys.GetOfflineSignature (); 893 memcpy (m_Buffer + offset, offlineSignature.data (), offlineSignature.size ()); 894 offset += offlineSignature.size (); 895 } 896 htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len 897 // keys 898 m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key 899 for (const auto& it: encryptionKeys) 900 { 901 htobe16buf (m_Buffer + offset, it->keyType); offset += 2; // key type 902 htobe16buf (m_Buffer + offset, it->pub.size()); offset += 2; // key len 903 memcpy (m_Buffer + offset, it->pub.data(), it->pub.size()); offset += it->pub.size(); // key 904 } 905 // leases 906 uint32_t expirationTime = 0; // in seconds 907 int skipped = 0; auto numLeasesPos = offset; 908 m_Buffer[offset] = num; offset++; // num leases 909 for (int i = 0; i < num; i++) 910 { 911 auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration 912 if (ts <= publishedTimestamp) 913 { 914 // already expired, skip 915 skipped++; 916 continue; 917 } 918 if (ts > expirationTime) expirationTime = ts; 919 memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); 920 offset += 32; // gateway id 921 htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ()); 922 offset += 4; // tunnel id 923 htobe32buf (m_Buffer + offset, ts); 924 offset += 4; // end date 925 } 926 if (skipped > 0) 927 { 928 // adjust num leases 929 if (skipped > num) skipped = num; 930 num -= skipped; 931 m_BufferLen -= skipped*LEASE2_SIZE; 932 m_Buffer[numLeasesPos] = num; 933 } 934 // update expiration 935 if (expirationTime) 936 { 937 SetExpirationTime (expirationTime*1000LL); 938 auto expires = (int)expirationTime - publishedTimestamp; 939 htobe16buf (expiresBuf, expires > 0 ? expires : 0); 940 } 941 else 942 { 943 // no tunnels or withdraw 944 SetExpirationTime (publishedTimestamp*1000LL); 945 memset (expiresBuf, 0, 2); // expires immeditely 946 } 947 // sign 948 keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type 949 } 950 951 LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len): 952 LocalLeaseSet (identity, nullptr, 0) 953 { 954 m_BufferLen = len; 955 m_Buffer = new uint8_t[m_BufferLen + 1]; 956 memcpy (m_Buffer + 1, buf, len); 957 m_Buffer[0] = storeType; 958 } 959 960 LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, 961 int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys): 962 LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls) 963 { 964 size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1; 965 uint8_t layer1Flags = 0; 966 if (authKeys) 967 { 968 if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 969 else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 970 if (layer1Flags) 971 lenOuterPlaintext += 32 + 2 + authKeys->size ()*40; // auth data len 972 } 973 size_t lenOuterCiphertext = lenOuterPlaintext + 32; 974 975 m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/; 976 m_Buffer = new uint8_t[m_BufferLen + 1]; 977 m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; 978 BlindedPublicKey blindedKey (ls->GetIdentity ()); 979 auto timestamp = i2p::util::GetSecondsSinceEpoch (); 980 char date[9]; 981 i2p::util::GetDateString (timestamp, date); 982 uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max 983 size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub); 984 std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv)); 985 if (!blindedSigner) 986 { 987 LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ()); 988 return; 989 } 990 auto offset = 1; 991 htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type 992 memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key 993 htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds) 994 auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds 995 auto expirationTime = ls->GetExpirationTime ()/1000LL; 996 if (expirationTime > nextMidnight) expirationTime = nextMidnight; 997 SetExpirationTime (expirationTime*1000LL); 998 htobe16buf (m_Buffer + offset, expirationTime > timestamp ? expirationTime - timestamp : 0); offset += 2; // expires 999 uint16_t flags = 0; 1000 htobe16buf (m_Buffer + offset, flags); offset += 2; // flags 1001 htobe16buf (m_Buffer + offset, lenOuterCiphertext); offset += 2; // lenOuterCiphertext 1002 // outerChipherText 1003 // Layer 1 1004 uint8_t subcredential[36]; 1005 blindedKey.GetSubcredential (blindedPub, 32, subcredential); 1006 htobe32buf (subcredential + 32, timestamp); // outerInput = subcredential || publishedTimestamp 1007 // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44) 1008 uint8_t keys1[64]; // 44 bytes actual data 1009 RAND_bytes (m_Buffer + offset, 32); // outerSalt = CSRNG(32) 1010 i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1); 1011 offset += 32; // outerSalt 1012 uint8_t * outerPlainText = m_Buffer + offset; 1013 m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags 1014 // auth data 1015 uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp 1016 if (layer1Flags) 1017 { 1018 RAND_bytes (innerInput, 32); // authCookie 1019 CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset); 1020 offset += 32 + 2 + authKeys->size ()*40; // auth clients 1021 } 1022 // Layer 2 1023 // keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44) 1024 uint8_t keys2[64]; // 44 bytes actual data 1025 RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32) 1026 if (layer1Flags) 1027 { 1028 memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp 1029 i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2); 1030 } 1031 else 1032 i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie 1033 offset += 32; // innerSalt 1034 m_Buffer[offset] = ls->GetStoreType (); 1035 memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ()); 1036 i2p::crypto::ChaCha20 (m_Buffer + offset, lenInnerPlaintext, keys2, keys2 + 32, m_Buffer + offset); // encrypt Layer 2 1037 offset += lenInnerPlaintext; 1038 i2p::crypto::ChaCha20 (outerPlainText, lenOuterPlaintext, keys1, keys1 + 32, outerPlainText); // encrypt Layer 1 1039 // signature 1040 blindedSigner->Sign (m_Buffer, offset, m_Buffer + offset); 1041 // store hash 1042 m_StoreHash = blindedKey.GetStoreHash (date); 1043 } 1044 1045 LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len): 1046 LocalLeaseSet2 (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, identity, buf, len) 1047 { 1048 // fill inner LeaseSet2 1049 auto blindedKey = std::make_shared<BlindedPublicKey>(identity); 1050 i2p::data::LeaseSet2 ls (buf, len, blindedKey); // inner layer 1051 if (ls.IsValid ()) 1052 { 1053 m_InnerLeaseSet = std::make_shared<LocalLeaseSet2>(ls.GetStoreType (), identity, ls.GetBuffer (), ls.GetBufferLen ()); 1054 m_StoreHash = blindedKey->GetStoreHash (); 1055 } 1056 else 1057 LogPrint (eLogError, "LeaseSet2: Couldn't extract inner layer"); 1058 } 1059 1060 void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const 1061 { 1062 if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) 1063 { 1064 i2p::crypto::X25519Keys ek; 1065 ek.GenerateKeys (); // esk and epk 1066 memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk 1067 htobe16buf (authData, authKeys->size ()); authData += 2; // num clients 1068 uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp 1069 memcpy (authInput + 64, subcredential, 36); 1070 for (auto& it: *authKeys) 1071 { 1072 ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i) 1073 memcpy (authInput + 32, it, 32); 1074 uint8_t okm[64]; // 52 actual data 1075 i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm); 1076 memcpy (authData, okm + 44, 8); authData += 8; // clientID_i 1077 i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i 1078 } 1079 } 1080 else // assume PSK 1081 { 1082 uint8_t authSalt[32]; 1083 RAND_bytes (authSalt, 32); 1084 memcpy (authData, authSalt, 32); authData += 32; // authSalt 1085 htobe16buf (authData, authKeys->size ()); authData += 2; // num clients 1086 uint8_t authInput[68]; // authInput = psk_i || subcredential || publishedTimestamp 1087 memcpy (authInput + 32, subcredential, 36); 1088 for (auto& it: *authKeys) 1089 { 1090 memcpy (authInput, it, 32); 1091 uint8_t okm[64]; // 52 actual data 1092 i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); 1093 memcpy (authData, okm + 44, 8); authData += 8; // clientID_i 1094 i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i 1095 } 1096 } 1097 } 1098 } 1099 }