Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/env/env_encryption.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under both the GPLv2 (found in the
3
//  COPYING file in the root directory) and Apache 2.0 License
4
//  (found in the LICENSE.Apache file in the root directory).
5
6
7
#include "rocksdb/env_encryption.h"
8
9
#include <algorithm>
10
#include <cassert>
11
#include <cctype>
12
#include <iostream>
13
14
#include "env/composite_env_wrapper.h"
15
#include "env/env_encryption_ctr.h"
16
#include "monitoring/perf_context_imp.h"
17
#include "rocksdb/convenience.h"
18
#include "rocksdb/io_status.h"
19
#include "rocksdb/system_clock.h"
20
#include "rocksdb/utilities/customizable_util.h"
21
#include "rocksdb/utilities/options_type.h"
22
#include "util/aligned_buffer.h"
23
#include "util/coding.h"
24
#include "util/random.h"
25
#include "util/string_util.h"
26
27
namespace ROCKSDB_NAMESPACE {
28
std::shared_ptr<EncryptionProvider> EncryptionProvider::NewCTRProvider(
29
0
    const std::shared_ptr<BlockCipher>& cipher) {
30
0
  return std::make_shared<CTREncryptionProvider>(cipher);
31
0
}
32
33
IOStatus EncryptedSequentialFile::Read(size_t n, const IOOptions& options,
34
                                       Slice* result, char* scratch,
35
0
                                       IODebugContext* dbg) {
36
0
  assert(scratch);
37
0
  IOStatus io_s = file_->Read(n, options, result, scratch, dbg);
38
0
  if (!io_s.ok()) {
39
0
    return io_s;
40
0
  }
41
0
  {
42
0
    PERF_TIMER_GUARD(decrypt_data_nanos);
43
0
    io_s = status_to_io_status(
44
0
        stream_->Decrypt(offset_, (char*)result->data(), result->size()));
45
0
  }
46
0
  if (io_s.ok()) {
47
0
    offset_ += result->size();  // We've already read data from disk, so update
48
                                // offset_ even if decryption fails.
49
0
  }
50
0
  return io_s;
51
0
}
52
53
0
IOStatus EncryptedSequentialFile::Skip(uint64_t n) {
54
0
  auto status = file_->Skip(n);
55
0
  if (!status.ok()) {
56
0
    return status;
57
0
  }
58
0
  offset_ += n;
59
0
  return status;
60
0
}
61
62
0
bool EncryptedSequentialFile::use_direct_io() const {
63
0
  return file_->use_direct_io();
64
0
}
65
66
0
size_t EncryptedSequentialFile::GetRequiredBufferAlignment() const {
67
0
  return file_->GetRequiredBufferAlignment();
68
0
}
69
70
IOStatus EncryptedSequentialFile::InvalidateCache(size_t offset,
71
0
                                                  size_t length) {
72
0
  return file_->InvalidateCache(offset + prefixLength_, length);
73
0
}
74
75
IOStatus EncryptedSequentialFile::PositionedRead(uint64_t offset, size_t n,
76
                                                 const IOOptions& options,
77
                                                 Slice* result, char* scratch,
78
0
                                                 IODebugContext* dbg) {
79
0
  assert(scratch);
80
0
  offset += prefixLength_;  // Skip prefix
81
0
  auto io_s = file_->PositionedRead(offset, n, options, result, scratch, dbg);
82
0
  if (!io_s.ok()) {
83
0
    return io_s;
84
0
  }
85
0
  offset_ = offset + result->size();
86
0
  {
87
0
    PERF_TIMER_GUARD(decrypt_data_nanos);
88
0
    io_s = status_to_io_status(
89
0
        stream_->Decrypt(offset, (char*)result->data(), result->size()));
90
0
  }
91
0
  return io_s;
92
0
}
93
94
IOStatus EncryptedRandomAccessFile::Read(uint64_t offset, size_t n,
95
                                         const IOOptions& options,
96
                                         Slice* result, char* scratch,
97
0
                                         IODebugContext* dbg) const {
98
0
  assert(scratch);
99
0
  offset += prefixLength_;
100
0
  auto io_s = file_->Read(offset, n, options, result, scratch, dbg);
101
0
  if (!io_s.ok()) {
102
0
    return io_s;
103
0
  }
104
0
  {
105
0
    PERF_TIMER_GUARD(decrypt_data_nanos);
106
0
    io_s = status_to_io_status(
107
0
        stream_->Decrypt(offset, (char*)result->data(), result->size()));
108
0
  }
109
0
  return io_s;
110
0
}
111
112
IOStatus EncryptedRandomAccessFile::Prefetch(uint64_t offset, size_t n,
113
                                             const IOOptions& options,
114
0
                                             IODebugContext* dbg) {
115
0
  return file_->Prefetch(offset + prefixLength_, n, options, dbg);
116
0
}
117
118
0
size_t EncryptedRandomAccessFile::GetUniqueId(char* id, size_t max_size) const {
119
0
  return file_->GetUniqueId(id, max_size);
120
0
}
121
122
0
void EncryptedRandomAccessFile::Hint(AccessPattern pattern) {
123
0
  file_->Hint(pattern);
124
0
}
125
126
0
bool EncryptedRandomAccessFile::use_direct_io() const {
127
0
  return file_->use_direct_io();
128
0
}
129
130
0
size_t EncryptedRandomAccessFile::GetRequiredBufferAlignment() const {
131
0
  return file_->GetRequiredBufferAlignment();
132
0
}
133
134
IOStatus EncryptedRandomAccessFile::InvalidateCache(size_t offset,
135
0
                                                    size_t length) {
136
0
  return file_->InvalidateCache(offset + prefixLength_, length);
137
0
}
138
139
IOStatus EncryptedWritableFile::Append(const Slice& data,
140
                                       const IOOptions& options,
141
0
                                       IODebugContext* dbg) {
142
0
  AlignedBuffer buf;
143
0
  Slice dataToAppend(data);
144
0
  if (data.size() > 0) {
145
0
    auto offset = file_->GetFileSize(options, dbg);  // size including prefix
146
    // Encrypt in cloned buffer
147
0
    buf.Alignment(GetRequiredBufferAlignment());
148
0
    buf.AllocateNewBuffer(data.size());
149
    // TODO (sagar0): Modify AlignedBuffer.Append to allow doing a memmove
150
    // so that the next two lines can be replaced with buf.Append().
151
0
    memmove(buf.BufferStart(), data.data(), data.size());
152
0
    buf.Size(data.size());
153
0
    IOStatus io_s;
154
0
    {
155
0
      PERF_TIMER_GUARD(encrypt_data_nanos);
156
0
      io_s = status_to_io_status(
157
0
          stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()));
158
0
    }
159
0
    if (!io_s.ok()) {
160
0
      return io_s;
161
0
    }
162
0
    dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize());
163
0
  }
164
0
  return file_->Append(dataToAppend, options, dbg);
165
0
}
166
167
IOStatus EncryptedWritableFile::PositionedAppend(const Slice& data,
168
                                                 uint64_t offset,
169
                                                 const IOOptions& options,
170
0
                                                 IODebugContext* dbg) {
171
0
  AlignedBuffer buf;
172
0
  Slice dataToAppend(data);
173
0
  offset += prefixLength_;
174
0
  if (data.size() > 0) {
175
    // Encrypt in cloned buffer
176
0
    buf.Alignment(GetRequiredBufferAlignment());
177
0
    buf.AllocateNewBuffer(data.size());
178
0
    memmove(buf.BufferStart(), data.data(), data.size());
179
0
    buf.Size(data.size());
180
0
    IOStatus io_s;
181
0
    {
182
0
      PERF_TIMER_GUARD(encrypt_data_nanos);
183
0
      io_s = status_to_io_status(
184
0
          stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()));
185
0
    }
186
0
    if (!io_s.ok()) {
187
0
      return io_s;
188
0
    }
189
0
    dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize());
