size_t Resource::Reader::readData(char *buffer, size_t size) { if(!mCurrentBlock) return 0; // EOF if(!mKey.empty() && !mCurrentBlock->hasDecryption()) { BinaryString subsalt; subsalt.writeBinary(uint64_t(mCurrentBlockIndex)); // Generate subkey BinaryString subkey; Sha256().pbkdf2_hmac(mKey, subsalt, subkey, 32, 100); // Generate iv BinaryString iv; Sha256().pbkdf2_hmac(mResource->salt(), subsalt, iv, 16, 100); // Initialize decryption process mCurrentBlock->setDecryption(subkey, iv); } size_t ret; if((ret = mCurrentBlock->readData(buffer, size))) { mReadPosition+= ret; return ret; } delete mCurrentBlock; ++mCurrentBlockIndex; mCurrentBlock = mNextBlock; mNextBlock = createBlock(mCurrentBlockIndex + 1); return readData(buffer, size); }
bool PortMapping::NatPMP::check(String &host) { LogDebug("PortMapping::NatPMP", "Trying NAT-PMP..."); BinaryString query; query.writeBinary(uint8_t(0)); // version query.writeBinary(uint8_t(0)); // op int attempts = 3; duration timeout = milliseconds(250.); for(int i=0; i<attempts; ++i) { BinaryString dgram = query; mSock.write(dgram, mGatewayAddr); using clock = std::chrono::steady_clock; std::chrono::time_point<clock> end = clock::now() + std::chrono::duration_cast<clock::duration>(timeout); while(clock::now() < end) { Address sender; duration left = end - clock::now(); if(!mSock.read(dgram, sender, left)) break; if(!sender.isPrivate()) continue; LogDebug("PortMapping::NatPMP", String("Got response from ") + sender.toString()); if(parse(dgram, 0)) { LogDebug("PortMapping", "NAT-PMP is available"); mGatewayAddr = sender; host = mExternalHost; return true; } } timeout*= 2; } //LogDebug("PortMapping::NatPMP", "NAT-PMP is not available"); return false; }
bool PortMapping::NatPMP::request(uint8_t op, uint16_t internal, uint16_t suggested, uint32_t lifetime, uint16_t *external) { if(!op) return false; BinaryString query; query.writeBinary(uint8_t(0)); // version query.writeBinary(op); // op query.writeBinary(uint16_t(0)); // reserved query.writeBinary(internal); query.writeBinary(suggested); query.writeBinary(lifetime); const int attempts = 3; duration timeout = milliseconds(250.); for(int i=0; i<attempts; ++i) { BinaryString dgram = query; mSock.write(dgram, mGatewayAddr); using clock = std::chrono::steady_clock; std::chrono::time_point<clock> end = clock::now() + std::chrono::duration_cast<clock::duration>(timeout); while(clock::now() < end) { Address sender; duration left = end - clock::now(); if(!mSock.read(dgram, sender, left)) break; if(!sender.isPrivate()) continue; if(parse(dgram, op, internal)) return true; } timeout*= 2; } return false; }
void Resource::process(const String &filename, const String &name, const String &type, const String &secret) { BinaryString salt; // If secret is not empty then this is an encrypted resource if(!secret.empty()) { // Generate salt from plaintext // Because we need to be able to recognize data is identical even when encrypted BinaryString digest; File file(filename, File::Read); Sha256().compute(file, digest); Sha256().pbkdf2_hmac(digest, type, salt, 32, 100000); Assert(!salt.empty()); } // Fill index record delete mIndexRecord; int64_t size = File::Size(filename); mIndexRecord = new Resource::IndexRecord; mIndexRecord->name = name; mIndexRecord->type = type; mIndexRecord->size = size; mIndexRecord->salt = salt; mIndexRecord->blockDigests.reserve(size/Block::Size); // Process blocks File file(filename, File::Read); BinaryString blockDigest; if(!secret.empty()) { BinaryString key; Sha256().pbkdf2_hmac(secret, salt, key, 32, 100000); uint64_t i = 0; while(true) { BinaryString subsalt; subsalt.writeBinary(i); // Generate subkey BinaryString subkey; Sha256().pbkdf2_hmac(key, subsalt, subkey, 32, 100); // Generate iv BinaryString iv; Sha256().pbkdf2_hmac(salt, subsalt, iv, 16, 100); if(!Block::EncryptFile(file, subkey, iv, blockDigest)) break; mIndexRecord->blockDigests.append(blockDigest); ++i; } } else { while(Block::ProcessFile(file, blockDigest)) mIndexRecord->blockDigests.append(blockDigest); } // Create index String tempFileName = File::TempName(); File tempFile(tempFileName, File::Truncate); BinarySerializer serializer(&tempFile); serializer.write(mIndexRecord); tempFile.close(); String indexFilePath = Cache::Instance->move(tempFileName); // Create index block delete mIndexBlock; mIndexBlock = new Block(indexFilePath); }