2021-07-11 09:22:30 +00:00
|
|
|
#include <Disks/DiskEncrypted.h>
|
2021-05-18 20:48:16 +00:00
|
|
|
|
|
|
|
#if USE_SSL
|
2021-07-11 09:22:30 +00:00
|
|
|
#include <Disks/DiskFactory.h>
|
|
|
|
#include <IO/FileEncryptionCommon.h>
|
|
|
|
#include <IO/ReadBufferFromEncryptedFile.h>
|
|
|
|
#include <IO/WriteBufferFromEncryptedFile.h>
|
2021-05-14 21:52:51 +00:00
|
|
|
|
2021-05-17 16:58:51 +00:00
|
|
|
|
2021-05-13 06:37:05 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int INCORRECT_DISK_INDEX;
|
|
|
|
extern const int UNKNOWN_ELEMENT_IN_CONFIG;
|
2021-07-11 09:22:30 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2021-05-13 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
using DiskEncryptedPtr = std::shared_ptr<DiskEncrypted>;
|
2021-05-16 22:35:20 +00:00
|
|
|
using namespace FileEncryption;
|
2021-05-13 06:37:05 +00:00
|
|
|
|
|
|
|
class DiskEncryptedReservation : public IReservation
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DiskEncryptedReservation(DiskEncryptedPtr disk_, std::unique_ptr<IReservation> reservation_)
|
|
|
|
: disk(std::move(disk_)), reservation(std::move(reservation_))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
UInt64 getSize() const override { return reservation->getSize(); }
|
|
|
|
|
2021-05-19 22:06:25 +00:00
|
|
|
DiskPtr getDisk(size_t i) const override
|
|
|
|
{
|
2021-05-13 06:37:05 +00:00
|
|
|
if (i != 0)
|
|
|
|
throw Exception("Can't use i != 0 with single disk reservation", ErrorCodes::INCORRECT_DISK_INDEX);
|
|
|
|
return disk;
|
|
|
|
}
|
|
|
|
|
|
|
|
Disks getDisks() const override { return {disk}; }
|
|
|
|
|
|
|
|
void update(UInt64 new_size) override { reservation->update(new_size); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
DiskEncryptedPtr disk;
|
|
|
|
std::unique_ptr<IReservation> reservation;
|
|
|
|
};
|
|
|
|
|
|
|
|
ReservationPtr DiskEncrypted::reserve(UInt64 bytes)
|
|
|
|
{
|
2021-05-14 21:52:51 +00:00
|
|
|
auto reservation = delegate->reserve(bytes);
|
2021-05-13 06:37:05 +00:00
|
|
|
if (!reservation)
|
|
|
|
return {};
|
|
|
|
return std::make_unique<DiskEncryptedReservation>(std::static_pointer_cast<DiskEncrypted>(shared_from_this()), std::move(reservation));
|
|
|
|
}
|
|
|
|
|
2021-07-11 09:22:30 +00:00
|
|
|
DiskEncrypted::DiskEncrypted(const String & name_, DiskPtr disk_, const String & key_, const String & path_)
|
|
|
|
: DiskDecorator(disk_)
|
|
|
|
, name(name_), key(key_), disk_path(path_)
|
|
|
|
, disk_absolute_path(delegate->getPath() + disk_path)
|
|
|
|
{
|
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiskEncrypted::initialize()
|
|
|
|
{
|
|
|
|
// use wrapped_disk as an EncryptedDisk store
|
|
|
|
if (disk_path.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (disk_path.back() != '/')
|
|
|
|
throw Exception("Disk path must ends with '/', but '" + disk_path + "' doesn't.", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
delegate->createDirectories(disk_path);
|
|
|
|
}
|
|
|
|
|
2021-05-13 06:37:05 +00:00
|
|
|
std::unique_ptr<ReadBufferFromFileBase> DiskEncrypted::readFile(
|
|
|
|
const String & path,
|
|
|
|
size_t buf_size,
|
|
|
|
size_t estimated_size,
|
|
|
|
size_t aio_threshold,
|
|
|
|
size_t mmap_threshold,
|
2021-05-13 16:21:45 +00:00
|
|
|
MMappedFileCache * mmap_cache) const
|
|
|
|
{
|
|
|
|
auto wrapped_path = wrappedPath(path);
|
2021-05-14 21:52:51 +00:00
|
|
|
auto buffer = delegate->readFile(wrapped_path, buf_size, estimated_size, aio_threshold, mmap_threshold, mmap_cache);
|
2021-05-16 22:35:20 +00:00
|
|
|
|
2021-05-18 20:02:19 +00:00
|
|
|
String iv;
|
2021-05-14 21:52:51 +00:00
|
|
|
size_t offset = 0;
|
2021-05-16 22:35:20 +00:00
|
|
|
|
2021-05-17 16:15:21 +00:00
|
|
|
if (exists(path) && getFileSize(path))
|
2021-05-14 21:52:51 +00:00
|
|
|
{
|
2021-07-11 09:22:30 +00:00
|
|
|
iv = readIV(kIVSize, *buffer);
|
2021-05-14 21:52:51 +00:00
|
|
|
offset = kIVSize;
|
|
|
|
}
|
2021-05-18 20:02:19 +00:00
|
|
|
else
|
2021-07-11 09:22:30 +00:00
|
|
|
iv = randomString(kIVSize);
|
2021-05-16 22:35:20 +00:00
|
|
|
|
2021-07-11 09:22:30 +00:00
|
|
|
return std::make_unique<ReadBufferFromEncryptedFile>(buf_size, std::move(buffer), iv, key, offset);
|
2021-05-13 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 09:22:30 +00:00
|
|
|
std::unique_ptr<WriteBufferFromFileBase> DiskEncrypted::writeFile(const String & path, size_t buf_size, WriteMode mode)
|
2021-05-13 16:21:45 +00:00
|
|
|
{
|
2021-05-18 20:02:19 +00:00
|
|
|
String iv;
|
2021-07-11 09:22:30 +00:00
|
|
|
size_t start_offset = 0;
|
2021-05-13 16:21:45 +00:00
|
|
|
auto wrapped_path = wrappedPath(path);
|
2021-05-16 22:35:20 +00:00
|
|
|
|
2021-05-18 20:02:19 +00:00
|
|
|
if (mode == WriteMode::Append && exists(path) && getFileSize(path))
|
2021-05-17 16:15:21 +00:00
|
|
|
{
|
2021-05-14 21:52:51 +00:00
|
|
|
auto read_buffer = delegate->readFile(wrapped_path, kIVSize);
|
2021-07-11 09:22:30 +00:00
|
|
|
iv = readIV(kIVSize, *read_buffer);
|
|
|
|
start_offset = getFileSize(path);
|
2021-05-14 21:52:51 +00:00
|
|
|
}
|
2021-05-18 20:02:19 +00:00
|
|
|
else
|
2021-07-11 09:22:30 +00:00
|
|
|
iv = randomString(kIVSize);
|
2021-05-16 22:35:20 +00:00
|
|
|
|
2021-05-14 21:52:51 +00:00
|
|
|
auto buffer = delegate->writeFile(wrapped_path, buf_size, mode);
|
2021-07-11 09:22:30 +00:00
|
|
|
return std::make_unique<WriteBufferFromEncryptedFile>(buf_size, std::move(buffer), iv, key, start_offset);
|
2021-05-14 21:52:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t DiskEncrypted::getFileSize(const String & path) const
|
|
|
|
{
|
|
|
|
auto wrapped_path = wrappedPath(path);
|
|
|
|
size_t size = delegate->getFileSize(wrapped_path);
|
|
|
|
return size > kIVSize ? (size - kIVSize) : 0;
|
2021-05-13 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
2021-05-13 16:21:45 +00:00
|
|
|
void DiskEncrypted::truncateFile(const String & path, size_t size)
|
|
|
|
{
|
|
|
|
auto wrapped_path = wrappedPath(path);
|
2021-05-14 21:52:51 +00:00
|
|
|
delegate->truncateFile(wrapped_path, size ? (size + kIVSize) : 0);
|
2021-05-13 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
2021-05-13 16:21:45 +00:00
|
|
|
SyncGuardPtr DiskEncrypted::getDirectorySyncGuard(const String & path) const
|
|
|
|
{
|
|
|
|
auto wrapped_path = wrappedPath(path);
|
2021-05-14 21:52:51 +00:00
|
|
|
return delegate->getDirectorySyncGuard(wrapped_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiskEncrypted::applyNewSettings(
|
|
|
|
const Poco::Util::AbstractConfiguration & config,
|
2021-06-18 05:36:50 +00:00
|
|
|
ContextPtr /*context*/,
|
2021-05-14 21:52:51 +00:00
|
|
|
const String & config_prefix,
|
|
|
|
const DisksMap & map)
|
|
|
|
{
|
|
|
|
String wrapped_disk_name = config.getString(config_prefix + ".disk", "");
|
|
|
|
if (wrapped_disk_name.empty())
|
|
|
|
throw Exception("The wrapped disk name can not be empty. An encrypted disk is a wrapper over another disk. "
|
|
|
|
"Disk " + name, ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
|
|
|
|
|
|
|
key = config.getString(config_prefix + ".key", "");
|
|
|
|
if (key.empty())
|
|
|
|
throw Exception("Encrypted disk key can not be empty. Disk " + name, ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
|
|
|
|
|
|
|
auto wrapped_disk = map.find(wrapped_disk_name);
|
|
|
|
if (wrapped_disk == map.end())
|
|
|
|
throw Exception("The wrapped disk must have been announced earlier. No disk with name " + wrapped_disk_name + ". Disk " + name,
|
|
|
|
ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
|
|
|
delegate = wrapped_disk->second;
|
|
|
|
|
|
|
|
disk_path = config.getString(config_prefix + ".path", "");
|
|
|
|
initialize();
|
2021-05-13 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void registerDiskEncrypted(DiskFactory & factory)
|
|
|
|
{
|
|
|
|
auto creator = [](const String & name,
|
|
|
|
const Poco::Util::AbstractConfiguration & config,
|
|
|
|
const String & config_prefix,
|
2021-06-18 05:36:50 +00:00
|
|
|
ContextPtr /*context*/,
|
2021-05-18 20:20:51 +00:00
|
|
|
const DisksMap & map) -> DiskPtr {
|
2021-05-13 06:46:11 +00:00
|
|
|
|
2021-05-13 06:37:05 +00:00
|
|
|
String wrapped_disk_name = config.getString(config_prefix + ".disk", "");
|
|
|
|
if (wrapped_disk_name.empty())
|
|
|
|
throw Exception("The wrapped disk name can not be empty. An encrypted disk is a wrapper over another disk. "
|
|
|
|
"Disk " + name, ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
|
|
|
|
|
|
|
String key = config.getString(config_prefix + ".key", "");
|
|
|
|
if (key.empty())
|
|
|
|
throw Exception("Encrypted disk key can not be empty. Disk " + name, ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
2021-07-11 09:22:30 +00:00
|
|
|
if (key.size() != cipherKeyLength(defaultCipher()))
|
|
|
|
throw Exception("Expected key with size " + std::to_string(cipherKeyLength(defaultCipher())) + ", got key with size " + std::to_string(key.size()),
|
2021-05-18 20:20:51 +00:00
|
|
|
ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
2021-05-13 06:37:05 +00:00
|
|
|
|
2021-05-13 06:46:11 +00:00
|
|
|
auto wrapped_disk = map.find(wrapped_disk_name);
|
|
|
|
if (wrapped_disk == map.end())
|
2021-05-13 06:37:05 +00:00
|
|
|
throw Exception("The wrapped disk must have been announced earlier. No disk with name " + wrapped_disk_name + ". Disk " + name,
|
|
|
|
ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG);
|
|
|
|
|
2021-05-13 16:21:45 +00:00
|
|
|
String relative_path = config.getString(config_prefix + ".path", "");
|
|
|
|
|
|
|
|
return std::make_shared<DiskEncrypted>(name, wrapped_disk->second, key, relative_path);
|
2021-05-13 06:37:05 +00:00
|
|
|
};
|
|
|
|
factory.registerDiskType("encrypted", creator);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2021-05-18 20:48:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
#endif
|