190
0
  }
191
0
  return file_->PositionedAppend(dataToAppend, offset, options, dbg);
192
0
}
193
194
0
bool EncryptedWritableFile::use_direct_io() const {
195
0
  return file_->use_direct_io();
196
0
}
197
198
0
bool EncryptedWritableFile::IsSyncThreadSafe() const {
199
0
  return file_->IsSyncThreadSafe();
200
0
}
201
202
0
size_t EncryptedWritableFile::GetRequiredBufferAlignment() const {
203
0
  return file_->GetRequiredBufferAlignment();
204
0
}
205
206
uint64_t EncryptedWritableFile::GetFileSize(const IOOptions& options,
207
0
                                            IODebugContext* dbg) {
208
0
  return file_->GetFileSize(options, dbg) - prefixLength_;
209
0
}
210
211
IOStatus EncryptedWritableFile::Truncate(uint64_t size,
212
                                         const IOOptions& options,
213
0
                                         IODebugContext* dbg) {
214
0
  return file_->Truncate(size + prefixLength_, options, dbg);
215
0
}
216
217
0
IOStatus EncryptedWritableFile::InvalidateCache(size_t offset, size_t length) {
218
0
  return file_->InvalidateCache(offset + prefixLength_, length);
219
0
}
220
221
IOStatus EncryptedWritableFile::RangeSync(uint64_t offset, uint64_t nbytes,
222
                                          const IOOptions& options,
223
0
                                          IODebugContext* dbg) {
224
0
  return file_->RangeSync(offset + prefixLength_, nbytes, options, dbg);
225
0
}
226
227
void EncryptedWritableFile::PrepareWrite(size_t offset, size_t len,
228
                                         const IOOptions& options,
229
0
                                         IODebugContext* dbg) {
230
0
  file_->PrepareWrite(offset + prefixLength_, len, options, dbg);
231
0
}
232
233
0
void EncryptedWritableFile::SetPreallocationBlockSize(size_t size) {
234
  // the size here doesn't need to include prefixLength_, as it's a
235
  // configuration will be use for `PrepareWrite()`.
236
0
  file_->SetPreallocationBlockSize(size);
237
0
}
238
239
void EncryptedWritableFile::GetPreallocationStatus(
240
0
    size_t* block_size, size_t* last_allocated_block) {
241
0
  file_->GetPreallocationStatus(block_size, last_allocated_block);
242
0
}
243
244
IOStatus EncryptedWritableFile::Allocate(uint64_t offset, uint64_t len,
245
                                         const IOOptions& options,
246
0
                                         IODebugContext* dbg) {
247
0
  return file_->Allocate(offset + prefixLength_, len, options, dbg);
248
0
}
249
250
IOStatus EncryptedWritableFile::Flush(const IOOptions& options,
251
0
                                      IODebugContext* dbg) {
252
0
  return file_->Flush(options, dbg);
253
0
}
254
255
IOStatus EncryptedWritableFile::Sync(const IOOptions& options,
256
0
                                     IODebugContext* dbg) {
257
0
  return file_->Sync(options, dbg);
258
0
}
259
260
IOStatus EncryptedWritableFile::Close(const IOOptions& options,
261
0
                                      IODebugContext* dbg) {
262
0
  return file_->Close(options, dbg);
263
0
}
264
265
0
bool EncryptedRandomRWFile::use_direct_io() const {
266
0
  return file_->use_direct_io();
267
0
}
268
269
0
size_t EncryptedRandomRWFile::GetRequiredBufferAlignment() const {
270
0
  return file_->GetRequiredBufferAlignment();
271
0
}
272
273
IOStatus EncryptedRandomRWFile::Write(uint64_t offset, const Slice& data,
274
                                      const IOOptions& options,
275
0
                                      IODebugContext* dbg) {
276
0
  AlignedBuffer buf;
277
0
  Slice dataToWrite(data);
278
0
  offset += prefixLength_;
279
0
  if (data.size() > 0) {
280
    // Encrypt in cloned buffer
281
0
    buf.Alignment(GetRequiredBufferAlignment());
282
0
    buf.AllocateNewBuffer(data.size());
283
0
    memmove(buf.BufferStart(), data.data(), data.size());
284
0
    buf.Size(data.size());
285
0
    IOStatus io_s;
286
0
    {
287
0
      PERF_TIMER_GUARD(encrypt_data_nanos);
288
0
      io_s = status_to_io_status(
289
0
          stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize()));
290
0
    }
291
0
    if (!io_s.ok()) {
292
0
      return io_s;
293
0
    }
294
0
    dataToWrite = Slice(buf.BufferStart(), buf.CurrentSize());
295
0
  }
296
0
  return file_->Write(offset, dataToWrite, options, dbg);
