@ -12,17 +12,69 @@
# include <cctype>
# include <iostream>
# include "env/env_encryption_ctr.h"
# include "monitoring/perf_context_imp.h"
# include "rocksdb/convenience.h"
# include "util/aligned_buffer.h"
# include "util/coding.h"
# include "util/random.h"
# include "util/string_util.h"
# endif
namespace ROCKSDB_NAMESPACE {
# ifndef ROCKSDB_LITE
static constexpr char kROT13CipherName [ ] = " ROT13 " ;
static constexpr char kCTRProviderName [ ] = " CTR " ;
Status BlockCipher : : CreateFromString ( const ConfigOptions & /*config_options*/ ,
const std : : string & value ,
std : : shared_ptr < BlockCipher > * result ) {
std : : string id = value ;
size_t colon = value . find ( ' : ' ) ;
if ( colon ! = std : : string : : npos ) {
id = value . substr ( 0 , colon ) ;
}
if ( id = = kROT13CipherName ) {
if ( colon ! = std : : string : : npos ) {
size_t block_size = ParseSizeT ( value . substr ( colon + 1 ) ) ;
result - > reset ( new ROT13BlockCipher ( block_size ) ) ;
} else {
result - > reset ( new ROT13BlockCipher ( 32 ) ) ;
}
return Status : : OK ( ) ;
} else {
return Status : : NotSupported ( " Could not find cipher " , value ) ;
}
}
Status EncryptionProvider : : CreateFromString (
const ConfigOptions & /*config_options*/ , const std : : string & value ,
std : : shared_ptr < EncryptionProvider > * result ) {
std : : string id = value ;
bool is_test = StartsWith ( value , " test:// " ) ;
Status status = Status : : OK ( ) ;
if ( is_test ) {
id = value . substr ( strlen ( " test:// " ) ) ;
}
if ( id = = kCTRProviderName ) {
result - > reset ( new CTREncryptionProvider ( ) ) ;
} else if ( is_test ) {
result - > reset ( new CTREncryptionProvider ( ) ) ;
} else {
return Status : : NotSupported ( " Could not find provider " , value ) ;
}
if ( status . ok ( ) & & is_test ) {
status = result - > get ( ) - > TEST_Initialize ( ) ;
}
return status ;
}
std : : shared_ptr < EncryptionProvider > EncryptionProvider : : NewCTRProvider (
const std : : shared_ptr < BlockCipher > & cipher ) {
return std : : make_shared < CTREncryptionProvider > ( cipher ) ;
}
// Read up to "n" bytes from the file. "scratch[0..n-1]" may be
// written by this routine. Sets "*result" to the data that was
@ -361,9 +413,221 @@ Status EncryptedRandomRWFile::Close() { return file_->Close(); }
// EncryptedEnv implements an Env wrapper that adds encryption to files stored
// on disk.
class EncryptedEnv : public EnvWrapper {
class EncryptedEnvImpl : public EnvWrapper {
// Returns the raw encryption provider that should be used to write the input
// encrypted file. If there is no such provider, NotFound is returned.
Status GetWritableProvider ( const std : : string & /*fname*/ ,
EncryptionProvider * * result ) {
if ( provider_ ) {
* result = provider_ . get ( ) ;
return Status : : OK ( ) ;
} else {
* result = nullptr ;
return Status : : NotFound ( " No WriteProvider specified " ) ;
}
}
// Returns the raw encryption provider that should be used to read the input
// encrypted file. If there is no such provider, NotFound is returned.
Status GetReadableProvider ( const std : : string & /*fname*/ ,
EncryptionProvider * * result ) {
if ( provider_ ) {
* result = provider_ . get ( ) ;
return Status : : OK ( ) ;
} else {
* result = nullptr ;
return Status : : NotFound ( " No Provider specified " ) ;
}
}
// Creates a CipherStream for the underlying file/name using the options
// If a writable provider is found and encryption is enabled, uses
// this provider to create a cipher stream.
// @param fname Name of the writable file
// @param underlying The underlying "raw" file
// @param options Options for creating the file/cipher
// @param prefix_length Returns the length of the encryption prefix used for
// this file
// @param stream Returns the cipher stream to use for this file if it
// should be encrypted
// @return OK on success, non-OK on failure.
template < class TypeFile >
Status CreateWritableCipherStream (
const std : : string & fname , const std : : unique_ptr < TypeFile > & underlying ,
const EnvOptions & options , size_t * prefix_length ,
std : : unique_ptr < BlockAccessCipherStream > * stream ) {
EncryptionProvider * provider = nullptr ;
* prefix_length = 0 ;
Status status = GetWritableProvider ( fname , & provider ) ;
if ( ! status . ok ( ) ) {
return status ;
} else if ( provider ! = nullptr ) {
// Initialize & write prefix (if needed)
AlignedBuffer buffer ;
Slice prefix ;
* prefix_length = provider - > GetPrefixLength ( ) ;
if ( * prefix_length > 0 ) {
// Initialize prefix
buffer . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
buffer . AllocateNewBuffer ( * prefix_length ) ;
status = provider - > CreateNewPrefix ( fname , buffer . BufferStart ( ) ,
* prefix_length ) ;
if ( status . ok ( ) ) {
buffer . Size ( * prefix_length ) ;
prefix = Slice ( buffer . BufferStart ( ) , buffer . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Append ( prefix ) ;
}
if ( ! status . ok ( ) ) {
return status ;
}
}
// Create cipher stream
status = provider - > CreateCipherStream ( fname , options , prefix , stream ) ;
}
return status ;
}
template < class TypeFile >
Status CreateWritableEncryptedFile ( const std : : string & fname ,
std : : unique_ptr < TypeFile > & underlying ,
const EnvOptions & options ,
std : : unique_ptr < TypeFile > * result ) {
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
size_t prefix_length ;
Status status = CreateWritableCipherStream ( fname , underlying , options ,
& prefix_length , & stream ) ;
if ( status . ok ( ) ) {
if ( stream ) {
result - > reset ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefix_length ) ) ;
} else {
result - > reset ( underlying . release ( ) ) ;
}
}
return status ;
}
// Creates a CipherStream for the underlying file/name using the options
// If a writable provider is found and encryption is enabled, uses
// this provider to create a cipher stream.
// @param fname Name of the writable file
// @param underlying The underlying "raw" file
// @param options Options for creating the file/cipher
// @param prefix_length Returns the length of the encryption prefix used for
// this file
// @param stream Returns the cipher stream to use for this file if it
// should be encrypted
// @return OK on success, non-OK on failure.
template < class TypeFile >
Status CreateRandomWriteCipherStream (
const std : : string & fname , const std : : unique_ptr < TypeFile > & underlying ,
const EnvOptions & options , size_t * prefix_length ,
std : : unique_ptr < BlockAccessCipherStream > * stream ) {
EncryptionProvider * provider = nullptr ;
* prefix_length = 0 ;
Status status = GetWritableProvider ( fname , & provider ) ;
if ( ! status . ok ( ) ) {
return status ;
} else if ( provider ! = nullptr ) {
// Initialize & write prefix (if needed)
AlignedBuffer buffer ;
Slice prefix ;
* prefix_length = provider - > GetPrefixLength ( ) ;
if ( * prefix_length > 0 ) {
// Initialize prefix
buffer . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
buffer . AllocateNewBuffer ( * prefix_length ) ;
status = provider - > CreateNewPrefix ( fname , buffer . BufferStart ( ) ,
* prefix_length ) ;
if ( status . ok ( ) ) {
buffer . Size ( * prefix_length ) ;
prefix = Slice ( buffer . BufferStart ( ) , buffer . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Write ( 0 , prefix ) ;
}
if ( ! status . ok ( ) ) {
return status ;
}
}
// Create cipher stream
status = provider - > CreateCipherStream ( fname , options , prefix , stream ) ;
}
return status ;
}
// Creates a CipherStream for the underlying file/name using the options
// If a readable provider is found and the file is encrypted, uses
// this provider to create a cipher stream.
// @param fname Name of the writable file
// @param underlying The underlying "raw" file
// @param options Options for creating the file/cipher
// @param prefix_length Returns the length of the encryption prefix used for
// this file
// @param stream Returns the cipher stream to use for this file if it
// is encrypted
// @return OK on success, non-OK on failure.
template < class TypeFile >
Status CreateSequentialCipherStream (
const std : : string & fname , const std : : unique_ptr < TypeFile > & underlying ,
const EnvOptions & options , size_t * prefix_length ,
std : : unique_ptr < BlockAccessCipherStream > * stream ) {
// Read prefix (if needed)
AlignedBuffer buffer ;
Slice prefix ;
* prefix_length = provider_ - > GetPrefixLength ( ) ;
if ( * prefix_length > 0 ) {
// Read prefix
buffer . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
buffer . AllocateNewBuffer ( * prefix_length ) ;
Status status =
underlying - > Read ( * prefix_length , & prefix , buffer . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
buffer . Size ( * prefix_length ) ;
}
return provider_ - > CreateCipherStream ( fname , options , prefix , stream ) ;
}
// Creates a CipherStream for the underlying file/name using the options
// If a readable provider is found and the file is encrypted, uses
// this provider to create a cipher stream.
// @param fname Name of the writable file
// @param underlying The underlying "raw" file
// @param options Options for creating the file/cipher
// @param prefix_length Returns the length of the encryption prefix used for
// this file
// @param stream Returns the cipher stream to use for this file if it
// is encrypted
// @return OK on success, non-OK on failure.
template < class TypeFile >
Status CreateRandomReadCipherStream (
const std : : string & fname , const std : : unique_ptr < TypeFile > & underlying ,
const EnvOptions & options , size_t * prefix_length ,
std : : unique_ptr < BlockAccessCipherStream > * stream ) {
// Read prefix (if needed)
AlignedBuffer buffer ;
Slice prefix ;
* prefix_length = provider_ - > GetPrefixLength ( ) ;
if ( * prefix_length > 0 ) {
// Read prefix
buffer . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
buffer . AllocateNewBuffer ( * prefix_length ) ;
Status status =
underlying - > Read ( 0 , * prefix_length , & prefix , buffer . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
buffer . Size ( * prefix_length ) ;
}
return provider_ - > CreateCipherStream ( fname , options , prefix , stream ) ;
}
public :
EncryptedEnv ( Env * base_env , EncryptionProvider * provider )
EncryptedEnvImpl ( Env * base_env ,
const std : : shared_ptr < EncryptionProvider > & provider )
: EnvWrapper ( base_env ) {
provider_ = provider ;
}
@ -382,31 +646,16 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Read prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
// Read prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
status =
underlying - > Read ( prefixLength , & prefixSlice , prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
prefixBuf . Size ( prefixLength ) ;
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
size_t prefix_length ;
status = CreateSequentialCipherStream ( fname , underlying , options ,
& prefix_length , & stream ) ;
if ( status . ok ( ) ) {
result - > reset ( new EncryptedSequentialFile (
std : : move ( underlying ) , std : : move ( stream ) , prefix_length ) ) ;
}
( * result ) = std : : unique_ptr < SequentialFile > ( new EncryptedSequentialFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
return status ;
}
// NewRandomAccessFile opens a file for random read access.
@ -423,31 +672,19 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Read prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
// Read prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
status = underlying - > Read ( 0 , prefixLength , & prefixSlice ,
prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
prefixBuf . Size ( prefixLength ) ;
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
size_t prefix_length ;
status = CreateRandomReadCipherStream ( fname , underlying , options ,
& prefix_length , & stream ) ;
if ( status . ok ( ) ) {
if ( stream ) {
result - > reset ( new EncryptedRandomAccessFile (
std : : move ( underlying ) , std : : move ( stream ) , prefix_length ) ) ;
} else {
result - > reset ( underlying . release ( ) ) ;
}
}
( * result ) = std : : unique_ptr < RandomAccessFile > ( new EncryptedRandomAccessFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
return status ;
}
// NewWritableFile opens a file for sequential writing.
@ -464,36 +701,7 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Initialize & write prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
// Initialize prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
status = provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) ,
prefixLength ) ;
if ( status . ok ( ) ) {
prefixBuf . Size ( prefixLength ) ;
prefixSlice = Slice ( prefixBuf . BufferStart ( ) , prefixBuf . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Append ( prefixSlice ) ;
}
if ( ! status . ok ( ) ) {
return status ;
}
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
return CreateWritableEncryptedFile ( fname , underlying , options , result ) ;
}
// Create an object that writes to a new file with the specified
@ -516,33 +724,7 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Initialize & write prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
// Initialize prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) , prefixLength ) ;
prefixBuf . Size ( prefixLength ) ;
prefixSlice = Slice ( prefixBuf . BufferStart ( ) , prefixBuf . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Append ( prefixSlice ) ;
if ( ! status . ok ( ) ) {
return status ;
}
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
return CreateWritableEncryptedFile ( fname , underlying , options , result ) ;
}
// Reuse an existing file by renaming it and opening it as writable.
@ -561,33 +743,7 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Initialize & write prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
// Initialize prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) , prefixLength ) ;
prefixBuf . Size ( prefixLength ) ;
prefixSlice = Slice ( prefixBuf . BufferStart ( ) , prefixBuf . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Append ( prefixSlice ) ;
if ( ! status . ok ( ) ) {
return status ;
}
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
return CreateWritableEncryptedFile ( fname , underlying , options , result ) ;
}
// Open `fname` for random read and write, if file doesn't exist the file
@ -611,44 +767,26 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
// Read or Initialize & write prefix (if needed)
AlignedBuffer prefixBuf ;
Slice prefixSlice ;
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
if ( prefixLength > 0 ) {
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
if ( ! isNewFile ) {
// File already exists, read prefix
status = underlying - > Read ( 0 , prefixLength , & prefixSlice ,
prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
prefixBuf . Size ( prefixLength ) ;
} else {
// File is new, initialize & write prefix
provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) ,
prefixLength ) ;
prefixBuf . Size ( prefixLength ) ;
prefixSlice = Slice ( prefixBuf . BufferStart ( ) , prefixBuf . CurrentSize ( ) ) ;
// Write prefix
status = underlying - > Write ( 0 , prefixSlice ) ;
if ( ! status . ok ( ) ) {
return status ;
}
}
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
size_t prefix_length = 0 ;
if ( ! isNewFile ) {
// File already exists, read prefix
status = CreateRandomReadCipherStream ( fname , underlying , options ,
& prefix_length , & stream ) ;
} else {
status = CreateRandomWriteCipherStream ( fname , underlying , options ,
& prefix_length , & stream ) ;
}
( * result ) = std : : unique_ptr < RandomRWFile > ( new EncryptedRandomRWFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
if ( status . ok ( ) ) {
if ( stream ) {
result - > reset ( new EncryptedRandomRWFile (
std : : move ( underlying ) , std : : move ( stream ) , prefix_length ) ) ;
} else {
result - > reset ( underlying . release ( ) ) ;
}
}
return status ;
}
// Store in *result the attributes of the children of the specified
@ -671,14 +809,19 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
for ( auto it = std : : begin ( * result ) ; it ! = std : : end ( * result ) ; + + it ) {
// assert(it->size_bytes >= prefixLength);
// breaks env_basic_test when called on directory containing
// directories
// which makes subtraction of prefixLength worrisome since
// FileAttributes does not identify directories
it - > size_bytes - = prefixLength ;
EncryptionProvider * provider ;
status = GetReadableProvider ( it - > name , & provider ) ;
if ( ! status . ok ( ) ) {
return status ;
} else if ( provider ! = nullptr ) {
it - > size_bytes - = provider - > GetPrefixLength ( ) ;
}
}
return Status : : OK ( ) ;
}
@ -690,20 +833,25 @@ class EncryptedEnv : public EnvWrapper {
if ( ! status . ok ( ) ) {
return status ;
}
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
assert ( * file_size > = prefixLength ) ;
* file_size - = prefixLength ;
return Status : : OK ( ) ;
EncryptionProvider * provider ;
status = GetReadableProvider ( fname , & provider ) ;
if ( provider ! = nullptr & & status . ok ( ) ) {
size_t prefixLength = provider - > GetPrefixLength ( ) ;
assert ( * file_size > = prefixLength ) ;
* file_size - = prefixLength ;
}
return status ;
}
private :
EncryptionProvider * provider_ ;
std : : shared_ptr < EncryptionProvider > provider_ ;
} ;
// Returns an Env that encrypts data when stored on disk and decrypts data when
// read from disk.
Env * NewEncryptedEnv ( Env * base_env , EncryptionProvider * provider ) {
return new EncryptedEnv ( base_env , provider ) ;
Env * NewEncryptedEnv ( Env * base_env ,
const std : : shared_ptr < EncryptionProvider > & provider ) {
return new EncryptedEnvImpl ( base_env , provider ) ;
}
// Encrypt one or more (partial) blocks of data at the file offset.
@ -804,38 +952,38 @@ Status BlockAccessCipherStream::Decrypt(uint64_t fileOffset, char *data, size_t
}
}
const char * ROT13BlockCipher : : Name ( ) const { return kROT13CipherName ; }
// Encrypt a block of data.
// Length of data is equal to BlockSize().
Status ROT13BlockCipher : : Encrypt ( char * data ) {
Status ROT13BlockCipher : : Encrypt ( char * data ) {
for ( size_t i = 0 ; i < blockSize_ ; + + i ) {
data [ i ] + = 13 ;
data [ i ] + = 13 ;
}
return Status : : OK ( ) ;
}
// Decrypt a block of data.
// Length of data is equal to BlockSize().
Status ROT13BlockCipher : : Decrypt ( char * data ) {
return Encrypt ( data ) ;
}
Status ROT13BlockCipher : : Decrypt ( char * data ) { return Encrypt ( data ) ; }
// Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
void CTRCipherStream : : AllocateScratch ( std : : string & scratch ) {
auto blockSize = cipher_ . BlockSize ( ) ;
auto blockSize = cipher_ - > BlockSize ( ) ;
scratch . reserve ( blockSize ) ;
}
// Encrypt a block of data at the given block index.
// Length of data is equal to BlockSize();
Status CTRCipherStream : : EncryptBlock ( uint64_t blockIndex , char * data , char * scratch ) {
Status CTRCipherStream : : EncryptBlock ( uint64_t blockIndex , char * data ,
char * scratch ) {
// Create nonce + counter
auto blockSize = cipher_ . BlockSize ( ) ;
auto blockSize = cipher_ - > BlockSize ( ) ;
memmove ( scratch , iv_ . data ( ) , blockSize ) ;
EncodeFixed64 ( scratch , blockIndex + initialCounter_ ) ;
// Encrypt nonce+counter
auto status = cipher_ . Encrypt ( scratch ) ;
auto status = cipher_ - > Encrypt ( scratch ) ;
if ( ! status . ok ( ) ) {
return status ;
}
@ -849,22 +997,48 @@ Status CTRCipherStream::EncryptBlock(uint64_t blockIndex, char *data, char* scra
// Decrypt a block of data at the given block index.
// Length of data is equal to BlockSize();
Status CTRCipherStream : : DecryptBlock ( uint64_t blockIndex , char * data , char * scratch ) {
Status CTRCipherStream : : DecryptBlock ( uint64_t blockIndex , char * data ,
char * scratch ) {
// For CTR decryption & encryption are the same
return EncryptBlock ( blockIndex , data , scratch ) ;
}
const char * CTREncryptionProvider : : Name ( ) const { return kCTRProviderName ; }
// GetPrefixLength returns the length of the prefix that is added to every file
// and used for storing encryption options.
// For optimal performance, the prefix length should be a multiple of
// the page size.
size_t CTREncryptionProvider : : GetPrefixLength ( ) {
size_t CTREncryptionProvider : : GetPrefixLength ( ) const {
return defaultPrefixLength ;
}
Status CTREncryptionProvider : : TEST_Initialize ( ) {
if ( ! cipher_ ) {
return BlockCipher : : CreateFromString (
ConfigOptions ( ) , std : : string ( kROT13CipherName ) + " :32 " , & cipher_ ) ;
}
return Status : : OK ( ) ;
}
Status CTREncryptionProvider : : AddCipher ( const std : : string & /*descriptor*/ ,
const char * cipher , size_t len ,
bool /*for_write*/ ) {
if ( cipher_ ) {
return Status : : NotSupported ( " Cannot add keys to CTREncryptionProvider " ) ;
} else if ( strcmp ( kROT13CipherName , cipher ) = = 0 ) {
cipher_ . reset ( new ROT13BlockCipher ( len ) ) ;
return Status : : OK ( ) ;
} else {
return BlockCipher : : CreateFromString ( ConfigOptions ( ) , std : : string ( cipher ) ,
& cipher_ ) ;
}
}
// decodeCTRParameters decodes the initial counter & IV from the given
// (plain text) prefix.
static void decodeCTRParameters ( const char * prefix , size_t blockSize , uint64_t & initialCounter , Slice & iv ) {
static void decodeCTRParameters ( const char * prefix , size_t blockSize ,
uint64_t & initialCounter , Slice & iv ) {
// First block contains 64-bit initial counter
initialCounter = DecodeFixed64 ( prefix ) ;
// Second block contains IV
@ -875,7 +1049,10 @@ static void decodeCTRParameters(const char *prefix, size_t blockSize, uint64_t &
// for a new file.
Status CTREncryptionProvider : : CreateNewPrefix ( const std : : string & /*fname*/ ,
char * prefix ,
size_t prefixLength ) {
size_t prefixLength ) const {
if ( ! cipher_ ) {
return Status : : InvalidArgument ( " Encryption Cipher is missing " ) ;
}
// Create & seed rnd.
Random rnd ( ( uint32_t ) Env : : Default ( ) - > NowMicros ( ) ) ;
// Fill entire prefix block with random values.
@ -883,13 +1060,14 @@ Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/,
prefix [ i ] = rnd . Uniform ( 256 ) & 0xFF ;
}
// Take random data to extract initial counter & IV
auto blockSize = cipher_ . BlockSize ( ) ;
auto blockSize = cipher_ - > BlockSize ( ) ;
uint64_t initialCounter ;
Slice prefixIV ;
decodeCTRParameters ( prefix , blockSize , initialCounter , prefixIV ) ;
// Now populate the rest of the prefix, starting from the third block.
PopulateSecretPrefixPart ( prefix + ( 2 * blockSize ) , prefixLength - ( 2 * blockSize ) , blockSize ) ;
PopulateSecretPrefixPart ( prefix + ( 2 * blockSize ) ,
prefixLength - ( 2 * blockSize ) , blockSize ) ;
// Encrypt the prefix, starting from block 2 (leave block 0, 1 with initial
// counter & IV unencrypted)
@ -910,9 +1088,8 @@ Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/,
// in plain text.
// Returns the amount of space (starting from the start of the prefix)
// that has been initialized.
size_t CTREncryptionProvider : : PopulateSecretPrefixPart ( char * /*prefix*/ ,
size_t /*prefixLength*/ ,
size_t /*blockSize*/ ) {
size_t CTREncryptionProvider : : PopulateSecretPrefixPart (
char * /*prefix*/ , size_t /*prefixLength*/ , size_t /*blockSize*/ ) const {
// Nothing to do here, put in custom data in override when needed.
return 0 ;
}
@ -920,8 +1097,11 @@ size_t CTREncryptionProvider::PopulateSecretPrefixPart(char* /*prefix*/,
Status CTREncryptionProvider : : CreateCipherStream (
const std : : string & fname , const EnvOptions & options , Slice & prefix ,
std : : unique_ptr < BlockAccessCipherStream > * result ) {
if ( ! cipher_ ) {
return Status : : InvalidArgument ( " Encryption Cipher is missing " ) ;
}
// Read plain text part of prefix.
auto blockSize = cipher_ . BlockSize ( ) ;
auto blockSize = cipher_ - > BlockSize ( ) ;
uint64_t initialCounter ;
Slice iv ;
decodeCTRParameters ( prefix . data ( ) , blockSize , initialCounter , iv ) ;
@ -948,11 +1128,12 @@ Status CTREncryptionProvider::CreateCipherStream(
}
// Create cipher stream
return CreateCipherStreamFromPrefix ( fname , options , initialCounter , iv , prefix , result ) ;
return CreateCipherStreamFromPrefix ( fname , options , initialCounter , iv ,
prefix , result ) ;
}
// CreateCipherStreamFromPrefix creates a block access cipher stream for a file given
// given name and options. The given prefix is already decrypted.
// CreateCipherStreamFromPrefix creates a block access cipher stream for a file
// given given name and options. The given prefix is already decrypted.
Status CTREncryptionProvider : : CreateCipherStreamFromPrefix (
const std : : string & /*fname*/ , const EnvOptions & /*options*/ ,
uint64_t initialCounter , const Slice & iv , const Slice & /*prefix*/ ,