Skip to content

Commit 2af065b

Browse files
author
marc
committed
Add preamble handler with plaintext cipher stream
1 parent b6d0a3b commit 2af065b

File tree

4 files changed

+183
-2
lines changed

4 files changed

+183
-2
lines changed

c-deps/libroach/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_library(roach
2424
db.cc
2525
encoding.cc
2626
eventlistener.cc
27+
preamble.cc
2728
protos/roachpb/data.pb.cc
2829
protos/roachpb/internal.pb.cc
2930
protos/roachpb/metadata.pb.cc

c-deps/libroach/db.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "encoding.h"
3636
#include "eventlistener.h"
3737
#include "keys.h"
38+
#include "preamble.h"
3839

3940
extern "C" {
4041
static void __attribute__((noreturn)) die_missing_symbol(const char* name) {
@@ -89,6 +90,7 @@ struct DBEngine {
8990
};
9091

9192
struct DBImpl : public DBEngine {
93+
std::unique_ptr<PreambleHandler> preamble_handler;
9294
std::unique_ptr<rocksdb::Env> memenv;
9395
std::unique_ptr<rocksdb::DB> rep_deleter;
9496
std::shared_ptr<rocksdb::Cache> block_cache;
@@ -98,8 +100,9 @@ struct DBImpl : public DBEngine {
98100
// and Env will be deleted when the DBImpl is deleted. It is ok to
99101
// pass NULL for the Env.
100102
DBImpl(rocksdb::DB* r, rocksdb::Env* m, std::shared_ptr<rocksdb::Cache> bc,
101-
std::shared_ptr<DBEventListener> event_listener)
103+
std::shared_ptr<DBEventListener> event_listener, PreambleHandler* preamble)
102104
: DBEngine(r),
105+
preamble_handler(preamble),
103106
memenv(m),
104107
rep_deleter(r),
105108
block_cache(bc),
@@ -1697,14 +1700,22 @@ DBStatus DBOpen(DBEngine **db, DBSlice dir, DBOptions db_opts) {
16971700
options.env = memenv.get();
16981701
}
16991702

1703+
PreambleHandler* preamble;
1704+
if (db_opts.use_preamble) {
1705+
// The caller makes sure we're not an in-memory DB.
1706+
assert(dir.len != 0);
1707+
preamble = new PreambleHandler();
1708+
options.env = preamble->GetEnv(options.env);
1709+
}
1710+
17001711
rocksdb::DB *db_ptr;
17011712
rocksdb::Status status = rocksdb::DB::Open(options, ToString(dir), &db_ptr);
17021713
if (!status.ok()) {
17031714
return ToDBStatus(status);
17041715
}
17051716
*db = new DBImpl(db_ptr, memenv.release(),
17061717
db_opts.cache != nullptr ? db_opts.cache->rep : nullptr,
1707-
event_listener);
1718+
event_listener, preamble);
17081719
return kSuccess;
17091720
}
17101721

c-deps/libroach/preamble.cc

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
#include <arpa/inet.h>
16+
#include "preamble.h"
17+
#include "protos/storage/preamble.pb.h"
18+
19+
size_t PreambleHandler::GetPrefixLength() {
20+
return defaultPreambleLength;
21+
}
22+
23+
rocksdb::Env* PreambleHandler::GetEnv(rocksdb::Env* base_env) {
24+
return rocksdb::NewEncryptedEnv(base_env ? base_env : rocksdb::Env::Default(), this);
25+
}
26+
27+
rocksdb::Status PreambleHandler::CreateNewPrefix(const std::string& fname, char *prefix, size_t prefixLength) {
28+
// Zero-out the prefix.
29+
memset(prefix, 0, prefixLength);
30+
31+
// Create a preamble proto with encryption settings.
32+
cockroach::storage::Preamble preamble;
33+
// Everything is plaintext for now.
34+
preamble.set_encryption_type(cockroach::storage::Plaintext);
35+
36+
// Check the byte size before encoding.
37+
int byte_size = preamble.ByteSize();
38+
39+
// Determine the serialized length and size of the length prefix.
40+
// TODO(mberhault): protobuf encoding is little-endian, so this is a little weird.
41+
assert(byte_size < UINT16_MAX);
42+
uint16_t message_size = htons(byte_size);
43+
auto num_length_bytes = sizeof(message_size);
44+
45+
if ((byte_size + num_length_bytes) > prefixLength ) {
46+
// TODO(mberhault): is NoSpace the right thing? Nothing really fits.
47+
return rocksdb::Status::NoSpace("new preamble exceeds max preamble length");
48+
}
49+
50+
// Write length prefix.
51+
memcpy(prefix, &message_size, num_length_bytes);
52+
53+
// Write it to the prefix.
54+
if (!preamble.SerializeToArray(prefix + num_length_bytes, byte_size)) {
55+
return rocksdb::Status::Corruption("unable to write prefix");
56+
}
57+
58+
return rocksdb::Status::OK();
59+
}
60+
61+
rocksdb::Status PreambleHandler::CreateCipherStream(const std::string& fname, const rocksdb::EnvOptions& options, rocksdb::Slice &prefix, std::unique_ptr<rocksdb::BlockAccessCipherStream>* result) {
62+
// Read length prefix.
63+
uint16_t message_size;
64+
auto num_length_bytes = sizeof(message_size);
65+
memcpy(&message_size, prefix.data(), num_length_bytes);
66+
67+
// Convert length prefix from network byte order.
68+
int byte_size = ntohs(message_size);
69+
70+
// Parse prefix
71+
cockroach::storage::Preamble preamble;
72+
if (!preamble.ParseFromArray(prefix.data() + num_length_bytes, byte_size)) {
73+
return rocksdb::Status::Corruption("unable to parse prefix");
74+
}
75+
76+
if (preamble.encryption_type() == cockroach::storage::Plaintext) {
77+
(*result) = std::unique_ptr<rocksdb::BlockAccessCipherStream>(new PlaintextCipherStream());
78+
} else {
79+
return rocksdb::Status::NotSupported("unknown encryption type");
80+
}
81+
82+
return rocksdb::Status::OK();
83+
}

c-deps/libroach/preamble.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
#ifndef ROACHLIB_PREAMBLE_H
16+
#define ROACHLIB_PREAMBLE_H
17+
18+
#include <rocksdb/env.h>
19+
#include <rocksdb/env_encryption.h>
20+
21+
// Preamble length.
22+
// WARNING: changing this will result in incompatible on-disk format.
23+
// The preamble length must fit in a uint16_t.
24+
const static size_t defaultPreambleLength = 4096;
25+
26+
class PreambleHandler : rocksdb::EncryptionProvider {
27+
public:
28+
29+
PreambleHandler() {}
30+
virtual ~PreambleHandler() {}
31+
32+
// GetEnv returns an EncryptionEnv wrapped around base_env.
33+
rocksdb::Env* GetEnv(rocksdb::Env* base_env);
34+
35+
// GetPrefixLength returns the preamble length.
36+
virtual size_t GetPrefixLength() override;
37+
38+
// CreateNewPrefix initializes an allocated block of prefix memory for a new file.
39+
virtual rocksdb::Status CreateNewPrefix(const std::string& fname, char *prefix, size_t prefixLength) override;
40+
41+
// CreateCipherStream creates a block access cipher stream for a file given name and options.
42+
virtual rocksdb::Status CreateCipherStream(const std::string& fname, const rocksdb::EnvOptions& options,
43+
rocksdb::Slice& prefix, std::unique_ptr<rocksdb::BlockAccessCipherStream>* result) override;
44+
};
45+
46+
// Blocksize for the plaintext cipher stream.
47+
// TODO(mberhault): we can pick anything we like. What's good?
48+
const static size_t plaintextBlockSize = 4096;
49+
50+
// PlaintextCipherStream implements BlockAccessCipherStream with
51+
// no-op encrypt/decrypt operations.
52+
class PlaintextCipherStream final : public rocksdb::BlockAccessCipherStream {
53+
public:
54+
PlaintextCipherStream() {}
55+
virtual ~PlaintextCipherStream() {}
56+
57+
// BlockSize returns the size of each block supported by this cipher stream.
58+
virtual size_t BlockSize() override { return plaintextBlockSize; }
59+
60+
// Encrypt blocks of data. This is a noop.
61+
virtual rocksdb::Status Encrypt(uint64_t fileOffset, char *data, size_t dataSize) override {
62+
return rocksdb::Status::OK();
63+
}
64+
65+
// Decrypt blocks of data. This is a noop.
66+
virtual rocksdb::Status Decrypt(uint64_t fileOffset, char *data, size_t dataSize) override {
67+
return rocksdb::Status::OK();
68+
}
69+
protected:
70+
// Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
71+
virtual void AllocateScratch(std::string&) override {}
72+
73+
// Encrypt a block of data at the given block index.
74+
// Length of data is equal to BlockSize();
75+
virtual rocksdb::Status EncryptBlock(uint64_t blockIndex, char *data, char* scratch) override {
76+
return rocksdb::Status::OK();
77+
}
78+
79+
// Decrypt a block of data at the given block index.
80+
// Length of data is equal to BlockSize();
81+
virtual rocksdb::Status DecryptBlock(uint64_t blockIndex, char *data, char* scratch) override {
82+
return rocksdb::Status::OK();
83+
}
84+
};
85+
86+
#endif // ROACHLIB_PREAMBLE_H

0 commit comments

Comments
 (0)