297
0
}
298
299
IOStatus EncryptedRandomRWFile::Read(uint64_t offset, size_t n,
300
                                     const IOOptions& options, Slice* result,
301
0
                                     char* scratch, IODebugContext* dbg) const {
302
0
  assert(scratch);
303
0
  offset += prefixLength_;
304
0
  auto status = file_->Read(offset, n, options, result, scratch, dbg);
305
0
  if (!status.ok()) {
306
0
    return status;
307
0
  }
308
0
  {
309
0
    PERF_TIMER_GUARD(decrypt_data_nanos);
310
0
    status = status_to_io_status(
311
0
        stream_->Decrypt(offset, (char*)result->data(), result->size()));
312
0
  }
313
0
  return status;
314
0
}
315
316
IOStatus EncryptedRandomRWFile::Flush(const IOOptions& options,
317
0
                                      IODebugContext* dbg) {
318
0
  return file_->Flush(options, dbg);
319
0
}
320
321
IOStatus EncryptedRandomRWFile::Sync(const IOOptions& options,
322
0
                                     IODebugContext* dbg) {
323
0
  return file_->Sync(options, dbg);
324
0
}
325
326
IOStatus EncryptedRandomRWFile::Fsync(const IOOptions& options,
327
0
                                      IODebugContext* dbg) {
328
0
  return file_->Fsync(options, dbg);
329
0
}
330
331
IOStatus EncryptedRandomRWFile::Close(const IOOptions& options,
332
0
                                      IODebugContext* dbg) {
333
0
  return file_->Close(options, dbg);
334
0
}
335
336
namespace {
337
static std::unordered_map<std::string, OptionTypeInfo> encrypted_fs_type_info =
338
    {
339
        {"provider",
340
         OptionTypeInfo::AsCustomSharedPtr<EncryptionProvider>(
341
             0 /* No offset, whole struct*/, OptionVerificationType::kByName,
342
             OptionTypeFlags::kNone)},
343
};
344
// EncryptedFileSystemImpl implements an FileSystemWrapper that adds encryption
345
// to files stored on disk.
346
class EncryptedFileSystemImpl : public EncryptedFileSystem {
347
 public:
348
0
  const char* Name() const override {
349
0
    return EncryptedFileSystem::kClassName();
350
0
  }
351
  // Returns the raw encryption provider that should be used to write the input
352
  // encrypted file.  If there is no such provider, NotFound is returned.
353
  IOStatus GetWritableProvider(const std::string& /*fname*/,
354
0
                               EncryptionProvider** result) {
355
0
    if (provider_) {
356
0
      *result = provider_.get();
357
0
      return IOStatus::OK();
358
0
    } else {
359
0
      *result = nullptr;
360
0
      return IOStatus::NotFound("No WriteProvider specified");
361
0
    }
362
0
  }
363
364
  // Returns the raw encryption provider that should be used to read the input
365
  // encrypted file.  If there is no such provider, NotFound is returned.
366
  IOStatus GetReadableProvider(const std::string& /*fname*/,
367
0
                               EncryptionProvider** result) {
368
0
    if (provider_) {
369
0
      *result = provider_.get();
370
0
      return IOStatus::OK();
371
0
    } else {
372
0
      *result = nullptr;
373
0
      return IOStatus::NotFound("No Provider specified");
374
0
    }
375
0
  }
376
377
  // Creates a CipherStream for the underlying file/name using the options
378
  // If a writable provider is found and encryption is enabled, uses
379
  // this provider to create a cipher stream.
380
  // @param fname         Name of the writable file
381
  // @param underlying    The underlying "raw" file
382
  // @param options       Options for creating the file/cipher
383
  // @param prefix_length Returns the length of the encryption prefix used for
384
  // this file
385
  // @param stream        Returns the cipher stream to use for this file if it
386
  // should be encrypted
387
  // @return OK on success, non-OK on failure.
388
  template <class TypeFile>
389
  IOStatus CreateWritableCipherStream(
390
      const std::string& fname, const std::unique_ptr<TypeFile>& underlying,
391
      const FileOptions& options, size_t* prefix_length,
392
0
      std::unique_ptr<BlockAccessCipherStream>* stream, IODebugContext* dbg) {
393
0
    EncryptionProvider* provider = nullptr;
394
0
    *prefix_length = 0;
395
0
    IOStatus status = GetWritableProvider(fname, &provider);
396
0
    if (!status.ok()) {
397
0
      return status;
398
0
    } else if (provider != nullptr) {
399
      // Initialize & write prefix (if needed)
400
0
      AlignedBuffer buffer;
401
0
      Slice prefix;
402
0
      *prefix_length = provider->GetPrefixLength();
403
0
      if (*prefix_length > 0) {
404
        // Initialize prefix
405
0
        buffer.Alignment(underlying->GetRequiredBufferAlignment());
406
0
        buffer.AllocateNewBuffer(*prefix_length);
407
0
        status = status_to_io_status(provider->CreateNewPrefix(
408
0
            fname, buffer.BufferStart(), *prefix_length));
409
0
        if (status.ok()) {
410
0
          buffer.Size(*prefix_length);
411
0
          prefix = Slice(buffer.BufferStart(), buffer.CurrentSize());
412
          // Write prefix
413
0
          status = underlying->Append(prefix, options.io_options, dbg);
414
0
        }
415
0
        if (!status.ok()) {
416
0
          return status;
417
0
        }
418
0
      }
419
      // Create cipher stream
420
0
      status = status_to_io_status(
421
0
          provider->CreateCipherStream(fname, options, prefix, stream));
422
0
    }
423
0
    return status;
424
0
  }
425
426
  template <class TypeFile>
427
  IOStatus CreateWritableEncryptedFile(const std::string& fname,
428
                                       std::unique_ptr<TypeFile>& underlying,
429
                                       const FileOptions& options,
430
                                       std::unique_ptr<TypeFile>* result,
431
0
                                       IODebugContext* dbg) {
432
    // Create cipher stream
433
0
    std::unique_ptr<BlockAccessCipherStream> stream;
434
0
    size_t prefix_length;
435
0
    IOStatus status = CreateWritableCipherStream(fname, underlying, options,
436
0
                                                 &prefix_length, &stream, dbg);
437
0
    if (status.ok()) {
438
0
      if (stream) {
439
0
        result->reset(new EncryptedWritableFile(
440
0
            std::move(underlying), std::move(stream), prefix_length));
441
0
      } else {
442
0
        result->reset(underlying.release());
443
0
      }
444
0
    }
445
0
    return status;
446
0
  }
447
448
  // Creates a CipherStream for the underlying file/name using the options
449
  // If a writable provider is found and encryption is enabled, uses
450
  // this provider to create a cipher stream.
451
  // @param fname         Name of the writable file
452
  // @param underlying    The underlying "raw" file
453
  // @param options       Options for creating the file/cipher
454
  // @param prefix_length Returns the length of the encryption prefix used for
455
  // this file
456
  // @param stream        Returns the cipher stream to use for this file if it
457
  // should be encrypted
458
  // @return OK on success, non-OK on failure.
459
  template <class TypeFile>
460
  IOStatus CreateRandomWriteCipherStream(
461
      const std::string& fname, const std::unique_ptr<TypeFile>& underlying,
462
      const FileOptions& options, size_t* prefix_length,
463
0
      std::unique_ptr<BlockAccessCipherStream>* stream, IODebugContext* dbg) {
464
0
    EncryptionProvider* provider = nullptr;
465
0
    *prefix_length = 0;
466
0
    IOStatus io_s = GetWritableProvider(fname, &provider);
467
0
    if (!io_s.ok()) {
468
0
      return io_s;
469
0
    } else if (provider != nullptr) {
470
      // Initialize & write prefix (if needed)
471
0
      AlignedBuffer buffer;
472
0
      Slice prefix;
473
0
      *prefix_length = provider->GetPrefixLength();
474
0
      if (*prefix_length > 0) {
475
        // Initialize prefix
476
0
        buffer.Alignment(underlying->GetRequiredBufferAlignment());
477
0
        buffer.AllocateNewBuffer(*prefix_length);
478
0
        io_s = status_to_io_status(provider->CreateNewPrefix(
479
0
            fname, buffer.BufferStart(), *prefix_length));
480
0
        if (io_s.ok()) {
481
0
          buffer.Size(*prefix_length);
482
0
          prefix = Slice(buffer.BufferStart(), buffer.CurrentSize());
483
          // Write prefix
484
0
          io_s = underlying->Write(0, prefix, options.io_options, dbg);
485
0
        }
486
0
        if (!io_s.ok()) {
487
0
          return io_s;
488
0
        }
489
0
      }
490
      // Create cipher stream
491
0
      io_s = status_to_io_status(
492
0
          provider->CreateCipherStream(fname, options, prefix, stream));
493
0
    }
494
0
    return io_s;
495
0
  }
496
497
  // Creates a CipherStream for the underlying file/name using the options
498
  // If a readable provider is found and the file is encrypted, uses
499
  // this provider to create a cipher stream.
500
  // @param fname         Name of the writable file
501
  // @param underlying    The underlying "raw" file
502
  // @param options       Options for creating the file/cipher
503
  // @param prefix_length Returns the length of the encryption prefix used for
504
  // this file
505
  // @param stream        Returns the cipher stream to use for this file if it
506
  // is encrypted
507
  // @return OK on success, non-OK on failure.
508
  template <class TypeFile>
509
  IOStatus CreateSequentialCipherStream(
510
      const std::string& fname, const std::unique_ptr<TypeFile>& underlying,
511
      const FileOptions& options, size_t* prefix_length,
512
0
      std::unique_ptr<BlockAccessCipherStream>* stream, IODebugContext* dbg) {
513
    // Read prefix (if needed)
514
0
    AlignedBuffer buffer;
515
0
    Slice prefix;
516
0
    *prefix_length = provider_->GetPrefixLength();
517
0
    if (*prefix_length > 0) {
518
      // Read prefix
519
0
      buffer.Alignment(underlying->GetRequiredBufferAlignment());
520
0
      buffer.AllocateNewBuffer(*prefix_length);
521
0
      IOStatus status = underlying->Read(*prefix_length, options.io_options,
522
0
                                         &prefix, buffer.BufferStart(), dbg);
523
0
      if (!status.ok()) {
524
0
        return status;
525
0
      }
526
0
      buffer.Size(*prefix_length);
527
0
    }
528
0
    return status_to_io_status(
529
0
        provider_->CreateCipherStream(fname, options, prefix, stream));
530
0
  }
531
532
  // Creates a CipherStream for the underlying file/name using the options
533
  // If a readable provider is found and the file is encrypted, uses
534
  // this provider to create a cipher stream.
535
  // @param fname         Name of the writable file
536
  // @param underlying    The underlying "raw" file
537
  // @param options       Options for creating the file/cipher
538
  // @param prefix_length Returns the length of the encryption prefix used for
539
  // this file
540
  // @param stream        Returns the cipher stream to use for this file if it
541
  // is encrypted
542
  // @return OK on success, non-OK on failure.
543
  template <class TypeFile>
544
  IOStatus CreateRandomReadCipherStream(
545
      const std::string& fname, const std::unique_ptr<TypeFile>& underlying,
546
      const FileOptions& options, size_t* prefix_length,
547
0
      std::unique_ptr<BlockAccessCipherStream>* stream, IODebugContext* dbg) {
548
    // Read prefix (if needed)
549
0
    AlignedBuffer buffer;
550
0
    Slice prefix;
551
0
    *prefix_length = provider_->GetPrefixLength();
552
0
    if (*prefix_length > 0) {
553
      // Read prefix
554
0
      buffer.Alignment(underlying->GetRequiredBufferAlignment());
555
0
      buffer.AllocateNewBuffer(*prefix_length);
556
0
      IOStatus status = underlying->Read(0, *prefix_length, options.io_options,
557
0
                                         &prefix, buffer.BufferStart(), dbg);
558
0
      if (!status.ok()) {
559
0
        return status;
560
0
      }
561
0
      buffer.Size(*prefix_length);
562
0
    }
563
0
    return status_to_io_status(
564
0
        provider_->CreateCipherStream(fname, options, prefix, stream));
565
0
  }
Unexecuted instantiation: env_encryption.cc:rocksdb::IOStatus rocksdb::(anonymous namespace)::EncryptedFileSystemImpl::CreateRandomReadCipherStream<rocksdb::FSRandomAccessFile>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::unique_ptr<rocksdb::FSRandomAccessFile, std::__1::default_delete<rocksdb::FSRandomAccessFile> > const&, rocksdb::FileOptions const&, unsigned long*, std::__1::unique_ptr<rocksdb::BlockAccessCipherStream, std::__1::default_delete<rocksdb::BlockAccessCipherStream> >*, rocksdb::IODebugContext*)
Unexecuted instantiation: env_encryption.cc:rocksdb::IOStatus rocksdb::(anonymous namespace)::EncryptedFileSystemImpl::CreateRandomReadCipherStream<rocksdb::FSRandomRWFile>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::unique_ptr<rocksdb::FSRandomRWFile, std::__1::default_delete<rocksdb::FSRandomRWFile> > const&, rocksdb::FileOptions const&, unsigned long*, std::__1::unique_ptr<rocksdb::BlockAccessCipherStream, std::__1::default_delete<rocksdb::BlockAccessCipherStream> >*, rocksdb::IODebugContext*)
566
567
 public:
