Added AsyncFileEncrypted
This commit is contained in:
parent
1615977695
commit
88bc157bd0
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
* AsyncFileEncrypted.actor.cpp
|
||||||
|
*
|
||||||
|
* This source file is part of the FoundationDB open source project
|
||||||
|
*
|
||||||
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fdbrpc/AsyncFileEncrypted.h"
|
||||||
|
#include "flow/StreamCipher.h"
|
||||||
|
#include "flow/UnitTest.h"
|
||||||
|
#include "flow/xxhash.h"
|
||||||
|
#include "flow/actorcompiler.h" // must be last include
|
||||||
|
|
||||||
|
class AsyncFileEncryptedImpl {
|
||||||
|
public:
|
||||||
|
static auto getFirstBlockIV(const std::string& filename) {
|
||||||
|
StreamCipher::IV iv;
|
||||||
|
auto hash = XXH3_128bits(filename.c_str(), filename.size());
|
||||||
|
auto high = reinterpret_cast<unsigned char*>(&hash.high64);
|
||||||
|
auto low = reinterpret_cast<unsigned char*>(&hash.low64);
|
||||||
|
std::copy(high, high + 8, &iv[0]);
|
||||||
|
std::copy(low, low + 6, &iv[8]);
|
||||||
|
iv[14] = iv[15] = 0; // last 16 bits identify block
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<Standalone<StringRef>> readBlock(AsyncFileEncrypted* self, uint16_t block) {
|
||||||
|
state Arena arena;
|
||||||
|
state unsigned char* encrypted = new (arena) unsigned char[FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE];
|
||||||
|
int bytes = wait(
|
||||||
|
self->file->read(encrypted, FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE, FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE * block));
|
||||||
|
DecryptionStreamCipher decryptor(AsyncFileEncrypted::getKey(), self->getIV(block));
|
||||||
|
auto decrypted = decryptor.decrypt(encrypted, bytes, arena);
|
||||||
|
return Standalone<StringRef>(decrypted, arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<int> read(AsyncFileEncrypted* self, void* data, int length, int offset) {
|
||||||
|
state const uint16_t firstBlock = offset / FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE;
|
||||||
|
state const uint16_t lastBlock = (offset + length - 1) / FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE;
|
||||||
|
state uint16_t block;
|
||||||
|
state unsigned char* output = reinterpret_cast<unsigned char*>(data);
|
||||||
|
state int bytesRead = 0;
|
||||||
|
for (block = firstBlock; block <= lastBlock; ++block) {
|
||||||
|
state StringRef plaintext;
|
||||||
|
auto it = self->readBuffers.find(block);
|
||||||
|
if (it != self->readBuffers.end()) {
|
||||||
|
plaintext = it->second;
|
||||||
|
} else {
|
||||||
|
Standalone<StringRef> _plaintext = wait(readBlock(self, block));
|
||||||
|
ASSERT(_plaintext.size() == FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE);
|
||||||
|
if (self->readBuffers.size() == FLOW_KNOBS->MAX_DECRYPTED_BLOCKS) {
|
||||||
|
// TODO: Improve eviction policy
|
||||||
|
self->readBuffers.erase(self->readBuffers.begin());
|
||||||
|
}
|
||||||
|
self->readBuffers[block] = _plaintext;
|
||||||
|
plaintext = _plaintext;
|
||||||
|
}
|
||||||
|
ASSERT(plaintext.size() == FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE);
|
||||||
|
auto start = (block == firstBlock) ? plaintext.begin() + (offset % FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE)
|
||||||
|
: plaintext.begin();
|
||||||
|
auto end = (block == lastBlock)
|
||||||
|
? plaintext.begin() + ((offset + length) % FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE)
|
||||||
|
: plaintext.end();
|
||||||
|
if ((offset + length) % FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE == 0) {
|
||||||
|
end = plaintext.end();
|
||||||
|
}
|
||||||
|
std::copy(start, end, output);
|
||||||
|
output += (end - start);
|
||||||
|
bytesRead += (end - start);
|
||||||
|
}
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<Void> write(AsyncFileEncrypted* self, void const* data, int length, int64_t offset) {
|
||||||
|
ASSERT(self->canWrite);
|
||||||
|
ASSERT(offset == self->currentBlock * FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE + self->offsetInBlock);
|
||||||
|
state unsigned char const* input = reinterpret_cast<unsigned char const*>(data);
|
||||||
|
while (length > 0) {
|
||||||
|
const auto chunkSize = std::min(length, FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE - self->offsetInBlock);
|
||||||
|
Arena arena;
|
||||||
|
auto encrypted = self->encryptor->encrypt(input, chunkSize, arena);
|
||||||
|
std::copy(encrypted.begin(), encrypted.end(), &self->writeBuffer[self->offsetInBlock]);
|
||||||
|
offset += encrypted.size();
|
||||||
|
self->offsetInBlock += chunkSize;
|
||||||
|
length -= chunkSize;
|
||||||
|
input += chunkSize;
|
||||||
|
if (self->offsetInBlock == FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE) {
|
||||||
|
wait(self->writeLastBlockToFile());
|
||||||
|
self->offsetInBlock = 0;
|
||||||
|
ASSERT(self->currentBlock < std::numeric_limits<uint16_t>::max());
|
||||||
|
++self->currentBlock;
|
||||||
|
self->encryptor = std::make_unique<EncryptionStreamCipher>(AsyncFileEncrypted::getKey(), self->getIV(self->currentBlock));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<Void> sync(AsyncFileEncrypted* self) {
|
||||||
|
ASSERT(self->canWrite);
|
||||||
|
wait(self->writeLastBlockToFile());
|
||||||
|
wait(self->file->sync());
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<Void> initializeKey(Reference<IAsyncFile> keyFile, int64_t offset) {
|
||||||
|
ASSERT(!AsyncFileEncrypted::key.present());
|
||||||
|
AsyncFileEncrypted::key = StreamCipher::Key{};
|
||||||
|
state int keySize = AsyncFileEncrypted::key.get().size();
|
||||||
|
if (g_network->isSimulated()) {
|
||||||
|
generateRandomData(AsyncFileEncrypted::key.get().data(), keySize);
|
||||||
|
return Void();
|
||||||
|
} else {
|
||||||
|
int bytesRead = wait(keyFile->read(AsyncFileEncrypted::key.get().data(), keySize, offset));
|
||||||
|
ASSERT(bytesRead == keySize);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTOR static Future<Void> zeroRange(AsyncFileEncrypted* self, int64_t offset, int64_t length) {
|
||||||
|
// TODO: Could optimize this
|
||||||
|
Arena arena;
|
||||||
|
auto zeroes = new (arena) unsigned char[length];
|
||||||
|
memset(zeroes, 0, length);
|
||||||
|
wait(self->write(zeroes, length, offset));
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AsyncFileEncrypted::AsyncFileEncrypted(Reference<IAsyncFile> file, bool canWrite)
|
||||||
|
: file(file), canWrite(canWrite), currentBlock(0) {
|
||||||
|
firstBlockIV = AsyncFileEncryptedImpl::getFirstBlockIV(file->getFilename());
|
||||||
|
if (canWrite) {
|
||||||
|
encryptor = std::make_unique<EncryptionStreamCipher>(AsyncFileEncrypted::getKey(), getIV(currentBlock));
|
||||||
|
writeBuffer = std::vector<unsigned char>(FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncFileEncrypted::addref() {
|
||||||
|
ReferenceCounted<AsyncFileEncrypted>::addref();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncFileEncrypted::delref() {
|
||||||
|
ReferenceCounted<AsyncFileEncrypted>::delref();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> AsyncFileEncrypted::read(void* data, int length, int64_t offset) {
|
||||||
|
return AsyncFileEncryptedImpl::read(this, data, length, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::write(void const* data, int length, int64_t offset) {
|
||||||
|
return AsyncFileEncryptedImpl::write(this, data, length, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::zeroRange(int64_t offset, int64_t length) {
|
||||||
|
return AsyncFileEncryptedImpl::zeroRange(this, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::truncate(int64_t size) {
|
||||||
|
ASSERT(false); // TODO: Not yet implemented
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::sync() {
|
||||||
|
return AsyncFileEncryptedImpl::sync(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::flush() {
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int64_t> AsyncFileEncrypted::size() const {
|
||||||
|
return currentBlock * FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE + offsetInBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AsyncFileEncrypted::getFilename() const {
|
||||||
|
return file->getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::readZeroCopy(void** data, int* length, int64_t offset) {
|
||||||
|
ASSERT(false); // Not implemented
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncFileEncrypted::releaseZeroCopy(void* data, int length, int64_t offset) {
|
||||||
|
ASSERT(false); // Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t AsyncFileEncrypted::debugFD() const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamCipher::IV AsyncFileEncrypted::getIV(uint16_t block) const {
|
||||||
|
auto iv = firstBlockIV;
|
||||||
|
iv[14] = block / 256;
|
||||||
|
iv[15] = block % 256;
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::writeLastBlockToFile() {
|
||||||
|
return file->write(&writeBuffer[0], offsetInBlock, currentBlock * FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<StreamCipher::Key> AsyncFileEncrypted::key;
|
||||||
|
|
||||||
|
StreamCipher::Key AsyncFileEncrypted::getKey() {
|
||||||
|
return key.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Void> AsyncFileEncrypted::initializeKey(const Reference<IAsyncFile>& keyFile, int64_t offset) {
|
||||||
|
return AsyncFileEncryptedImpl::initializeKey(keyFile, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("fdbrpc/AsyncFileEncrypted") {
|
||||||
|
state const int bytes = FLOW_KNOBS->ENCRYPTION_BLOCK_SIZE * deterministicRandom()->randomInt(0, 1000);
|
||||||
|
state std::vector<unsigned char> writeBuffer(bytes, 0);
|
||||||
|
generateRandomData(&writeBuffer.front(), bytes);
|
||||||
|
state std::vector<unsigned char> readBuffer(bytes, 0);
|
||||||
|
ASSERT(g_network->isSimulated());
|
||||||
|
wait(AsyncFileEncrypted::initializeKey(Reference<IAsyncFile>{}));
|
||||||
|
int flags = IAsyncFile::OPEN_READWRITE | IAsyncFile::OPEN_CREATE | IAsyncFile::OPEN_ATOMIC_WRITE_AND_CREATE |
|
||||||
|
IAsyncFile::OPEN_UNBUFFERED | IAsyncFile::OPEN_ENCRYPTED | IAsyncFile::OPEN_UNCACHED |
|
||||||
|
IAsyncFile::OPEN_NO_AIO;
|
||||||
|
state Reference<IAsyncFile> file = wait(IAsyncFileSystem::filesystem()->open("/tmp/test", flags, 0600));
|
||||||
|
state int bytesWritten = 0;
|
||||||
|
while (bytesWritten < bytes) {
|
||||||
|
chunkSize = std::min(deterministicRandom()->randomInt(0, 100), bytes - bytesWritten);
|
||||||
|
wait(file->write(&writeBuffer[bytesWritten], chunkSize, bytesWritten));
|
||||||
|
bytesWritten += chunkSize;
|
||||||
|
}
|
||||||
|
wait(file->sync());
|
||||||
|
state int bytesRead = 0;
|
||||||
|
state int chunkSize;
|
||||||
|
while (bytesRead < bytes) {
|
||||||
|
chunkSize = std::min(deterministicRandom()->randomInt(0, 100), bytes - bytesRead);
|
||||||
|
int bytesReadInChunk = wait(file->read(&readBuffer[bytesRead], chunkSize, bytesRead));
|
||||||
|
ASSERT(bytesReadInChunk == chunkSize);
|
||||||
|
bytesRead += bytesReadInChunk;
|
||||||
|
}
|
||||||
|
ASSERT(writeBuffer == readBuffer);
|
||||||
|
return Void();
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* AsyncFileEncrypted.h
|
||||||
|
*
|
||||||
|
* This source file is part of the FoundationDB open source project
|
||||||
|
*
|
||||||
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDBRPC_ASYNC_FILE_ENCRYPTED_H__
|
||||||
|
#define __FDBRPC_ASYNC_FILE_ENCRYPTED_H__
|
||||||
|
|
||||||
|
#include "fdbrpc/IAsyncFile.h"
|
||||||
|
#include "flow/FastRef.h"
|
||||||
|
#include "flow/flow.h"
|
||||||
|
#include "flow/IRandom.h"
|
||||||
|
#include "flow/StreamCipher.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append-only file encrypted using AES-128-GCM.
|
||||||
|
* */
|
||||||
|
class AsyncFileEncrypted : public IAsyncFile, public ReferenceCounted<AsyncFileEncrypted> {
|
||||||
|
Reference<IAsyncFile> file;
|
||||||
|
StreamCipher::IV firstBlockIV;
|
||||||
|
StreamCipher::IV getIV(uint16_t block) const;
|
||||||
|
bool canWrite;
|
||||||
|
Future<Void> writeLastBlockToFile();
|
||||||
|
friend class AsyncFileEncryptedImpl;
|
||||||
|
static Optional<StreamCipher::Key> key;
|
||||||
|
static StreamCipher::Key getKey();
|
||||||
|
|
||||||
|
// Reading:
|
||||||
|
std::map<uint16_t, Standalone<StringRef>> readBuffers;
|
||||||
|
|
||||||
|
// Writing (append only):
|
||||||
|
std::unique_ptr<EncryptionStreamCipher> encryptor;
|
||||||
|
uint16_t currentBlock{ 0 };
|
||||||
|
int offsetInBlock{ 0 };
|
||||||
|
std::vector<unsigned char> writeBuffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncFileEncrypted(Reference<IAsyncFile>, bool canWrite);
|
||||||
|
void addref() override;
|
||||||
|
void delref() override;
|
||||||
|
Future<int> read(void* data, int length, int64_t offset) override;
|
||||||
|
Future<Void> write(void const* data, int length, int64_t offset) override;
|
||||||
|
Future<Void> zeroRange(int64_t offset, int64_t length) override;
|
||||||
|
Future<Void> truncate(int64_t size) override;
|
||||||
|
Future<Void> sync() override;
|
||||||
|
Future<Void> flush() override;
|
||||||
|
Future<int64_t> size() const override;
|
||||||
|
std::string getFilename() const override;
|
||||||
|
Future<Void> readZeroCopy(void** data, int* length, int64_t offset) override;
|
||||||
|
void releaseZeroCopy(void* data, int length, int64_t offset) override;
|
||||||
|
int64_t debugFD() const override;
|
||||||
|
static Future<Void> initializeKey(const Reference<IAsyncFile>& keyFile, int64_t offset = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,6 +8,8 @@ set(FDBRPC_SRCS
|
||||||
AsyncFileCached.actor.cpp
|
AsyncFileCached.actor.cpp
|
||||||
AsyncFileNonDurable.actor.cpp
|
AsyncFileNonDurable.actor.cpp
|
||||||
AsyncFileWriteChecker.cpp
|
AsyncFileWriteChecker.cpp
|
||||||
|
AsyncFileEncrypted.actor.cpp
|
||||||
|
AsyncFileEncrypted.h
|
||||||
FailureMonitor.actor.cpp
|
FailureMonitor.actor.cpp
|
||||||
FlowTransport.actor.cpp
|
FlowTransport.actor.cpp
|
||||||
genericactors.actor.h
|
genericactors.actor.h
|
||||||
|
|
|
@ -35,21 +35,25 @@ public:
|
||||||
virtual ~IAsyncFile();
|
virtual ~IAsyncFile();
|
||||||
// Pass these to g_network->open to get an IAsyncFile
|
// Pass these to g_network->open to get an IAsyncFile
|
||||||
enum {
|
enum {
|
||||||
// Implementation relies on the low bits being the same as the SQLite flags (this is validated by a static_assert there)
|
// Implementation relies on the low bits being the same as the SQLite flags (this is validated by a
|
||||||
OPEN_READONLY = 0x1,
|
// static_assert there)
|
||||||
OPEN_READWRITE = 0x2,
|
OPEN_READONLY = 0x1,
|
||||||
OPEN_CREATE = 0x4,
|
OPEN_READWRITE = 0x2,
|
||||||
OPEN_EXCLUSIVE = 0x10,
|
OPEN_CREATE = 0x4,
|
||||||
|
OPEN_EXCLUSIVE = 0x10,
|
||||||
|
|
||||||
// Further flag values are arbitrary bits
|
// Further flag values are arbitrary bits
|
||||||
OPEN_UNBUFFERED = 0x10000,
|
OPEN_UNBUFFERED = 0x10000,
|
||||||
OPEN_UNCACHED = 0x20000,
|
OPEN_UNCACHED = 0x20000,
|
||||||
OPEN_LOCK = 0x40000,
|
OPEN_LOCK = 0x40000,
|
||||||
OPEN_ATOMIC_WRITE_AND_CREATE = 0x80000, // A temporary file is opened, and on the first call to sync() it is atomically renamed to the given filename
|
OPEN_ATOMIC_WRITE_AND_CREATE = 0x80000, // A temporary file is opened, and on the first call to sync() it is
|
||||||
OPEN_LARGE_PAGES = 0x100000,
|
// atomically renamed to the given filename
|
||||||
OPEN_NO_AIO = 0x200000, // Don't use AsyncFileKAIO or similar implementations that rely on filesystem support for AIO
|
OPEN_LARGE_PAGES = 0x100000,
|
||||||
OPEN_CACHED_READ_ONLY = 0x400000 // AsyncFileCached opens files read/write even if you specify read only
|
OPEN_NO_AIO =
|
||||||
};
|
0x200000, // Don't use AsyncFileKAIO or similar implementations that rely on filesystem support for AIO
|
||||||
|
OPEN_CACHED_READ_ONLY = 0x400000, // AsyncFileCached opens files read/write even if you specify read only
|
||||||
|
OPEN_ENCRYPTED = 0x800000 // File is encrypted using AES-128-GCM (must be either read-only or write-only)
|
||||||
|
};
|
||||||
|
|
||||||
virtual void addref() = 0;
|
virtual void addref() = 0;
|
||||||
virtual void delref() = 0;
|
virtual void delref() = 0;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "fdbrpc/AsyncFileCached.actor.h"
|
#include "fdbrpc/AsyncFileCached.actor.h"
|
||||||
#include "fdbrpc/AsyncFileEIO.actor.h"
|
#include "fdbrpc/AsyncFileEIO.actor.h"
|
||||||
|
#include "fdbrpc/AsyncFileEncrypted.h"
|
||||||
#include "fdbrpc/AsyncFileWinASIO.actor.h"
|
#include "fdbrpc/AsyncFileWinASIO.actor.h"
|
||||||
#include "fdbrpc/AsyncFileKAIO.actor.h"
|
#include "fdbrpc/AsyncFileKAIO.actor.h"
|
||||||
#include "flow/AsioReactor.h"
|
#include "flow/AsioReactor.h"
|
||||||
|
@ -69,7 +70,11 @@ Future<Reference<class IAsyncFile>> Net2FileSystem::open(const std::string& file
|
||||||
#endif
|
#endif
|
||||||
f = Net2AsyncFile::open(filename, flags, mode, static_cast<boost::asio::io_service*> ((void*) g_network->global(INetwork::enASIOService)));
|
f = Net2AsyncFile::open(filename, flags, mode, static_cast<boost::asio::io_service*> ((void*) g_network->global(INetwork::enASIOService)));
|
||||||
if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
|
if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
|
||||||
f = map(f, [=](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
|
f = map(f, [](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
|
||||||
|
if (flags & IAsyncFile::OPEN_ENCRYPTED)
|
||||||
|
f = map(f, [flags](Reference<IAsyncFile> r) {
|
||||||
|
return Reference<IAsyncFile>(new AsyncFileEncrypted(r, flags & IAsyncFile::OPEN_READWRITE));
|
||||||
|
});
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "flow/Util.h"
|
#include "flow/Util.h"
|
||||||
#include "fdbrpc/IAsyncFile.h"
|
#include "fdbrpc/IAsyncFile.h"
|
||||||
#include "fdbrpc/AsyncFileCached.actor.h"
|
#include "fdbrpc/AsyncFileCached.actor.h"
|
||||||
|
#include "fdbrpc/AsyncFileEncrypted.h"
|
||||||
#include "fdbrpc/AsyncFileNonDurable.actor.h"
|
#include "fdbrpc/AsyncFileNonDurable.actor.h"
|
||||||
#include "flow/crc32c.h"
|
#include "flow/crc32c.h"
|
||||||
#include "fdbrpc/TraceFileIO.h"
|
#include "fdbrpc/TraceFileIO.h"
|
||||||
|
@ -2060,7 +2061,11 @@ Future<Reference<class IAsyncFile>> Sim2FileSystem::open(const std::string& file
|
||||||
}
|
}
|
||||||
Future<Reference<IAsyncFile>> f = AsyncFileDetachable::open( machineCache[actualFilename] );
|
Future<Reference<IAsyncFile>> f = AsyncFileDetachable::open( machineCache[actualFilename] );
|
||||||
if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
|
if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
|
||||||
f = map(f, [=](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
|
f = map(f, [](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
|
||||||
|
if (flags & IAsyncFile::OPEN_ENCRYPTED)
|
||||||
|
f = map(f, [flags](Reference<IAsyncFile> r) {
|
||||||
|
return Reference<IAsyncFile>(new AsyncFileEncrypted(r, flags & IAsyncFile::OPEN_READWRITE));
|
||||||
|
});
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -132,8 +132,7 @@ target_link_libraries(flow PRIVATE ${FLOW_LIBS})
|
||||||
if(USE_VALGRIND)
|
if(USE_VALGRIND)
|
||||||
target_link_libraries(flow PUBLIC Valgrind)
|
target_link_libraries(flow PUBLIC Valgrind)
|
||||||
endif()
|
endif()
|
||||||
# TODO(atn34) Re-enable TLS for OPEN_FOR_IDE build once #2201 is resolved
|
if(NOT WITH_TLS)
|
||||||
if(NOT WITH_TLS OR OPEN_FOR_IDE)
|
|
||||||
target_compile_definitions(flow PUBLIC TLS_DISABLED)
|
target_compile_definitions(flow PUBLIC TLS_DISABLED)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(flow PUBLIC OpenSSL::SSL)
|
target_link_libraries(flow PUBLIC OpenSSL::SSL)
|
||||||
|
|
|
@ -121,6 +121,10 @@ void FlowKnobs::initialize(bool randomize, bool isSimulated) {
|
||||||
init( EIO_MAX_PARALLELISM, 4 );
|
init( EIO_MAX_PARALLELISM, 4 );
|
||||||
init( EIO_USE_ODIRECT, 0 );
|
init( EIO_USE_ODIRECT, 0 );
|
||||||
|
|
||||||
|
//AsyncFileEncrypted
|
||||||
|
init( ENCRYPTION_BLOCK_SIZE, 4096 );
|
||||||
|
init( MAX_DECRYPTED_BLOCKS, 10 );
|
||||||
|
|
||||||
//AsyncFileKAIO
|
//AsyncFileKAIO
|
||||||
init( MAX_OUTSTANDING, 64 );
|
init( MAX_OUTSTANDING, 64 );
|
||||||
init( MIN_SUBMIT, 10 );
|
init( MIN_SUBMIT, 10 );
|
||||||
|
|
|
@ -138,6 +138,10 @@ public:
|
||||||
int EIO_MAX_PARALLELISM;
|
int EIO_MAX_PARALLELISM;
|
||||||
int EIO_USE_ODIRECT;
|
int EIO_USE_ODIRECT;
|
||||||
|
|
||||||
|
// AsyncFileEncrypted
|
||||||
|
int ENCRYPTION_BLOCK_SIZE;
|
||||||
|
int MAX_DECRYPTED_BLOCKS;
|
||||||
|
|
||||||
//AsyncFileKAIO
|
//AsyncFileKAIO
|
||||||
int MAX_OUTSTANDING;
|
int MAX_OUTSTANDING;
|
||||||
int MIN_SUBMIT;
|
int MIN_SUBMIT;
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
EncryptionStreamCipher::EncryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv)
|
EncryptionStreamCipher::EncryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv)
|
||||||
: ctx(EVP_CIPHER_CTX_new()) {
|
: ctx(EVP_CIPHER_CTX_new()) {
|
||||||
EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, nullptr);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size(), nullptr);
|
||||||
EVP_EncryptInit_ex(ctx, nullptr, nullptr, key, iv);
|
EVP_EncryptInit_ex(ctx, nullptr, nullptr, key.data(), iv.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptionStreamCipher::~EncryptionStreamCipher() {
|
EncryptionStreamCipher::~EncryptionStreamCipher() {
|
||||||
|
@ -46,12 +46,12 @@ StringRef EncryptionStreamCipher::finish(Arena& arena) {
|
||||||
return StringRef(ciphertext, bytes);
|
return StringRef(ciphertext, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptionStreamCipher::DecryptionStreamCipher(unsigned char const* key, unsigned char const* iv)
|
DecryptionStreamCipher::DecryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv)
|
||||||
: ctx(EVP_CIPHER_CTX_new()) {
|
: ctx(EVP_CIPHER_CTX_new()) {
|
||||||
|
|
||||||
EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, nullptr);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size(), nullptr);
|
||||||
EVP_DecryptInit_ex(ctx, nullptr, nullptr, key, iv);
|
EVP_DecryptInit_ex(ctx, nullptr, nullptr, key.data(), iv.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptionStreamCipher::~DecryptionStreamCipher() {
|
DecryptionStreamCipher::~DecryptionStreamCipher() {
|
||||||
|
@ -77,10 +77,10 @@ StringRef DecryptionStreamCipher::finish(Arena& arena) {
|
||||||
void forceLinkStreamCipherTests() {}
|
void forceLinkStreamCipherTests() {}
|
||||||
|
|
||||||
TEST_CASE("flow/StreamCipher") {
|
TEST_CASE("flow/StreamCipher") {
|
||||||
std::array<unsigned char, 16> key;
|
StreamCipher::Key key;
|
||||||
generateRandomData(key.data(), key.size());
|
generateRandomData(key.data(), key.size());
|
||||||
|
|
||||||
std::array<unsigned char, 12> iv;
|
StreamCipher::IV iv;
|
||||||
generateRandomData(iv.data(), iv.size());
|
generateRandomData(iv.data(), iv.size());
|
||||||
|
|
||||||
Arena arena;
|
Arena arena;
|
||||||
|
@ -93,7 +93,7 @@ TEST_CASE("flow/StreamCipher") {
|
||||||
.detail("PlaintextSize", plaintext.size())
|
.detail("PlaintextSize", plaintext.size())
|
||||||
.detail("AESBlockSize", AES_BLOCK_SIZE);
|
.detail("AESBlockSize", AES_BLOCK_SIZE);
|
||||||
{
|
{
|
||||||
EncryptionStreamCipher encryptor(key.data(), iv.data());
|
EncryptionStreamCipher encryptor(key, iv);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int encryptedOffset = 0;
|
int encryptedOffset = 0;
|
||||||
while (index < plaintext.size()) {
|
while (index < plaintext.size()) {
|
||||||
|
@ -113,7 +113,7 @@ TEST_CASE("flow/StreamCipher") {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
DecryptionStreamCipher decryptor(key.data(), iv.data());
|
DecryptionStreamCipher decryptor(key, iv);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int decryptedOffset = 0;
|
int decryptedOffset = 0;
|
||||||
while (index < plaintext.size()) {
|
while (index < plaintext.size()) {
|
||||||
|
|
|
@ -30,10 +30,15 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace StreamCipher {
|
||||||
|
using Key = std::array<unsigned char, 16>;
|
||||||
|
using IV = std::array<unsigned char, 16>;
|
||||||
|
}; // namespace StreamCipher
|
||||||
|
|
||||||
class EncryptionStreamCipher final : NonCopyable, public ReferenceCounted<EncryptionStreamCipher> {
|
class EncryptionStreamCipher final : NonCopyable, public ReferenceCounted<EncryptionStreamCipher> {
|
||||||
EVP_CIPHER_CTX* ctx;
|
EVP_CIPHER_CTX* ctx;
|
||||||
public:
|
public:
|
||||||
EncryptionStreamCipher(unsigned char const* key, unsigned char const* salt);
|
EncryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv);
|
||||||
~EncryptionStreamCipher();
|
~EncryptionStreamCipher();
|
||||||
StringRef encrypt(unsigned char const* plaintext, int len, Arena&);
|
StringRef encrypt(unsigned char const* plaintext, int len, Arena&);
|
||||||
StringRef finish(Arena&);
|
StringRef finish(Arena&);
|
||||||
|
@ -42,7 +47,7 @@ public:
|
||||||
class DecryptionStreamCipher final : NonCopyable, public ReferenceCounted<DecryptionStreamCipher> {
|
class DecryptionStreamCipher final : NonCopyable, public ReferenceCounted<DecryptionStreamCipher> {
|
||||||
EVP_CIPHER_CTX* ctx;
|
EVP_CIPHER_CTX* ctx;
|
||||||
public:
|
public:
|
||||||
DecryptionStreamCipher(unsigned char const* key, unsigned char const* salt);
|
DecryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv);
|
||||||
~DecryptionStreamCipher();
|
~DecryptionStreamCipher();
|
||||||
StringRef decrypt(unsigned char const* ciphertext, int len, Arena&);
|
StringRef decrypt(unsigned char const* ciphertext, int len, Arena&);
|
||||||
StringRef finish(Arena&);
|
StringRef finish(Arena&);
|
||||||
|
|
Loading…
Reference in New Issue