2021-07-11 09:22:30 +00:00
|
|
|
#include <IO/ReadBufferFromEncryptedFile.h>
|
|
|
|
|
|
|
|
#if USE_SSL
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int ARGUMENT_OUT_OF_BOUND;
|
|
|
|
}
|
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
using InitVector = FileEncryption::InitVector;
|
|
|
|
|
2021-07-11 09:22:30 +00:00
|
|
|
ReadBufferFromEncryptedFile::ReadBufferFromEncryptedFile(
|
2021-07-11 19:26:39 +00:00
|
|
|
size_t buffer_size_,
|
2021-07-11 09:22:30 +00:00
|
|
|
std::unique_ptr<ReadBufferFromFileBase> in_,
|
2021-07-11 19:26:39 +00:00
|
|
|
const String & key_,
|
|
|
|
const InitVector & init_vector_)
|
|
|
|
: ReadBufferFromFileBase(buffer_size_, nullptr, 0)
|
2021-07-11 09:22:30 +00:00
|
|
|
, in(std::move(in_))
|
2021-07-11 19:26:39 +00:00
|
|
|
, encrypted_buffer(buffer_size_)
|
|
|
|
, encryptor(key_, init_vector_)
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
/// We should start reading from `in` at the offset == InitVector::kSize.
|
|
|
|
need_seek = true;
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
off_t ReadBufferFromEncryptedFile::seek(off_t off, int whence)
|
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
off_t new_pos;
|
|
|
|
if (whence == SEEK_SET)
|
|
|
|
{
|
|
|
|
if (off < 0)
|
|
|
|
throw Exception("SEEK_SET underflow: off = " + std::to_string(off), ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
new_pos = off;
|
|
|
|
}
|
|
|
|
else if (whence == SEEK_CUR)
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
|
|
|
if (off < 0 && -off > getPosition())
|
|
|
|
throw Exception("SEEK_CUR shift out of bounds", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
2021-07-11 19:26:39 +00:00
|
|
|
new_pos = getPosition() + off;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw Exception("ReadBufferFromFileEncrypted::seek expects SEEK_SET or SEEK_CUR as whence", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
2021-07-11 09:22:30 +00:00
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
if ((offset - static_cast<off_t>(working_buffer.size()) <= new_pos) && (new_pos <= offset) && !need_seek)
|
|
|
|
{
|
|
|
|
/// Position is still inside buffer.
|
|
|
|
pos = working_buffer.end() - offset + new_pos;
|
|
|
|
assert(pos >= working_buffer.begin());
|
|
|
|
assert(pos <= working_buffer.end());
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
2021-07-11 19:26:39 +00:00
|
|
|
else
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
need_seek = true;
|
|
|
|
offset = new_pos;
|
2021-07-11 09:22:30 +00:00
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
/// No more reading from the current working buffer until next() is called.
|
|
|
|
pos = working_buffer.end();
|
|
|
|
assert(!hasPendingData());
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
/// The encryptor always needs to know what the current offset is.
|
|
|
|
encryptor.setOffset(new_pos);
|
|
|
|
|
|
|
|
return new_pos;
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
off_t ReadBufferFromEncryptedFile::getPosition()
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
return offset - available();
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
bool ReadBufferFromEncryptedFile::nextImpl()
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
if (need_seek)
|
|
|
|
{
|
|
|
|
off_t raw_offset = offset + InitVector::kSize;
|
|
|
|
if (in->seek(raw_offset, SEEK_SET) != raw_offset)
|
|
|
|
return false;
|
|
|
|
need_seek = false;
|
|
|
|
}
|
2021-07-11 09:22:30 +00:00
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
if (in->eof())
|
|
|
|
return false;
|
2021-07-11 09:22:30 +00:00
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
/// Read up to the size of `encrypted_buffer`.
|
|
|
|
size_t bytes_read = 0;
|
|
|
|
while (bytes_read < encrypted_buffer.size() && !in->eof())
|
2021-07-11 09:22:30 +00:00
|
|
|
{
|
2021-07-11 19:26:39 +00:00
|
|
|
bytes_read += in->read(encrypted_buffer.data() + bytes_read, encrypted_buffer.size() - bytes_read);
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 19:26:39 +00:00
|
|
|
/// The used cipher algorithms generate the same number of bytes in output as it were in input,
|
|
|
|
/// so after deciphering the numbers of bytes will be still `bytes_read`.
|
|
|
|
working_buffer.resize(bytes_read);
|
|
|
|
encryptor.decrypt(encrypted_buffer.data(), bytes_read, working_buffer.begin());
|
2021-07-11 09:22:30 +00:00
|
|
|
|
|
|
|
pos = working_buffer.begin();
|
2021-07-11 19:26:39 +00:00
|
|
|
return true;
|
2021-07-11 09:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|