568
  EncryptedFileSystemImpl(const std::shared_ptr<FileSystem>& base,
569
                          const std::shared_ptr<EncryptionProvider>& provider)
570
0
      : EncryptedFileSystem(base) {
571
0
    provider_ = provider;
572
0
    RegisterOptions("EncryptionProvider", &provider_, &encrypted_fs_type_info);
573
0
  }
574
575
  Status AddCipher(const std::string& descriptor, const char* cipher,
576
0
                   size_t len, bool for_write) override {
577
0
    return provider_->AddCipher(descriptor, cipher, len, for_write);
578
0
  }
579
580
  IOStatus NewSequentialFile(const std::string& fname,
581
                             const FileOptions& options,
582
                             std::unique_ptr<FSSequentialFile>* result,
583
0
                             IODebugContext* dbg) override {
584
0
    result->reset();
585
0
    if (options.use_mmap_reads) {
586
0
      return IOStatus::InvalidArgument();
587
0
    }
588
    // Open file using underlying Env implementation
589
0
    std::unique_ptr<FSSequentialFile> underlying;
590
0
    auto status =
591
0
        FileSystemWrapper::NewSequentialFile(fname, options, &underlying, dbg);
592
0
    if (!status.ok()) {
593
0
      return status;
594
0
    }
595
0
    uint64_t file_size;
596
0
    status = FileSystemWrapper::GetFileSize(fname, options.io_options,
597
0
                                            &file_size, dbg);
598
0
    if (!status.ok()) {
599
0
      return status;
600
0
    }
601
0
    if (!file_size) {
602
0
      *result = std::move(underlying);
603
0
      return status;
604
0
    }
605
    // Create cipher stream
606
0
    std::unique_ptr<BlockAccessCipherStream> stream;
607
0
    size_t prefix_length;
608
0
    status = CreateSequentialCipherStream(fname, underlying, options,
609
0
                                          &prefix_length, &stream, dbg);
610
0
    if (status.ok()) {
611
0
      result->reset(new EncryptedSequentialFile(
612
0
          std::move(underlying), std::move(stream), prefix_length));
613
0
    }
614
0
    return status;
615
0
  }
