env_encryption.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  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. #ifndef ROCKSDB_LITE
  6. #include <algorithm>
  7. #include <cassert>
  8. #include <cctype>
  9. #include <iostream>
  10. #include "rocksdb/env_encryption.h"
  11. #include "util/aligned_buffer.h"
  12. #include "util/coding.h"
  13. #include "util/random.h"
  14. #endif
  15. namespace ROCKSDB_NAMESPACE {
  16. #ifndef ROCKSDB_LITE
  17. class EncryptedSequentialFile : public SequentialFile {
  18. private:
  19. std::unique_ptr<SequentialFile> file_;
  20. std::unique_ptr<BlockAccessCipherStream> stream_;
  21. uint64_t offset_;
  22. size_t prefixLength_;
  23. public:
  24. // Default ctor. Given underlying sequential file is supposed to be at
  25. // offset == prefixLength.
  26. EncryptedSequentialFile(SequentialFile* f, BlockAccessCipherStream* s, size_t prefixLength)
  27. : file_(f), stream_(s), offset_(prefixLength), prefixLength_(prefixLength) {
  28. }
  29. // Read up to "n" bytes from the file. "scratch[0..n-1]" may be
  30. // written by this routine. Sets "*result" to the data that was
  31. // read (including if fewer than "n" bytes were successfully read).
  32. // May set "*result" to point at data in "scratch[0..n-1]", so
  33. // "scratch[0..n-1]" must be live when "*result" is used.
  34. // If an error was encountered, returns a non-OK status.
  35. //
  36. // REQUIRES: External synchronization
  37. Status Read(size_t n, Slice* result, char* scratch) override {
  38. assert(scratch);
  39. Status status = file_->Read(n, result, scratch);
  40. if (!status.ok()) {
  41. return status;
  42. }
  43. status = stream_->Decrypt(offset_, (char*)result->data(), result->size());
  44. offset_ += result->size(); // We've already ready data from disk, so update offset_ even if decryption fails.
  45. return status;
  46. }
  47. // Skip "n" bytes from the file. This is guaranteed to be no
  48. // slower that reading the same data, but may be faster.
  49. //
  50. // If end of file is reached, skipping will stop at the end of the
  51. // file, and Skip will return OK.
  52. //
  53. // REQUIRES: External synchronization
  54. Status Skip(uint64_t n) override {
  55. auto status = file_->Skip(n);
  56. if (!status.ok()) {
  57. return status;
  58. }
  59. offset_ += n;
  60. return status;
  61. }
  62. // Indicates the upper layers if the current SequentialFile implementation
  63. // uses direct IO.
  64. bool use_direct_io() const override { return file_->use_direct_io(); }
  65. // Use the returned alignment value to allocate
  66. // aligned buffer for Direct I/O
  67. size_t GetRequiredBufferAlignment() const override {
  68. return file_->GetRequiredBufferAlignment();
  69. }
  70. // Remove any kind of caching of data from the offset to offset+length
  71. // of this file. If the length is 0, then it refers to the end of file.
  72. // If the system is not caching the file contents, then this is a noop.
  73. Status InvalidateCache(size_t offset, size_t length) override {
  74. return file_->InvalidateCache(offset + prefixLength_, length);
  75. }
  76. // Positioned Read for direct I/O
  77. // If Direct I/O enabled, offset, n, and scratch should be properly aligned
  78. Status PositionedRead(uint64_t offset, size_t n, Slice* result,
  79. char* scratch) override {
  80. assert(scratch);
  81. offset += prefixLength_; // Skip prefix
  82. auto status = file_->PositionedRead(offset, n, result, scratch);
  83. if (!status.ok()) {
  84. return status;
  85. }
  86. offset_ = offset + result->size();
  87. status = stream_->Decrypt(offset, (char*)result->data(), result->size());
  88. return status;
  89. }
  90. };
  91. // A file abstraction for randomly reading the contents of a file.
  92. class EncryptedRandomAccessFile : public RandomAccessFile {
  93. private:
  94. std::unique_ptr<RandomAccessFile> file_;
  95. std::unique_ptr<BlockAccessCipherStream> stream_;
  96. size_t prefixLength_;
  97. public:
  98. EncryptedRandomAccessFile(RandomAccessFile* f, BlockAccessCipherStream* s, size_t prefixLength)
  99. : file_(f), stream_(s), prefixLength_(prefixLength) { }
  100. // Read up to "n" bytes from the file starting at "offset".
  101. // "scratch[0..n-1]" may be written by this routine. Sets "*result"
  102. // to the data that was read (including if fewer than "n" bytes were
  103. // successfully read). May set "*result" to point at data in
  104. // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
  105. // "*result" is used. If an error was encountered, returns a non-OK
  106. // status.
  107. //
  108. // Safe for concurrent use by multiple threads.
  109. // If Direct I/O enabled, offset, n, and scratch should be aligned properly.
  110. Status Read(uint64_t offset, size_t n, Slice* result,
  111. char* scratch) const override {
  112. assert(scratch);
  113. offset += prefixLength_;
  114. auto status = file_->Read(offset, n, result, scratch);
  115. if (!status.ok()) {
  116. return status;
  117. }
  118. status = stream_->Decrypt(offset, (char*)result->data(), result->size());
  119. return status;
  120. }
  121. // Readahead the file starting from offset by n bytes for caching.
  122. Status Prefetch(uint64_t offset, size_t n) override {
  123. //return Status::OK();
  124. return file_->Prefetch(offset + prefixLength_, n);
  125. }
  126. // Tries to get an unique ID for this file that will be the same each time
  127. // the file is opened (and will stay the same while the file is open).
  128. // Furthermore, it tries to make this ID at most "max_size" bytes. If such an
  129. // ID can be created this function returns the length of the ID and places it
  130. // in "id"; otherwise, this function returns 0, in which case "id"
  131. // may not have been modified.
  132. //
  133. // This function guarantees, for IDs from a given environment, two unique ids
  134. // cannot be made equal to each other by adding arbitrary bytes to one of
  135. // them. That is, no unique ID is the prefix of another.
  136. //
  137. // This function guarantees that the returned ID will not be interpretable as
  138. // a single varint.
  139. //
  140. // Note: these IDs are only valid for the duration of the process.
  141. size_t GetUniqueId(char* id, size_t max_size) const override {
  142. return file_->GetUniqueId(id, max_size);
  143. };
  144. void Hint(AccessPattern pattern) override { file_->Hint(pattern); }
  145. // Indicates the upper layers if the current RandomAccessFile implementation
  146. // uses direct IO.
  147. bool use_direct_io() const override { return file_->use_direct_io(); }
  148. // Use the returned alignment value to allocate
  149. // aligned buffer for Direct I/O
  150. size_t GetRequiredBufferAlignment() const override {
  151. return file_->GetRequiredBufferAlignment();
  152. }
  153. // Remove any kind of caching of data from the offset to offset+length
  154. // of this file. If the length is 0, then it refers to the end of file.
  155. // If the system is not caching the file contents, then this is a noop.
  156. Status InvalidateCache(size_t offset, size_t length) override {
  157. return file_->InvalidateCache(offset + prefixLength_, length);
  158. }
  159. };
  160. // A file abstraction for sequential writing. The implementation
  161. // must provide buffering since callers may append small fragments
  162. // at a time to the file.
  163. class EncryptedWritableFile : public WritableFileWrapper {
  164. private:
  165. std::unique_ptr<WritableFile> file_;
  166. std::unique_ptr<BlockAccessCipherStream> stream_;
  167. size_t prefixLength_;
  168. public:
  169. // Default ctor. Prefix is assumed to be written already.
  170. EncryptedWritableFile(WritableFile* f, BlockAccessCipherStream* s, size_t prefixLength)
  171. : WritableFileWrapper(f), file_(f), stream_(s), prefixLength_(prefixLength) { }
  172. Status Append(const Slice& data) override {
  173. AlignedBuffer buf;
  174. Status status;
  175. Slice dataToAppend(data);
  176. if (data.size() > 0) {
  177. auto offset = file_->GetFileSize(); // size including prefix
  178. // Encrypt in cloned buffer
  179. buf.Alignment(GetRequiredBufferAlignment());
  180. buf.AllocateNewBuffer(data.size());
  181. // TODO (sagar0): Modify AlignedBuffer.Append to allow doing a memmove
  182. // so that the next two lines can be replaced with buf.Append().
  183. memmove(buf.BufferStart(), data.data(), data.size());
  184. buf.Size(data.size());
  185. status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize());
  186. if (!status.ok()) {
  187. return status;
  188. }
  189. dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize());
  190. }
  191. status = file_->Append(dataToAppend);
  192. if (!status.ok()) {
  193. return status;
  194. }
  195. return status;
  196. }
  197. Status PositionedAppend(const Slice& data, uint64_t offset) override {
  198. AlignedBuffer buf;
  199. Status status;
  200. Slice dataToAppend(data);
  201. offset += prefixLength_;
  202. if (data.size() > 0) {
  203. // Encrypt in cloned buffer
  204. buf.Alignment(GetRequiredBufferAlignment());
  205. buf.AllocateNewBuffer(data.size());
  206. memmove(buf.BufferStart(), data.data(), data.size());
  207. buf.Size(data.size());
  208. status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize());
  209. if (!status.ok()) {
  210. return status;
  211. }
  212. dataToAppend = Slice(buf.BufferStart(), buf.CurrentSize());
  213. }
  214. status = file_->PositionedAppend(dataToAppend, offset);
  215. if (!status.ok()) {
  216. return status;
  217. }
  218. return status;
  219. }
  220. // Indicates the upper layers if the current WritableFile implementation
  221. // uses direct IO.
  222. bool use_direct_io() const override { return file_->use_direct_io(); }
  223. // Use the returned alignment value to allocate
  224. // aligned buffer for Direct I/O
  225. size_t GetRequiredBufferAlignment() const override {
  226. return file_->GetRequiredBufferAlignment();
  227. }
  228. /*
  229. * Get the size of valid data in the file.
  230. */
  231. uint64_t GetFileSize() override {
  232. return file_->GetFileSize() - prefixLength_;
  233. }
  234. // Truncate is necessary to trim the file to the correct size
  235. // before closing. It is not always possible to keep track of the file
  236. // size due to whole pages writes. The behavior is undefined if called
  237. // with other writes to follow.
  238. Status Truncate(uint64_t size) override {
  239. return file_->Truncate(size + prefixLength_);
  240. }
  241. // Remove any kind of caching of data from the offset to offset+length
  242. // of this file. If the length is 0, then it refers to the end of file.
  243. // If the system is not caching the file contents, then this is a noop.
  244. // This call has no effect on dirty pages in the cache.
  245. Status InvalidateCache(size_t offset, size_t length) override {
  246. return file_->InvalidateCache(offset + prefixLength_, length);
  247. }
  248. // Sync a file range with disk.
  249. // offset is the starting byte of the file range to be synchronized.
  250. // nbytes specifies the length of the range to be synchronized.
  251. // This asks the OS to initiate flushing the cached data to disk,
  252. // without waiting for completion.
  253. // Default implementation does nothing.
  254. Status RangeSync(uint64_t offset, uint64_t nbytes) override {
  255. return file_->RangeSync(offset + prefixLength_, nbytes);
  256. }
  257. // PrepareWrite performs any necessary preparation for a write
  258. // before the write actually occurs. This allows for pre-allocation
  259. // of space on devices where it can result in less file
  260. // fragmentation and/or less waste from over-zealous filesystem
  261. // pre-allocation.
  262. void PrepareWrite(size_t offset, size_t len) override {
  263. file_->PrepareWrite(offset + prefixLength_, len);
  264. }
  265. // Pre-allocates space for a file.
  266. Status Allocate(uint64_t offset, uint64_t len) override {
  267. return file_->Allocate(offset + prefixLength_, len);
  268. }
  269. };
  270. // A file abstraction for random reading and writing.
  271. class EncryptedRandomRWFile : public RandomRWFile {
  272. private:
  273. std::unique_ptr<RandomRWFile> file_;
  274. std::unique_ptr<BlockAccessCipherStream> stream_;
  275. size_t prefixLength_;
  276. public:
  277. EncryptedRandomRWFile(RandomRWFile* f, BlockAccessCipherStream* s, size_t prefixLength)
  278. : file_(f), stream_(s), prefixLength_(prefixLength) {}
  279. // Indicates if the class makes use of direct I/O
  280. // If false you must pass aligned buffer to Write()
  281. bool use_direct_io() const override { return file_->use_direct_io(); }
  282. // Use the returned alignment value to allocate
  283. // aligned buffer for Direct I/O
  284. size_t GetRequiredBufferAlignment() const override {
  285. return file_->GetRequiredBufferAlignment();
  286. }
  287. // Write bytes in `data` at offset `offset`, Returns Status::OK() on success.
  288. // Pass aligned buffer when use_direct_io() returns true.
  289. Status Write(uint64_t offset, const Slice& data) override {
  290. AlignedBuffer buf;
  291. Status status;
  292. Slice dataToWrite(data);
  293. offset += prefixLength_;
  294. if (data.size() > 0) {
  295. // Encrypt in cloned buffer
  296. buf.Alignment(GetRequiredBufferAlignment());
  297. buf.AllocateNewBuffer(data.size());
  298. memmove(buf.BufferStart(), data.data(), data.size());
  299. buf.Size(data.size());
  300. status = stream_->Encrypt(offset, buf.BufferStart(), buf.CurrentSize());
  301. if (!status.ok()) {
  302. return status;
  303. }
  304. dataToWrite = Slice(buf.BufferStart(), buf.CurrentSize());
  305. }
  306. status = file_->Write(offset, dataToWrite);
  307. return status;
  308. }
  309. // Read up to `n` bytes starting from offset `offset` and store them in
  310. // result, provided `scratch` size should be at least `n`.
  311. // Returns Status::OK() on success.
  312. Status Read(uint64_t offset, size_t n, Slice* result,
  313. char* scratch) const override {
  314. assert(scratch);
  315. offset += prefixLength_;
  316. auto status = file_->Read(offset, n, result, scratch);
  317. if (!status.ok()) {
  318. return status;
  319. }
  320. status = stream_->Decrypt(offset, (char*)result->data(), result->size());
  321. return status;
  322. }
  323. Status Flush() override { return file_->Flush(); }
  324. Status Sync() override { return file_->Sync(); }
  325. Status Fsync() override { return file_->Fsync(); }
  326. Status Close() override { return file_->Close(); }
  327. };
  328. // EncryptedEnv implements an Env wrapper that adds encryption to files stored on disk.
  329. class EncryptedEnv : public EnvWrapper {
  330. public:
  331. EncryptedEnv(Env* base_env, EncryptionProvider *provider)
  332. : EnvWrapper(base_env) {
  333. provider_ = provider;
  334. }
  335. // NewSequentialFile opens a file for sequential reading.
  336. Status NewSequentialFile(const std::string& fname,
  337. std::unique_ptr<SequentialFile>* result,
  338. const EnvOptions& options) override {
  339. result->reset();
  340. if (options.use_mmap_reads) {
  341. return Status::InvalidArgument();
  342. }
  343. // Open file using underlying Env implementation
  344. std::unique_ptr<SequentialFile> underlying;
  345. auto status = EnvWrapper::NewSequentialFile(fname, &underlying, options);
  346. if (!status.ok()) {
  347. return status;
  348. }
  349. // Read prefix (if needed)
  350. AlignedBuffer prefixBuf;
  351. Slice prefixSlice;
  352. size_t prefixLength = provider_->GetPrefixLength();
  353. if (prefixLength > 0) {
  354. // Read prefix
  355. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  356. prefixBuf.AllocateNewBuffer(prefixLength);
  357. status = underlying->Read(prefixLength, &prefixSlice, prefixBuf.BufferStart());
  358. if (!status.ok()) {
  359. return status;
  360. }
  361. prefixBuf.Size(prefixLength);
  362. }
  363. // Create cipher stream
  364. std::unique_ptr<BlockAccessCipherStream> stream;
  365. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  366. if (!status.ok()) {
  367. return status;
  368. }
  369. (*result) = std::unique_ptr<SequentialFile>(new EncryptedSequentialFile(underlying.release(), stream.release(), prefixLength));
  370. return Status::OK();
  371. }
  372. // NewRandomAccessFile opens a file for random read access.
  373. Status NewRandomAccessFile(const std::string& fname,
  374. std::unique_ptr<RandomAccessFile>* result,
  375. const EnvOptions& options) override {
  376. result->reset();
  377. if (options.use_mmap_reads) {
  378. return Status::InvalidArgument();
  379. }
  380. // Open file using underlying Env implementation
  381. std::unique_ptr<RandomAccessFile> underlying;
  382. auto status = EnvWrapper::NewRandomAccessFile(fname, &underlying, options);
  383. if (!status.ok()) {
  384. return status;
  385. }
  386. // Read prefix (if needed)
  387. AlignedBuffer prefixBuf;
  388. Slice prefixSlice;
  389. size_t prefixLength = provider_->GetPrefixLength();
  390. if (prefixLength > 0) {
  391. // Read prefix
  392. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  393. prefixBuf.AllocateNewBuffer(prefixLength);
  394. status = underlying->Read(0, prefixLength, &prefixSlice, prefixBuf.BufferStart());
  395. if (!status.ok()) {
  396. return status;
  397. }
  398. prefixBuf.Size(prefixLength);
  399. }
  400. // Create cipher stream
  401. std::unique_ptr<BlockAccessCipherStream> stream;
  402. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  403. if (!status.ok()) {
  404. return status;
  405. }
  406. (*result) = std::unique_ptr<RandomAccessFile>(new EncryptedRandomAccessFile(underlying.release(), stream.release(), prefixLength));
  407. return Status::OK();
  408. }
  409. // NewWritableFile opens a file for sequential writing.
  410. Status NewWritableFile(const std::string& fname,
  411. std::unique_ptr<WritableFile>* result,
  412. const EnvOptions& options) override {
  413. result->reset();
  414. if (options.use_mmap_writes) {
  415. return Status::InvalidArgument();
  416. }
  417. // Open file using underlying Env implementation
  418. std::unique_ptr<WritableFile> underlying;
  419. Status status = EnvWrapper::NewWritableFile(fname, &underlying, options);
  420. if (!status.ok()) {
  421. return status;
  422. }
  423. // Initialize & write prefix (if needed)
  424. AlignedBuffer prefixBuf;
  425. Slice prefixSlice;
  426. size_t prefixLength = provider_->GetPrefixLength();
  427. if (prefixLength > 0) {
  428. // Initialize prefix
  429. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  430. prefixBuf.AllocateNewBuffer(prefixLength);
  431. provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength);
  432. prefixBuf.Size(prefixLength);
  433. prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize());
  434. // Write prefix
  435. status = underlying->Append(prefixSlice);
  436. if (!status.ok()) {
  437. return status;
  438. }
  439. }
  440. // Create cipher stream
  441. std::unique_ptr<BlockAccessCipherStream> stream;
  442. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  443. if (!status.ok()) {
  444. return status;
  445. }
  446. (*result) = std::unique_ptr<WritableFile>(new EncryptedWritableFile(underlying.release(), stream.release(), prefixLength));
  447. return Status::OK();
  448. }
  449. // Create an object that writes to a new file with the specified
  450. // name. Deletes any existing file with the same name and creates a
  451. // new file. On success, stores a pointer to the new file in
  452. // *result and returns OK. On failure stores nullptr in *result and
  453. // returns non-OK.
  454. //
  455. // The returned file will only be accessed by one thread at a time.
  456. Status ReopenWritableFile(const std::string& fname,
  457. std::unique_ptr<WritableFile>* result,
  458. const EnvOptions& options) override {
  459. result->reset();
  460. if (options.use_mmap_writes) {
  461. return Status::InvalidArgument();
  462. }
  463. // Open file using underlying Env implementation
  464. std::unique_ptr<WritableFile> underlying;
  465. Status status = EnvWrapper::ReopenWritableFile(fname, &underlying, options);
  466. if (!status.ok()) {
  467. return status;
  468. }
  469. // Initialize & write prefix (if needed)
  470. AlignedBuffer prefixBuf;
  471. Slice prefixSlice;
  472. size_t prefixLength = provider_->GetPrefixLength();
  473. if (prefixLength > 0) {
  474. // Initialize prefix
  475. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  476. prefixBuf.AllocateNewBuffer(prefixLength);
  477. provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength);
  478. prefixBuf.Size(prefixLength);
  479. prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize());
  480. // Write prefix
  481. status = underlying->Append(prefixSlice);
  482. if (!status.ok()) {
  483. return status;
  484. }
  485. }
  486. // Create cipher stream
  487. std::unique_ptr<BlockAccessCipherStream> stream;
  488. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  489. if (!status.ok()) {
  490. return status;
  491. }
  492. (*result) = std::unique_ptr<WritableFile>(new EncryptedWritableFile(underlying.release(), stream.release(), prefixLength));
  493. return Status::OK();
  494. }
  495. // Reuse an existing file by renaming it and opening it as writable.
  496. Status ReuseWritableFile(const std::string& fname,
  497. const std::string& old_fname,
  498. std::unique_ptr<WritableFile>* result,
  499. const EnvOptions& options) override {
  500. result->reset();
  501. if (options.use_mmap_writes) {
  502. return Status::InvalidArgument();
  503. }
  504. // Open file using underlying Env implementation
  505. std::unique_ptr<WritableFile> underlying;
  506. Status status = EnvWrapper::ReuseWritableFile(fname, old_fname, &underlying, options);
  507. if (!status.ok()) {
  508. return status;
  509. }
  510. // Initialize & write prefix (if needed)
  511. AlignedBuffer prefixBuf;
  512. Slice prefixSlice;
  513. size_t prefixLength = provider_->GetPrefixLength();
  514. if (prefixLength > 0) {
  515. // Initialize prefix
  516. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  517. prefixBuf.AllocateNewBuffer(prefixLength);
  518. provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength);
  519. prefixBuf.Size(prefixLength);
  520. prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize());
  521. // Write prefix
  522. status = underlying->Append(prefixSlice);
  523. if (!status.ok()) {
  524. return status;
  525. }
  526. }
  527. // Create cipher stream
  528. std::unique_ptr<BlockAccessCipherStream> stream;
  529. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  530. if (!status.ok()) {
  531. return status;
  532. }
  533. (*result) = std::unique_ptr<WritableFile>(new EncryptedWritableFile(underlying.release(), stream.release(), prefixLength));
  534. return Status::OK();
  535. }
  536. // Open `fname` for random read and write, if file doesn't exist the file
  537. // will be created. On success, stores a pointer to the new file in
  538. // *result and returns OK. On failure returns non-OK.
  539. //
  540. // The returned file will only be accessed by one thread at a time.
  541. Status NewRandomRWFile(const std::string& fname,
  542. std::unique_ptr<RandomRWFile>* result,
  543. const EnvOptions& options) override {
  544. result->reset();
  545. if (options.use_mmap_reads || options.use_mmap_writes) {
  546. return Status::InvalidArgument();
  547. }
  548. // Check file exists
  549. bool isNewFile = !FileExists(fname).ok();
  550. // Open file using underlying Env implementation
  551. std::unique_ptr<RandomRWFile> underlying;
  552. Status status = EnvWrapper::NewRandomRWFile(fname, &underlying, options);
  553. if (!status.ok()) {
  554. return status;
  555. }
  556. // Read or Initialize & write prefix (if needed)
  557. AlignedBuffer prefixBuf;
  558. Slice prefixSlice;
  559. size_t prefixLength = provider_->GetPrefixLength();
  560. if (prefixLength > 0) {
  561. prefixBuf.Alignment(underlying->GetRequiredBufferAlignment());
  562. prefixBuf.AllocateNewBuffer(prefixLength);
  563. if (!isNewFile) {
  564. // File already exists, read prefix
  565. status = underlying->Read(0, prefixLength, &prefixSlice, prefixBuf.BufferStart());
  566. if (!status.ok()) {
  567. return status;
  568. }
  569. prefixBuf.Size(prefixLength);
  570. } else {
  571. // File is new, initialize & write prefix
  572. provider_->CreateNewPrefix(fname, prefixBuf.BufferStart(), prefixLength);
  573. prefixBuf.Size(prefixLength);
  574. prefixSlice = Slice(prefixBuf.BufferStart(), prefixBuf.CurrentSize());
  575. // Write prefix
  576. status = underlying->Write(0, prefixSlice);
  577. if (!status.ok()) {
  578. return status;
  579. }
  580. }
  581. }
  582. // Create cipher stream
  583. std::unique_ptr<BlockAccessCipherStream> stream;
  584. status = provider_->CreateCipherStream(fname, options, prefixSlice, &stream);
  585. if (!status.ok()) {
  586. return status;
  587. }
  588. (*result) = std::unique_ptr<RandomRWFile>(new EncryptedRandomRWFile(underlying.release(), stream.release(), prefixLength));
  589. return Status::OK();
  590. }
  591. // Store in *result the attributes of the children of the specified directory.
  592. // In case the implementation lists the directory prior to iterating the files
  593. // and files are concurrently deleted, the deleted files will be omitted from
  594. // result.
  595. // The name attributes are relative to "dir".
  596. // Original contents of *results are dropped.
  597. // Returns OK if "dir" exists and "*result" contains its children.
  598. // NotFound if "dir" does not exist, the calling process does not have
  599. // permission to access "dir", or if "dir" is invalid.
  600. // IOError if an IO Error was encountered
  601. Status GetChildrenFileAttributes(
  602. const std::string& dir, std::vector<FileAttributes>* result) override {
  603. auto status = EnvWrapper::GetChildrenFileAttributes(dir, result);
  604. if (!status.ok()) {
  605. return status;
  606. }
  607. size_t prefixLength = provider_->GetPrefixLength();
  608. for (auto it = std::begin(*result); it!=std::end(*result); ++it) {
  609. assert(it->size_bytes >= prefixLength);
  610. it->size_bytes -= prefixLength;
  611. }
  612. return Status::OK();
  613. }
  614. // Store the size of fname in *file_size.
  615. Status GetFileSize(const std::string& fname, uint64_t* file_size) override {
  616. auto status = EnvWrapper::GetFileSize(fname, file_size);
  617. if (!status.ok()) {
  618. return status;
  619. }
  620. size_t prefixLength = provider_->GetPrefixLength();
  621. assert(*file_size >= prefixLength);
  622. *file_size -= prefixLength;
  623. return Status::OK();
  624. }
  625. private:
  626. EncryptionProvider *provider_;
  627. };
  628. // Returns an Env that encrypts data when stored on disk and decrypts data when
  629. // read from disk.
  630. Env* NewEncryptedEnv(Env* base_env, EncryptionProvider* provider) {
  631. return new EncryptedEnv(base_env, provider);
  632. }
  633. // Encrypt one or more (partial) blocks of data at the file offset.
  634. // Length of data is given in dataSize.
  635. Status BlockAccessCipherStream::Encrypt(uint64_t fileOffset, char *data, size_t dataSize) {
  636. // Calculate block index
  637. auto blockSize = BlockSize();
  638. uint64_t blockIndex = fileOffset / blockSize;
  639. size_t blockOffset = fileOffset % blockSize;
  640. std::unique_ptr<char[]> blockBuffer;
  641. std::string scratch;
  642. AllocateScratch(scratch);
  643. // Encrypt individual blocks.
  644. while (1) {
  645. char *block = data;
  646. size_t n = std::min(dataSize, blockSize - blockOffset);
  647. if (n != blockSize) {
  648. // We're not encrypting a full block.
  649. // Copy data to blockBuffer
  650. if (!blockBuffer.get()) {
  651. // Allocate buffer
  652. blockBuffer = std::unique_ptr<char[]>(new char[blockSize]);
  653. }
  654. block = blockBuffer.get();
  655. // Copy plain data to block buffer
  656. memmove(block + blockOffset, data, n);
  657. }
  658. auto status = EncryptBlock(blockIndex, block, (char*)scratch.data());
  659. if (!status.ok()) {
  660. return status;
  661. }
  662. if (block != data) {
  663. // Copy encrypted data back to `data`.
  664. memmove(data, block + blockOffset, n);
  665. }
  666. dataSize -= n;
  667. if (dataSize == 0) {
  668. return Status::OK();
  669. }
  670. data += n;
  671. blockOffset = 0;
  672. blockIndex++;
  673. }
  674. }
  675. // Decrypt one or more (partial) blocks of data at the file offset.
  676. // Length of data is given in dataSize.
  677. Status BlockAccessCipherStream::Decrypt(uint64_t fileOffset, char *data, size_t dataSize) {
  678. // Calculate block index
  679. auto blockSize = BlockSize();
  680. uint64_t blockIndex = fileOffset / blockSize;
  681. size_t blockOffset = fileOffset % blockSize;
  682. std::unique_ptr<char[]> blockBuffer;
  683. std::string scratch;
  684. AllocateScratch(scratch);
  685. // Decrypt individual blocks.
  686. while (1) {
  687. char *block = data;
  688. size_t n = std::min(dataSize, blockSize - blockOffset);
  689. if (n != blockSize) {
  690. // We're not decrypting a full block.
  691. // Copy data to blockBuffer
  692. if (!blockBuffer.get()) {
  693. // Allocate buffer
  694. blockBuffer = std::unique_ptr<char[]>(new char[blockSize]);
  695. }
  696. block = blockBuffer.get();
  697. // Copy encrypted data to block buffer
  698. memmove(block + blockOffset, data, n);
  699. }
  700. auto status = DecryptBlock(blockIndex, block, (char*)scratch.data());
  701. if (!status.ok()) {
  702. return status;
  703. }
  704. if (block != data) {
  705. // Copy decrypted data back to `data`.
  706. memmove(data, block + blockOffset, n);
  707. }
  708. // Simply decrementing dataSize by n could cause it to underflow,
  709. // which will very likely make it read over the original bounds later
  710. assert(dataSize >= n);
  711. if (dataSize < n) {
  712. return Status::Corruption("Cannot decrypt data at given offset");
  713. }
  714. dataSize -= n;
  715. if (dataSize == 0) {
  716. return Status::OK();
  717. }
  718. data += n;
  719. blockOffset = 0;
  720. blockIndex++;
  721. }
  722. }
  723. // Encrypt a block of data.
  724. // Length of data is equal to BlockSize().
  725. Status ROT13BlockCipher::Encrypt(char *data) {
  726. for (size_t i = 0; i < blockSize_; ++i) {
  727. data[i] += 13;
  728. }
  729. return Status::OK();
  730. }
  731. // Decrypt a block of data.
  732. // Length of data is equal to BlockSize().
  733. Status ROT13BlockCipher::Decrypt(char *data) {
  734. return Encrypt(data);
  735. }
  736. // Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
  737. void CTRCipherStream::AllocateScratch(std::string& scratch) {
  738. auto blockSize = cipher_.BlockSize();
  739. scratch.reserve(blockSize);
  740. }
  741. // Encrypt a block of data at the given block index.
  742. // Length of data is equal to BlockSize();
  743. Status CTRCipherStream::EncryptBlock(uint64_t blockIndex, char *data, char* scratch) {
  744. // Create nonce + counter
  745. auto blockSize = cipher_.BlockSize();
  746. memmove(scratch, iv_.data(), blockSize);
  747. EncodeFixed64(scratch, blockIndex + initialCounter_);
  748. // Encrypt nonce+counter
  749. auto status = cipher_.Encrypt(scratch);
  750. if (!status.ok()) {
  751. return status;
  752. }
  753. // XOR data with ciphertext.
  754. for (size_t i = 0; i < blockSize; i++) {
  755. data[i] = data[i] ^ scratch[i];
  756. }
  757. return Status::OK();
  758. }
  759. // Decrypt a block of data at the given block index.
  760. // Length of data is equal to BlockSize();
  761. Status CTRCipherStream::DecryptBlock(uint64_t blockIndex, char *data, char* scratch) {
  762. // For CTR decryption & encryption are the same
  763. return EncryptBlock(blockIndex, data, scratch);
  764. }
  765. // GetPrefixLength returns the length of the prefix that is added to every file
  766. // and used for storing encryption options.
  767. // For optimal performance, the prefix length should be a multiple of
  768. // the page size.
  769. size_t CTREncryptionProvider::GetPrefixLength() {
  770. return defaultPrefixLength;
  771. }
  772. // decodeCTRParameters decodes the initial counter & IV from the given
  773. // (plain text) prefix.
  774. static void decodeCTRParameters(const char *prefix, size_t blockSize, uint64_t &initialCounter, Slice &iv) {
  775. // First block contains 64-bit initial counter
  776. initialCounter = DecodeFixed64(prefix);
  777. // Second block contains IV
  778. iv = Slice(prefix + blockSize, blockSize);
  779. }
  780. // CreateNewPrefix initialized an allocated block of prefix memory
  781. // for a new file.
  782. Status CTREncryptionProvider::CreateNewPrefix(const std::string& /*fname*/,
  783. char* prefix,
  784. size_t prefixLength) {
  785. // Create & seed rnd.
  786. Random rnd((uint32_t)Env::Default()->NowMicros());
  787. // Fill entire prefix block with random values.
  788. for (size_t i = 0; i < prefixLength; i++) {
  789. prefix[i] = rnd.Uniform(256) & 0xFF;
  790. }
  791. // Take random data to extract initial counter & IV
  792. auto blockSize = cipher_.BlockSize();
  793. uint64_t initialCounter;
  794. Slice prefixIV;
  795. decodeCTRParameters(prefix, blockSize, initialCounter, prefixIV);
  796. // Now populate the rest of the prefix, starting from the third block.
  797. PopulateSecretPrefixPart(prefix + (2 * blockSize), prefixLength - (2 * blockSize), blockSize);
  798. // Encrypt the prefix, starting from block 2 (leave block 0, 1 with initial counter & IV unencrypted)
  799. CTRCipherStream cipherStream(cipher_, prefixIV.data(), initialCounter);
  800. auto status = cipherStream.Encrypt(0, prefix + (2 * blockSize), prefixLength - (2 * blockSize));
  801. if (!status.ok()) {
  802. return status;
  803. }
  804. return Status::OK();
  805. }
  806. // PopulateSecretPrefixPart initializes the data into a new prefix block
  807. // in plain text.
  808. // Returns the amount of space (starting from the start of the prefix)
  809. // that has been initialized.
  810. size_t CTREncryptionProvider::PopulateSecretPrefixPart(char* /*prefix*/,
  811. size_t /*prefixLength*/,
  812. size_t /*blockSize*/) {
  813. // Nothing to do here, put in custom data in override when needed.
  814. return 0;
  815. }
  816. Status CTREncryptionProvider::CreateCipherStream(
  817. const std::string& fname, const EnvOptions& options, Slice& prefix,
  818. std::unique_ptr<BlockAccessCipherStream>* result) {
  819. // Read plain text part of prefix.
  820. auto blockSize = cipher_.BlockSize();
  821. uint64_t initialCounter;
  822. Slice iv;
  823. decodeCTRParameters(prefix.data(), blockSize, initialCounter, iv);
  824. // If the prefix is smaller than twice the block size, we would below read a
  825. // very large chunk of the file (and very likely read over the bounds)
  826. assert(prefix.size() >= 2 * blockSize);
  827. if (prefix.size() < 2 * blockSize) {
  828. return Status::Corruption("Unable to read from file " + fname +
  829. ": read attempt would read beyond file bounds");
  830. }
  831. // Decrypt the encrypted part of the prefix, starting from block 2 (block 0, 1 with initial counter & IV are unencrypted)
  832. CTRCipherStream cipherStream(cipher_, iv.data(), initialCounter);
  833. auto status = cipherStream.Decrypt(0, (char*)prefix.data() + (2 * blockSize), prefix.size() - (2 * blockSize));
  834. if (!status.ok()) {
  835. return status;
  836. }
  837. // Create cipher stream
  838. return CreateCipherStreamFromPrefix(fname, options, initialCounter, iv, prefix, result);
  839. }
  840. // CreateCipherStreamFromPrefix creates a block access cipher stream for a file given
  841. // given name and options. The given prefix is already decrypted.
  842. Status CTREncryptionProvider::CreateCipherStreamFromPrefix(
  843. const std::string& /*fname*/, const EnvOptions& /*options*/,
  844. uint64_t initialCounter, const Slice& iv, const Slice& /*prefix*/,
  845. std::unique_ptr<BlockAccessCipherStream>* result) {
  846. (*result) = std::unique_ptr<BlockAccessCipherStream>(
  847. new CTRCipherStream(cipher_, iv.data(), initialCounter));
  848. return Status::OK();
  849. }
  850. #endif // ROCKSDB_LITE
  851. } // namespace ROCKSDB_NAMESPACE