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
|
||||
AsyncFileNonDurable.actor.cpp
|
||||
AsyncFileWriteChecker.cpp
|
||||
AsyncFileEncrypted.actor.cpp
|
||||
AsyncFileEncrypted.h
|
||||
FailureMonitor.actor.cpp
|
||||
FlowTransport.actor.cpp
|
||||
genericactors.actor.h
|
||||
|
|
|
@ -35,21 +35,25 @@ public:
|
|||
virtual ~IAsyncFile();
|
||||
// Pass these to g_network->open to get an IAsyncFile
|
||||
enum {
|
||||
// Implementation relies on the low bits being the same as the SQLite flags (this is validated by a static_assert there)
|
||||
OPEN_READONLY = 0x1,
|
||||
OPEN_READWRITE = 0x2,
|
||||
OPEN_CREATE = 0x4,
|
||||
OPEN_EXCLUSIVE = 0x10,
|
||||
|
||||
// Implementation relies on the low bits being the same as the SQLite flags (this is validated by a
|
||||
// static_assert there)
|
||||
OPEN_READONLY = 0x1,
|
||||
OPEN_READWRITE = 0x2,
|
||||
OPEN_CREATE = 0x4,
|
||||
OPEN_EXCLUSIVE = 0x10,
|
||||
|
||||
// Further flag values are arbitrary bits
|
||||
OPEN_UNBUFFERED = 0x10000,
|
||||
OPEN_UNCACHED = 0x20000,
|
||||
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_LARGE_PAGES = 0x100000,
|
||||
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_UNBUFFERED = 0x10000,
|
||||
OPEN_UNCACHED = 0x20000,
|
||||
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_LARGE_PAGES = 0x100000,
|
||||
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 delref() = 0;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "fdbrpc/AsyncFileCached.actor.h"
|
||||
#include "fdbrpc/AsyncFileEIO.actor.h"
|
||||
#include "fdbrpc/AsyncFileEncrypted.h"
|
||||
#include "fdbrpc/AsyncFileWinASIO.actor.h"
|
||||
#include "fdbrpc/AsyncFileKAIO.actor.h"
|
||||
#include "flow/AsioReactor.h"
|
||||
|
@ -69,7 +70,11 @@ Future<Reference<class IAsyncFile>> Net2FileSystem::open(const std::string& file
|
|||
#endif
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "flow/Util.h"
|
||||
#include "fdbrpc/IAsyncFile.h"
|
||||
#include "fdbrpc/AsyncFileCached.actor.h"
|
||||
#include "fdbrpc/AsyncFileEncrypted.h"
|
||||
#include "fdbrpc/AsyncFileNonDurable.actor.h"
|
||||
#include "flow/crc32c.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] );
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -132,8 +132,7 @@ target_link_libraries(flow PRIVATE ${FLOW_LIBS})
|
|||
if(USE_VALGRIND)
|
||||
target_link_libraries(flow PUBLIC Valgrind)
|
||||
endif()
|
||||
# TODO(atn34) Re-enable TLS for OPEN_FOR_IDE build once #2201 is resolved
|
||||
if(NOT WITH_TLS OR OPEN_FOR_IDE)
|
||||
if(NOT WITH_TLS)
|
||||
target_compile_definitions(flow PUBLIC TLS_DISABLED)
|
||||
else()
|
||||
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_USE_ODIRECT, 0 );
|
||||
|
||||
//AsyncFileEncrypted
|
||||
init( ENCRYPTION_BLOCK_SIZE, 4096 );
|
||||
init( MAX_DECRYPTED_BLOCKS, 10 );
|
||||
|
||||
//AsyncFileKAIO
|
||||
init( MAX_OUTSTANDING, 64 );
|
||||
init( MIN_SUBMIT, 10 );
|
||||
|
|
|
@ -138,6 +138,10 @@ public:
|
|||
int EIO_MAX_PARALLELISM;
|
||||
int EIO_USE_ODIRECT;
|
||||
|
||||
// AsyncFileEncrypted
|
||||
int ENCRYPTION_BLOCK_SIZE;
|
||||
int MAX_DECRYPTED_BLOCKS;
|
||||
|
||||
//AsyncFileKAIO
|
||||
int MAX_OUTSTANDING;
|
||||
int MIN_SUBMIT;
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
EncryptionStreamCipher::EncryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv)
|
||||
: ctx(EVP_CIPHER_CTX_new()) {
|
||||
EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, nullptr);
|
||||
EVP_EncryptInit_ex(ctx, nullptr, nullptr, key, iv);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size(), nullptr);
|
||||
EVP_EncryptInit_ex(ctx, nullptr, nullptr, key.data(), iv.data());
|
||||
}
|
||||
|
||||
EncryptionStreamCipher::~EncryptionStreamCipher() {
|
||||
|
@ -46,12 +46,12 @@ StringRef EncryptionStreamCipher::finish(Arena& arena) {
|
|||
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()) {
|
||||
|
||||
EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, nullptr);
|
||||
EVP_DecryptInit_ex(ctx, nullptr, nullptr, key, iv);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size(), nullptr);
|
||||
EVP_DecryptInit_ex(ctx, nullptr, nullptr, key.data(), iv.data());
|
||||
}
|
||||
|
||||
DecryptionStreamCipher::~DecryptionStreamCipher() {
|
||||
|
@ -77,10 +77,10 @@ StringRef DecryptionStreamCipher::finish(Arena& arena) {
|
|||
void forceLinkStreamCipherTests() {}
|
||||
|
||||
TEST_CASE("flow/StreamCipher") {
|
||||
std::array<unsigned char, 16> key;
|
||||
StreamCipher::Key key;
|
||||
generateRandomData(key.data(), key.size());
|
||||
|
||||
std::array<unsigned char, 12> iv;
|
||||
StreamCipher::IV iv;
|
||||
generateRandomData(iv.data(), iv.size());
|
||||
|
||||
Arena arena;
|
||||
|
@ -93,7 +93,7 @@ TEST_CASE("flow/StreamCipher") {
|
|||
.detail("PlaintextSize", plaintext.size())
|
||||
.detail("AESBlockSize", AES_BLOCK_SIZE);
|
||||
{
|
||||
EncryptionStreamCipher encryptor(key.data(), iv.data());
|
||||
EncryptionStreamCipher encryptor(key, iv);
|
||||
int index = 0;
|
||||
int encryptedOffset = 0;
|
||||
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 decryptedOffset = 0;
|
||||
while (index < plaintext.size()) {
|
||||
|
|
|
@ -30,10 +30,15 @@
|
|||
#include <string>
|
||||
#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> {
|
||||
EVP_CIPHER_CTX* ctx;
|
||||
public:
|
||||
EncryptionStreamCipher(unsigned char const* key, unsigned char const* salt);
|
||||
EncryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv);
|
||||
~EncryptionStreamCipher();
|
||||
StringRef encrypt(unsigned char const* plaintext, int len, Arena&);
|
||||
StringRef finish(Arena&);
|
||||
|
@ -42,7 +47,7 @@ public:
|
|||
class DecryptionStreamCipher final : NonCopyable, public ReferenceCounted<DecryptionStreamCipher> {
|
||||
EVP_CIPHER_CTX* ctx;
|
||||
public:
|
||||
DecryptionStreamCipher(unsigned char const* key, unsigned char const* salt);
|
||||
DecryptionStreamCipher(const StreamCipher::Key& key, const StreamCipher::IV& iv);
|
||||
~DecryptionStreamCipher();
|
||||
StringRef decrypt(unsigned char const* ciphertext, int len, Arena&);
|
||||
StringRef finish(Arena&);
|
||||
|
|
Loading…
Reference in New Issue