616
617
  IOStatus NewRandomAccessFile(const std::string& fname,
618
                               const FileOptions& options,
619
                               std::unique_ptr<FSRandomAccessFile>* result,
620
0
                               IODebugContext* dbg) override {
621
0
    result->reset();
622
0
    if (options.use_mmap_reads) {
623
0
      return IOStatus::InvalidArgument();
624
0
    }
625
    // Open file using underlying Env implementation
626
0
    std::unique_ptr<FSRandomAccessFile> underlying;
627
0
    auto status = FileSystemWrapper::NewRandomAccessFile(fname, options,
628
0
                                                         &underlying, dbg);
629
0
    if (!status.ok()) {
630
0
      return status;
631
0
    }
632
0
    std::unique_ptr<BlockAccessCipherStream> stream;
633
0
    size_t prefix_length;
634
0
    status = CreateRandomReadCipherStream(fname, underlying, options,
635
0
                                          &prefix_length, &stream, dbg);
636
0
    if (status.ok()) {
637
0
      if (stream) {
638
0
        result->reset(new EncryptedRandomAccessFile(
639
0
            std::move(underlying), std::move(stream), prefix_length));
640
0
      } else {
641
0
        result->reset(underlying.release());
642
0
      }
643
0
    }
644
0
    return status;
645
0
  }
646
647
  IOStatus NewWritableFile(const std::string& fname, const FileOptions& options,
648
                           std::unique_ptr<FSWritableFile>* result,
649
0
                           IODebugContext* dbg) override {
650
0
    result->reset();
651
0
    if (options.use_mmap_writes) {
652
0
      return IOStatus::InvalidArgument();
653
0
    }
654
    // Open file using underlying Env implementation
655
0
    std::unique_ptr<FSWritableFile> underlying;
656
0
    IOStatus status =
657
0
        FileSystemWrapper::NewWritableFile(fname, options, &underlying, dbg);
658
0
    if (!status.ok()) {
659
0
      return status;
660
0
    }
661
0
    return CreateWritableEncryptedFile(fname, underlying, options, result, dbg);
662
0
  }
663
664
  IOStatus ReopenWritableFile(const std::string& fname,
665
                              const FileOptions& options,
666
                              std::unique_ptr<FSWritableFile>* result,
667
0
                              IODebugContext* dbg) override {
668
0
    result->reset();
669
0
    if (options.use_mmap_writes) {
670
0
      return IOStatus::InvalidArgument();
671
0
    }
672
    // Open file using underlying Env implementation
673
0
    std::unique_ptr<FSWritableFile> underlying;
674
0
    IOStatus status =
675
0
        FileSystemWrapper::ReopenWritableFile(fname, options, &underlying, dbg);
676
0
    if (!status.ok()) {
677
0
      return status;
678
0
    }
679
0
    return CreateWritableEncryptedFile(fname, underlying, options, result, dbg);
680
0
  }
681
682
  IOStatus ReuseWritableFile(const std::string& fname,
683
                             const std::string& old_fname,
684
                             const FileOptions& options,
685
                             std::unique_ptr<FSWritableFile>* result,
686
0
                             IODebugContext* dbg) override {
687
0
    result->reset();
688
0
    if (options.use_mmap_writes) {
689
0
      return IOStatus::InvalidArgument();
690
0
    }
691
    // Open file using underlying Env implementation
692
0
    std::unique_ptr<FSWritableFile> underlying;
693
0
    auto status = FileSystemWrapper::ReuseWritableFile(
694
0
        fname, old_fname, options, &underlying, dbg);
695
0
    if (!status.ok()) {
696
0
      return status;
697
0
    }
698
0
    return CreateWritableEncryptedFile(fname, underlying, options, result, dbg);
699
0
  }
700
701
  IOStatus NewRandomRWFile(const std::string& fname, const FileOptions& options,
702
                           std::unique_ptr<FSRandomRWFile>* result,
703
0
                           IODebugContext* dbg) override {
704
0
    result->reset();
705
0
    if (options.use_mmap_reads || options.use_mmap_writes) {
706
0
      return IOStatus::InvalidArgument();
707
0
    }
708
    // Check file exists
709
0
    bool isNewFile = !FileExists(fname, options.io_options, dbg).ok();
710
711
    // Open file using underlying Env implementation
712
0
    std::unique_ptr<FSRandomRWFile> underlying;
713
0
    auto status =
714
0
        FileSystemWrapper::NewRandomRWFile(fname, options, &underlying, dbg);
715
0
    if (!status.ok()) {
716
0
      return status;
717
0
    }
718
    // Create cipher stream
719
0
    std::unique_ptr<BlockAccessCipherStream> stream;
720
0
    size_t prefix_length = 0;
721
0
    if (!isNewFile) {
722
      // File already exists, read prefix
723
0
      status = CreateRandomReadCipherStream(fname, underlying, options,
724
0
                                            &prefix_length, &stream, dbg);
725
0
    } else {
726
0
      status = CreateRandomWriteCipherStream(fname, underlying, options,
727
0
                                             &prefix_length, &stream, dbg);
728
0
    }
729
0
    if (status.ok()) {
730
0
      if (stream) {
731
0
        result->reset(new EncryptedRandomRWFile(
732
0
            std::move(underlying), std::move(stream), prefix_length));
733
0
      } else {
734
0
        result->reset(underlying.release());
735
0
      }
736
0
    }
737
0
    return status;
738
0
  }
