env_encryption.cc 43 KB

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