739
740
  IOStatus GetChildrenFileAttributes(const std::string& dir,
741
                                     const IOOptions& options,
742
                                     std::vector<FileAttributes>* result,
743
0
                                     IODebugContext* dbg) override {
744
0
    auto status =
745
0
        FileSystemWrapper::GetChildrenFileAttributes(dir, options, result, dbg);
746
0
    if (!status.ok()) {
747
0
      return status;
748
0
    }
749
0
    for (auto it = std::begin(*result); it != std::end(*result); ++it) {
750
      // assert(it->size_bytes >= prefixLength);
751
      //  breaks env_basic_test when called on directory containing
752
      //  directories
753
      // which makes subtraction of prefixLength worrisome since
754
      // FileAttributes does not identify directories
755
0
      EncryptionProvider* provider;
756
0
      status = GetReadableProvider(it->name, &provider);
757
0
      if (!status.ok()) {
758
0
        return status;
759
0
      } else if (provider != nullptr) {
760
0
        it->size_bytes -= provider->GetPrefixLength();
761
0
      }
762
0
    }
763
0
    return IOStatus::OK();
764
0
  }
765
766
  IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
767
0
                       uint64_t* file_size, IODebugContext* dbg) override {
768
0
    auto status =
769
0
        FileSystemWrapper::GetFileSize(fname, options, file_size, dbg);
770
0
    if (!status.ok() || !(*file_size)) {
771
0
      return status;
772
0
    }
773
0
    EncryptionProvider* provider;
774
0
    status = GetReadableProvider(fname, &provider);
775
0
    if (provider != nullptr && status.ok()) {
776
0
      size_t prefixLength = provider->GetPrefixLength();
777
0
      assert(*file_size >= prefixLength);
778
0
      *file_size -= prefixLength;
779
0
    }
780
0
    return status;
781
0
  }
782
783
 private:
784
  std::shared_ptr<EncryptionProvider> provider_;
785
};
786
}  // namespace
787
788
Status NewEncryptedFileSystemImpl(
789
    const std::shared_ptr<FileSystem>& base,
790
    const std::shared_ptr<EncryptionProvider>& provider,
791
0
    std::unique_ptr<FileSystem>* result) {
792
0
  result->reset(new EncryptedFileSystemImpl(base, provider));
793
0
  return Status::OK();
794
0
}
795
796
std::shared_ptr<FileSystem> NewEncryptedFS(
797
    const std::shared_ptr<FileSystem>& base,
798
0
    const std::shared_ptr<EncryptionProvider>& provider) {
799
0
  std::unique_ptr<FileSystem> efs;
800
0
  Status s = NewEncryptedFileSystemImpl(base, provider, &efs);
801
0
  if (s.ok()) {
802
0
    s = efs->PrepareOptions(ConfigOptions());
803
0
  }
804
0
  if (s.ok()) {
805
0
    std::shared_ptr<FileSystem> result(efs.release());
806
0
    return result;
807
0
  } else {
808
0
    return nullptr;
809
0
  }
810
0
}
811
812
Env* NewEncryptedEnv(Env* base_env,
813
0
                     const std::shared_ptr<EncryptionProvider>& provider) {
814
0
  return new CompositeEnvWrapper(
815
0
      base_env, NewEncryptedFS(base_env->GetFileSystem(), provider));
816
0
}
817
818
Status BlockAccessCipherStream::Encrypt(uint64_t fileOffset, char* data,
819
0
                                        size_t dataSize) {
820
  // Calculate block index
821
0
  auto blockSize = BlockSize();
822
0
  uint64_t blockIndex = fileOffset / blockSize;
823
0
  size_t blockOffset = fileOffset % blockSize;
824
0
  std::unique_ptr<char[]> blockBuffer;
825
826
0
  std::string scratch;
827
0
  AllocateScratch(scratch);
828
829
  // Encrypt individual blocks.
830
0
  while (true) {
831
0
    char* block = data;
832
0
    size_t n = std::min(dataSize, blockSize - blockOffset);
833
0
    if (n != blockSize) {
834
      // We're not encrypting a full block.
835
      // Copy data to blockBuffer
836
0
      if (!blockBuffer) {
837
        // Allocate buffer
838
0
        blockBuffer = std::unique_ptr<char[]>(new char[blockSize]);
839
0
      }
840
0
      block = blockBuffer.get();
841
      // Copy plain data to block buffer
842
0
      memmove(block + blockOffset, data, n);
843
0
    }
844
0
    auto status = EncryptBlock(blockIndex, block, (char*)scratch.data());
845
0
    if (!status.ok()) {
846
0
      return status;
847
0
    }
848
0
    if (block != data) {
849
      // Copy encrypted data back to `data`.
850
0
      memmove(data, block + blockOffset, n);
851
0
    }
852
0
    dataSize -= n;
853
0
    if (dataSize == 0) {
854
0
      return Status::OK();
855
0
    }
856
0
    data += n;
857
0
    blockOffset = 0;
858
0
    blockIndex++;
859
0
  }
860
0
}
861
862
Status BlockAccessCipherStream::Decrypt(uint64_t fileOffset, char* data,
863
0
                                        size_t dataSize) {
864
  // Calculate block index
865
0
  auto blockSize = BlockSize();
866
0
  uint64_t blockIndex = fileOffset / blockSize;
867
0
  size_t blockOffset = fileOffset % blockSize;
868
0
  std::unique_ptr<char[]> blockBuffer;
869
870
0
  std::string scratch;
871
0
  AllocateScratch(scratch);
872
873
  // Decrypt individual blocks.
874
0
  while (true) {
875
0
    char* block = data;
876
0
    size_t n = std::min(dataSize, blockSize - blockOffset);
877
0
    if (n != blockSize) {
878
      // We're not decrypting a full block.
879
      // Copy data to blockBuffer
880
0
      if (!blockBuffer) {
881
        // Allocate buffer
882
0
        blockBuffer = std::unique_ptr<char[]>(new char[blockSize]);
883
0
      }
884
0
      block = blockBuffer.get();
885
      // Copy encrypted data to block buffer
886
0
      memmove(block + blockOffset, data, n);
887
0
    }
888
0
    auto status = DecryptBlock(blockIndex, block, (char*)scratch.data());
889
0
    if (!status.ok()) {
890
0
      return status;
891
0
    }
892
0
    if (block != data) {
893
      // Copy decrypted data back to `data`.
894
0
      memmove(data, block + blockOffset, n);
895
0
    }
896
897
    // Simply decrementing dataSize by n could cause it to underflow,
898
    // which will very likely make it read over the original bounds later
899
0
    assert(dataSize >= n);
900
0
    if (dataSize < n) {
901
0
      return Status::Corruption("Cannot decrypt data at given offset");
902
0
    }
903
904
0
    dataSize -= n;
905
0
    if (dataSize == 0) {
906
0
      return Status::OK();
907
0
    }
908
0
    data += n;
909
0
    blockOffset = 0;
910
0
    blockIndex++;
911
0
  }
912
0
}
913
914
namespace {
915
static std::unordered_map<std::string, OptionTypeInfo>
916
    rot13_block_cipher_type_info = {
917
        {"block_size",
918
         {0 /* No offset, whole struct*/, OptionType::kInt,
919
          OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
920
};
921
922
// Implements a BlockCipher using ROT13.
923
//
924
// Note: This is a sample implementation of BlockCipher,
925
// it is NOT considered safe and should NOT be used in production.
926
class ROT13BlockCipher : public BlockCipher {
927
 private:
928
  size_t blockSize_;
929
930
 public:
931
0
  explicit ROT13BlockCipher(size_t blockSize) : blockSize_(blockSize) {
932
0
    RegisterOptions("ROT13BlockCipherOptions", &blockSize_,
933
0
                    &rot13_block_cipher_type_info);
934
0
  }
935
936
0
  static const char* kClassName() { return "ROT13"; }
937
0
  const char* Name() const override { return kClassName(); }
938
939
0
  size_t BlockSize() override { return blockSize_; }
940
0
  Status Encrypt(char* data) override {
941
0
    for (size_t i = 0; i < blockSize_; ++i) {
942
0
      data[i] += 13;
943
0
    }
944
0
    return Status::OK();
945
0
  }
946
0
  Status Decrypt(char* data) override { return Encrypt(data); }
947
};
948
949
static const std::unordered_map<std::string, OptionTypeInfo>
950
    ctr_encryption_provider_type_info = {
951
        {"cipher",
952
         OptionTypeInfo::AsCustomSharedPtr<BlockCipher>(
953
             0 /* No offset, whole struct*/, OptionVerificationType::kByName,
954
             OptionTypeFlags::kNone)},
955
};
956
}  // anonymous namespace
957
958
0
void CTRCipherStream::AllocateScratch(std::string& scratch) {
959
0
  auto blockSize = cipher_->BlockSize();
960
0
  scratch.reserve(blockSize);
961
0
}
962
963
Status CTRCipherStream::EncryptBlock(uint64_t blockIndex, char* data,
964
0
                                     char* scratch) {
965
  // Create nonce + counter
966
0
  auto blockSize = cipher_->BlockSize();
967
0
  memmove(scratch, iv_.data(), blockSize);
968
0
  EncodeFixed64(scratch, blockIndex + initialCounter_);
969
970
  // Encrypt nonce + counter
971
0
  auto status = cipher_->Encrypt(scratch);
972
0
  if (!status.ok()) {
973
0
    return status;
974
0
  }
975
976
  // XOR data with ciphertext.
977
0
  for (size_t i = 0; i < blockSize; i++) {
978
0
    data[i] = data[i] ^ scratch[i];
979
0
  }
980
0
  return Status::OK();
981
0
}
982
983
Status CTRCipherStream::DecryptBlock(uint64_t blockIndex, char* data,
984
0
                                     char* scratch) {
985
  // For CTR decryption & encryption are the same
986
0
  return EncryptBlock(blockIndex, data, scratch);
987
0
}
988
989
CTREncryptionProvider::CTREncryptionProvider(
990
    const std::shared_ptr<BlockCipher>& c)
991
0
    : cipher_(c) {
992
0
  RegisterOptions("Cipher", &cipher_, &ctr_encryption_provider_type_info);
993
0
}
994
995
0
bool CTREncryptionProvider::IsInstanceOf(const std::string& name) const {
996
  // Special case for test purposes.
997
0
  if (name == "1://test" && cipher_ != nullptr) {
998
0
    return cipher_->IsInstanceOf(ROT13BlockCipher::kClassName());
999
0
  } else {
1000
0
    return EncryptionProvider::IsInstanceOf(name);
1001
0
  }
1002
0
}
1003
1004
0
size_t CTREncryptionProvider::GetPrefixLength() const {
1005
0
  return defaultPrefixLength;
1006
0
}
1007
1008
Status CTREncryptionProvider::AddCipher(const std::string& /*descriptor*/,
1009
                                        const char* cipher, size_t len,
1010
0
                                        bool /*for_write*/) {
1011
0
  if (cipher_) {
1012
0
    return Status::NotSupported("Cannot add keys to CTREncryptionProvider");
1013
0
  } else if (strcmp(ROT13BlockCipher::kClassName(), cipher) == 0) {
1014
0
    cipher_.reset(new ROT13BlockCipher(len));
1015
0
    return Status::OK();
1016
0
  } else {
1017
0
    return BlockCipher::CreateFromString(ConfigOptions(), std::string(cipher),
1018
0
                                         &cipher_);
1019
0
  }
1020
0
}
1021
1022
// decodeCTRParameters decodes the initial counter & IV from the given
1023
// (plain text) prefix.
1024
static void decodeCTRParameters(const char* prefix, size_t blockSize,
1025
0
                                uint64_t& initialCounter, Slice& iv) {
1026
  // First block contains 64-bit initial counter
1027
0
  initialCounter = DecodeFixed64(prefix);
1028
  // Second block contains IV
1029
0
  iv = Slice(prefix + blockSize, blockSize);
1030
0
}
1031
1032
Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/,
1033
                                              char* prefix,
1034
0
                                              size_t prefixLength) const {
1035
0
  if (!cipher_) {
1036
0
    return Status::InvalidArgument("Encryption Cipher is missing");
1037
0
  }
1038
  // Create & seed rnd.
1039
0
  Random rnd((uint32_t)SystemClock::Default()->NowMicros());
1040
  // Fill entire prefix block with random values.
1041
0
  for (size_t i = 0; i < prefixLength; i++) {
1042
0
    prefix[i] = rnd.Uniform(256) & 0xFF;
1043
0
  }
1044
  // Take random data to extract initial counter & IV
1045
0
  auto blockSize = cipher_->BlockSize();
1046
0
  uint64_t initialCounter;
1047
0
  Slice prefixIV;
1048
0
  decodeCTRParameters(prefix, blockSize, initialCounter, prefixIV);
1049
1050
  // Now populate the rest of the prefix, starting from the third block.
1051
0
  PopulateSecretPrefixPart(prefix + (2 * blockSize),
1052
0
                           prefixLength - (2 * blockSize), blockSize);
1053
1054
  // Encrypt the prefix, starting from block 2 (leave block 0, 1 with initial
1055
  // counter & IV unencrypted)
1056
0
  CTRCipherStream cipherStream(cipher_, prefixIV.data(), initialCounter);
1057
0
  Status status;
1058
0
  {
1059
0
    PERF_TIMER_GUARD(encrypt_data_nanos);
1060
0
    status = cipherStream.Encrypt(0, prefix + (2 * blockSize),
1061
0
                                  prefixLength - (2 * blockSize));
1062
0
  }
1063
1064
0
  return status;
1065
0
}
1066
1067
// PopulateSecretPrefixPart initializes the data into a new prefix block
1068
// in plain text.
1069
// Returns the amount of space (starting from the start of the prefix)
1070
// that has been initialized.
1071
size_t CTREncryptionProvider::PopulateSecretPrefixPart(
1072
0
    char* /*prefix*/, size_t /*prefixLength*/, size_t /*blockSize*/) const {
1073
  // Nothing to do here, put in custom data in override when needed.
1074
0
  return 0;
1075
0
}
1076
1077
Status CTREncryptionProvider::CreateCipherStream(
1078
    const std::string& fname, const EnvOptions& options, Slice& prefix,
1079
0
    std::unique_ptr<BlockAccessCipherStream>* result) {
1080
0
  if (!cipher_) {
1081
0
    return Status::InvalidArgument("Encryption Cipher is missing");
1082
0
  }
1083
  // Read plain text part of prefix.
1084
0
  auto blockSize = cipher_->BlockSize();
1085
0
  uint64_t initialCounter;
1086
0
  Slice iv;
1087
0
  decodeCTRParameters(prefix.data(), blockSize, initialCounter, iv);
1088
1089
  // If the prefix is smaller than twice the block size, we would below read a
1090
  // very large chunk of the file (and very likely read over the bounds)
1091
0
  assert(prefix.size() >= 2 * blockSize);
1092
0
  if (prefix.size() < 2 * blockSize) {
1093
0
    return Status::Corruption("Unable to read from file " + fname +
1094
0
                              ": read attempt would read beyond file bounds");
1095
0
  }
1096
1097
  // Decrypt the encrypted part of the prefix, starting from block 2 (block 0, 1
1098
  // with initial counter & IV are unencrypted)
1099
0
  CTRCipherStream cipherStream(cipher_, iv.data(), initialCounter);
1100
0
  Status status;
1101
0
  {
1102
0
    PERF_TIMER_GUARD(decrypt_data_nanos);
1103
0
    status = cipherStream.Decrypt(0, (char*)prefix.data() + (2 * blockSize),
1104
0
                                  prefix.size() - (2 * blockSize));
1105
0
  }
1106
0
  if (!status.ok()) {
1107
0
    return status;
1108
0
  }
1109
1110
  // Create cipher stream
1111
0
  return CreateCipherStreamFromPrefix(fname, options, initialCounter, iv,
1112
0
                                      prefix, result);
1113
0
}
1114
1115
// CreateCipherStreamFromPrefix creates a block access cipher stream for a file
1116
// given name and options. The given prefix is already decrypted.
1117
Status CTREncryptionProvider::CreateCipherStreamFromPrefix(
1118
    const std::string& /*fname*/, const EnvOptions& /*options*/,
1119
    uint64_t initialCounter, const Slice& iv, const Slice& /*prefix*/,
1120
0
    std::unique_ptr<BlockAccessCipherStream>* result) {
1121
0
  (*result) = std::unique_ptr<BlockAccessCipherStream>(
1122
0
      new CTRCipherStream(cipher_, iv.data(), initialCounter));
1123
0
  return Status::OK();
1124
0
}
1125
1126
namespace {
1127
0
static void RegisterEncryptionBuiltins() {
1128
0
  static std::once_flag once;
1129
0
  std::call_once(once, [&]() {
1130
0
    auto lib = ObjectRegistry::Default()->AddLibrary("encryption");
1131
    // Match "CTR" or "CTR://test"
1132
0
    lib->AddFactory<EncryptionProvider>(
1133
0
        ObjectLibrary::PatternEntry(CTREncryptionProvider::kClassName(), true)
1134
0
            .AddSuffix("://test"),
1135
0
        [](const std::string& uri, std::unique_ptr<EncryptionProvider>* guard,
1136
0
           std::string* /*errmsg*/) {
1137
0
          if (EndsWith(uri, "://test")) {
1138
0
            std::shared_ptr<BlockCipher> cipher =
1139
0
                std::make_shared<ROT13BlockCipher>(32);
1140
0
            guard->reset(new CTREncryptionProvider(cipher));
1141
0
          } else {
1142
0
            guard->reset(new CTREncryptionProvider());
1143
0
          }
1144
0
          return guard->get();
1145
0
        });
1146
1147
0
    lib->AddFactory<EncryptionProvider>(
1148
0
        "1://test", [](const std::string& /*uri*/,
1149
0
                       std::unique_ptr<EncryptionProvider>* guard,
1150
0
                       std::string* /*errmsg*/) {
1151
0
          std::shared_ptr<BlockCipher> cipher =
1152
0
              std::make_shared<ROT13BlockCipher>(32);
1153
0
          guard->reset(new CTREncryptionProvider(cipher));
1154
0
          return guard->get();
1155
0
        });
1156
1157
    // Match "ROT13" or "ROT13:[0-9]+"
1158
0
    lib->AddFactory<BlockCipher>(
1159
0
        ObjectLibrary::PatternEntry(ROT13BlockCipher::kClassName(), true)
1160
0
            .AddNumber(":"),
1161
0
        [](const std::string& uri, std::unique_ptr<BlockCipher>* guard,
1162
0
           std::string* /* errmsg */) {
1163
0
          size_t colon = uri.find(':');
1164
0
          if (colon != std::string::npos) {
1165
0
            size_t block_size = ParseSizeT(uri.substr(colon + 1));
1166
0
            guard->reset(new ROT13BlockCipher(block_size));
1167
0
          } else {
1168
0
            guard->reset(new ROT13BlockCipher(32));
1169
0
          }
1170
1171
0
          return guard->get();
1172
0
        });
1173
0
  });
1174
0
}
1175
}  // namespace
1176
1177
Status BlockCipher::CreateFromString(const ConfigOptions& config_options,
1178
                                     const std::string& value,
1179
0
                                     std::shared_ptr<BlockCipher>* result) {
1180
0
  RegisterEncryptionBuiltins();
1181
0
  return LoadSharedObject<BlockCipher>(config_options, value, result);
1182
0
}
1183
1184
Status EncryptionProvider::CreateFromString(
1185
    const ConfigOptions& config_options, const std::string& value,
1186
0
    std::shared_ptr<EncryptionProvider>* result) {
1187
0
  RegisterEncryptionBuiltins();
1188
0
  return LoadSharedObject<EncryptionProvider>(config_options, value, result);
1189
0
}
1190
1191
1192
}  // namespace ROCKSDB_NAMESPACE