]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // vim: ts=8 sw=2 smarttab |
2 | /* | |
3 | * Ceph - scalable distributed file system | |
4 | * | |
5 | * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net> | |
6 | * | |
7 | * This is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License version 2.1, as published by the Free Software | |
10 | * Foundation. See file COPYING. | |
11 | * | |
12 | */ | |
13 | ||
11fdf7f2 | 14 | #include <array> |
7c673cae | 15 | #include <sstream> |
91327a77 | 16 | #include <limits> |
11fdf7f2 | 17 | |
91327a77 AA |
18 | #include <fcntl.h> |
19 | ||
7c673cae | 20 | #include "Crypto.h" |
11fdf7f2 TL |
21 | #ifdef USE_OPENSSL |
22 | # include <openssl/aes.h> | |
7c673cae FG |
23 | #endif |
24 | ||
11fdf7f2 | 25 | #include "include/ceph_assert.h" |
7c673cae FG |
26 | #include "common/Clock.h" |
27 | #include "common/armor.h" | |
11fdf7f2 | 28 | #include "common/ceph_context.h" |
7c673cae FG |
29 | #include "common/ceph_crypto.h" |
30 | #include "common/hex.h" | |
31 | #include "common/safe_io.h" | |
32 | #include "include/ceph_fs.h" | |
33 | #include "include/compat.h" | |
34 | #include "common/Formatter.h" | |
35 | #include "common/debug.h" | |
36 | #include <errno.h> | |
37 | ||
11fdf7f2 TL |
38 | // use getentropy() if available. it uses the same source of randomness |
39 | // as /dev/urandom without the filesystem overhead | |
40 | #ifdef HAVE_GETENTROPY | |
41 | ||
42 | #include <unistd.h> | |
43 | ||
44 | CryptoRandom::CryptoRandom() : fd(0) {} | |
45 | CryptoRandom::~CryptoRandom() = default; | |
46 | ||
47 | void CryptoRandom::get_bytes(char *buf, int len) | |
48 | { | |
49 | auto ret = TEMP_FAILURE_RETRY(::getentropy(buf, len)); | |
50 | if (ret < 0) { | |
51 | throw std::system_error(errno, std::system_category()); | |
52 | } | |
53 | } | |
54 | ||
55 | #else // !HAVE_GETENTROPY | |
56 | ||
57 | // open /dev/urandom once on construction and reuse the fd for all reads | |
58 | CryptoRandom::CryptoRandom() | |
59 | : fd(TEMP_FAILURE_RETRY(::open("/dev/urandom", O_CLOEXEC|O_RDONLY))) | |
60 | { | |
61 | if (fd < 0) { | |
62 | throw std::system_error(errno, std::system_category()); | |
63 | } | |
64 | } | |
65 | ||
66 | CryptoRandom::~CryptoRandom() | |
7c673cae | 67 | { |
7c673cae | 68 | VOID_TEMP_FAILURE_RETRY(::close(fd)); |
7c673cae FG |
69 | } |
70 | ||
11fdf7f2 | 71 | void CryptoRandom::get_bytes(char *buf, int len) |
7c673cae | 72 | { |
11fdf7f2 TL |
73 | auto ret = safe_read_exact(fd, buf, len); |
74 | if (ret < 0) { | |
75 | throw std::system_error(-ret, std::system_category()); | |
76 | } | |
77 | } | |
78 | ||
79 | #endif | |
80 | ||
81 | ||
82 | // --------------------------------------------------- | |
83 | // fallback implementation of the bufferlist-free | |
84 | // interface. | |
85 | ||
86 | std::size_t CryptoKeyHandler::encrypt( | |
87 | const CryptoKeyHandler::in_slice_t& in, | |
88 | const CryptoKeyHandler::out_slice_t& out) const | |
89 | { | |
90 | ceph::bufferptr inptr(reinterpret_cast<const char*>(in.buf), in.length); | |
91 | ceph::bufferlist plaintext; | |
92 | plaintext.append(std::move(inptr)); | |
93 | ||
94 | ceph::bufferlist ciphertext; | |
95 | std::string error; | |
96 | const int ret = encrypt(plaintext, ciphertext, &error); | |
97 | if (ret != 0 || !error.empty()) { | |
98 | throw std::runtime_error(std::move(error)); | |
99 | } | |
100 | ||
101 | // we need to specify the template parameter explicitly as ::length() | |
102 | // returns unsigned int, not size_t. | |
103 | const auto todo_len = \ | |
104 | std::min<std::size_t>(ciphertext.length(), out.max_length); | |
105 | memcpy(out.buf, ciphertext.c_str(), todo_len); | |
106 | ||
107 | return todo_len; | |
7c673cae FG |
108 | } |
109 | ||
11fdf7f2 TL |
110 | std::size_t CryptoKeyHandler::decrypt( |
111 | const CryptoKeyHandler::in_slice_t& in, | |
112 | const CryptoKeyHandler::out_slice_t& out) const | |
7c673cae | 113 | { |
11fdf7f2 TL |
114 | ceph::bufferptr inptr(reinterpret_cast<const char*>(in.buf), in.length); |
115 | ceph::bufferlist ciphertext; | |
116 | ciphertext.append(std::move(inptr)); | |
117 | ||
118 | ceph::bufferlist plaintext; | |
119 | std::string error; | |
120 | const int ret = decrypt(ciphertext, plaintext, &error); | |
121 | if (ret != 0 || !error.empty()) { | |
122 | throw std::runtime_error(std::move(error)); | |
123 | } | |
124 | ||
125 | // we need to specify the template parameter explicitly as ::length() | |
126 | // returns unsigned int, not size_t. | |
127 | const auto todo_len = \ | |
128 | std::min<std::size_t>(plaintext.length(), out.max_length); | |
129 | memcpy(out.buf, plaintext.c_str(), todo_len); | |
130 | ||
131 | return todo_len; | |
7c673cae FG |
132 | } |
133 | ||
11fdf7f2 TL |
134 | sha256_digest_t CryptoKeyHandler::hmac_sha256( |
135 | const ceph::bufferlist& in) const | |
136 | { | |
137 | ceph::crypto::HMACSHA256 hmac((const unsigned char*)secret.c_str(), secret.length()); | |
138 | ||
139 | for (const auto& bptr : in.buffers()) { | |
140 | hmac.Update((const unsigned char *)bptr.c_str(), bptr.length()); | |
141 | } | |
142 | sha256_digest_t ret; | |
143 | hmac.Final(ret.v); | |
144 | ||
145 | return ret; | |
146 | } | |
7c673cae FG |
147 | |
148 | // --------------------------------------------------- | |
149 | ||
150 | class CryptoNoneKeyHandler : public CryptoKeyHandler { | |
151 | public: | |
11fdf7f2 TL |
152 | CryptoNoneKeyHandler() |
153 | : CryptoKeyHandler(CryptoKeyHandler::BLOCK_SIZE_0B()) { | |
154 | } | |
155 | ||
156 | using CryptoKeyHandler::encrypt; | |
157 | using CryptoKeyHandler::decrypt; | |
158 | ||
7c673cae FG |
159 | int encrypt(const bufferlist& in, |
160 | bufferlist& out, std::string *error) const override { | |
161 | out = in; | |
162 | return 0; | |
163 | } | |
164 | int decrypt(const bufferlist& in, | |
165 | bufferlist& out, std::string *error) const override { | |
166 | out = in; | |
167 | return 0; | |
168 | } | |
169 | }; | |
170 | ||
171 | class CryptoNone : public CryptoHandler { | |
172 | public: | |
173 | CryptoNone() { } | |
174 | ~CryptoNone() override {} | |
175 | int get_type() const override { | |
176 | return CEPH_CRYPTO_NONE; | |
177 | } | |
11fdf7f2 | 178 | int create(CryptoRandom *random, bufferptr& secret) override { |
7c673cae FG |
179 | return 0; |
180 | } | |
181 | int validate_secret(const bufferptr& secret) override { | |
182 | return 0; | |
183 | } | |
184 | CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override { | |
185 | return new CryptoNoneKeyHandler; | |
186 | } | |
187 | }; | |
188 | ||
189 | ||
190 | // --------------------------------------------------- | |
191 | ||
192 | ||
193 | class CryptoAES : public CryptoHandler { | |
194 | public: | |
195 | CryptoAES() { } | |
196 | ~CryptoAES() override {} | |
197 | int get_type() const override { | |
198 | return CEPH_CRYPTO_AES; | |
199 | } | |
11fdf7f2 | 200 | int create(CryptoRandom *random, bufferptr& secret) override; |
7c673cae FG |
201 | int validate_secret(const bufferptr& secret) override; |
202 | CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override; | |
203 | }; | |
204 | ||
11fdf7f2 TL |
205 | #ifdef USE_OPENSSL |
206 | // when we say AES, we mean AES-128 | |
207 | static constexpr const std::size_t AES_KEY_LEN{16}; | |
208 | static constexpr const std::size_t AES_BLOCK_LEN{16}; | |
7c673cae FG |
209 | |
210 | class CryptoAESKeyHandler : public CryptoKeyHandler { | |
11fdf7f2 TL |
211 | AES_KEY enc_key; |
212 | AES_KEY dec_key; | |
7c673cae | 213 | |
11fdf7f2 | 214 | public: |
7c673cae | 215 | CryptoAESKeyHandler() |
11fdf7f2 | 216 | : CryptoKeyHandler(CryptoKeyHandler::BLOCK_SIZE_16B()) { |
7c673cae FG |
217 | } |
218 | ||
219 | int init(const bufferptr& s, ostringstream& err) { | |
220 | secret = s; | |
221 | ||
11fdf7f2 TL |
222 | const int enc_key_ret = \ |
223 | AES_set_encrypt_key((const unsigned char*)secret.c_str(), | |
224 | AES_KEY_LEN * CHAR_BIT, &enc_key); | |
225 | if (enc_key_ret != 0) { | |
226 | err << "cannot set OpenSSL encrypt key for AES: " << enc_key_ret; | |
7c673cae FG |
227 | return -1; |
228 | } | |
7c673cae | 229 | |
11fdf7f2 TL |
230 | const int dec_key_ret = \ |
231 | AES_set_decrypt_key((const unsigned char*)secret.c_str(), | |
232 | AES_KEY_LEN * CHAR_BIT, &dec_key); | |
233 | if (dec_key_ret != 0) { | |
234 | err << "cannot set OpenSSL decrypt key for AES: " << dec_key_ret; | |
7c673cae FG |
235 | return -1; |
236 | } | |
237 | ||
7c673cae FG |
238 | return 0; |
239 | } | |
7c673cae | 240 | |
11fdf7f2 TL |
241 | int encrypt(const ceph::bufferlist& in, |
242 | ceph::bufferlist& out, | |
243 | std::string* /* unused */) const override { | |
244 | // we need to take into account the PKCS#7 padding. There *always* will | |
245 | // be at least one byte of padding. This stays even to input aligned to | |
246 | // AES_BLOCK_LEN. Otherwise we would face ambiguities during decryption. | |
247 | // To exemplify: | |
248 | // 16 + p2align(10, 16) -> 16 | |
249 | // 16 + p2align(16, 16) -> 32 including 16 bytes for padding. | |
250 | ceph::bufferptr out_tmp{static_cast<unsigned>( | |
251 | AES_BLOCK_LEN + p2align<std::size_t>(in.length(), AES_BLOCK_LEN))}; | |
252 | ||
253 | // let's pad the data | |
254 | std::uint8_t pad_len = out_tmp.length() - in.length(); | |
255 | ceph::bufferptr pad_buf{pad_len}; | |
256 | memset(pad_buf.c_str(), pad_len, pad_len); | |
257 | ||
258 | // form contiguous buffer for block cipher. The ctor copies shallowly. | |
259 | ceph::bufferlist incopy(in); | |
260 | incopy.append(std::move(pad_buf)); | |
261 | const auto in_buf = reinterpret_cast<unsigned char*>(incopy.c_str()); | |
262 | ||
263 | // reinitialize IV each time. It might be unnecessary depending on | |
264 | // actual implementation but at the interface layer we are obliged | |
265 | // to deliver IV as non-const. | |
266 | static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN); | |
267 | unsigned char iv[AES_BLOCK_LEN]; | |
268 | memcpy(iv, CEPH_AES_IV, AES_BLOCK_LEN); | |
269 | ||
270 | // we aren't using EVP because of performance concerns. Profiling | |
271 | // shows the cost is quite high. Endianness might be an issue. | |
272 | // However, as they would affect Cephx, any fallout should pop up | |
273 | // rather early, hopefully. | |
274 | AES_cbc_encrypt(in_buf, reinterpret_cast<unsigned char*>(out_tmp.c_str()), | |
275 | out_tmp.length(), &enc_key, iv, AES_ENCRYPT); | |
276 | ||
277 | out.append(out_tmp); | |
278 | return 0; | |
7c673cae FG |
279 | } |
280 | ||
11fdf7f2 TL |
281 | int decrypt(const ceph::bufferlist& in, |
282 | ceph::bufferlist& out, | |
283 | std::string* /* unused */) const override { | |
284 | // PKCS#7 padding enlarges even empty plain-text to take 16 bytes. | |
285 | if (in.length() < AES_BLOCK_LEN || in.length() % AES_BLOCK_LEN) { | |
286 | return -1; | |
7c673cae | 287 | } |
7c673cae | 288 | |
11fdf7f2 TL |
289 | // needed because of .c_str() on const. It's a shallow copy. |
290 | ceph::bufferlist incopy(in); | |
291 | const auto in_buf = reinterpret_cast<unsigned char*>(incopy.c_str()); | |
7c673cae | 292 | |
11fdf7f2 TL |
293 | // make a local, modifiable copy of IV. |
294 | static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN); | |
295 | unsigned char iv[AES_BLOCK_LEN]; | |
296 | memcpy(iv, CEPH_AES_IV, AES_BLOCK_LEN); | |
7c673cae | 297 | |
11fdf7f2 TL |
298 | ceph::bufferptr out_tmp{in.length()}; |
299 | AES_cbc_encrypt(in_buf, reinterpret_cast<unsigned char*>(out_tmp.c_str()), | |
300 | in.length(), &dec_key, iv, AES_DECRYPT); | |
7c673cae | 301 | |
11fdf7f2 TL |
302 | // BE CAREFUL: we cannot expose any single bit of information about |
303 | // the cause of failure. Otherwise we'll face padding oracle attack. | |
304 | // See: https://en.wikipedia.org/wiki/Padding_oracle_attack. | |
305 | const auto pad_len = \ | |
306 | std::min<std::uint8_t>(out_tmp[in.length() - 1], AES_BLOCK_LEN); | |
307 | out_tmp.set_length(in.length() - pad_len); | |
308 | out.append(std::move(out_tmp)); | |
7c673cae | 309 | |
11fdf7f2 TL |
310 | return 0; |
311 | } | |
7c673cae | 312 | |
11fdf7f2 TL |
313 | std::size_t encrypt(const in_slice_t& in, |
314 | const out_slice_t& out) const override { | |
315 | if (out.buf == nullptr) { | |
316 | // 16 + p2align(10, 16) -> 16 | |
317 | // 16 + p2align(16, 16) -> 32 | |
318 | return AES_BLOCK_LEN + p2align<std::size_t>(in.length, AES_BLOCK_LEN); | |
7c673cae FG |
319 | } |
320 | ||
11fdf7f2 TL |
321 | // how many bytes of in.buf hang outside the alignment boundary and how |
322 | // much padding we need. | |
323 | // length = 23 -> tail_len = 7, pad_len = 9 | |
324 | // length = 32 -> tail_len = 0, pad_len = 16 | |
325 | const std::uint8_t tail_len = in.length % AES_BLOCK_LEN; | |
326 | const std::uint8_t pad_len = AES_BLOCK_LEN - tail_len; | |
327 | static_assert(std::numeric_limits<std::uint8_t>::max() > AES_BLOCK_LEN); | |
328 | ||
329 | std::array<unsigned char, AES_BLOCK_LEN> last_block; | |
330 | memcpy(last_block.data(), in.buf + in.length - tail_len, tail_len); | |
331 | memset(last_block.data() + tail_len, pad_len, pad_len); | |
332 | ||
333 | // need a local copy because AES_cbc_encrypt takes `iv` as non-const. | |
334 | // Useful because it allows us to encrypt in two steps: main + tail. | |
335 | static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN); | |
336 | std::array<unsigned char, AES_BLOCK_LEN> iv; | |
337 | memcpy(iv.data(), CEPH_AES_IV, AES_BLOCK_LEN); | |
338 | ||
339 | const std::size_t main_encrypt_size = \ | |
340 | std::min(in.length - tail_len, out.max_length); | |
341 | AES_cbc_encrypt(in.buf, out.buf, main_encrypt_size, &enc_key, iv.data(), | |
342 | AES_ENCRYPT); | |
343 | ||
344 | const std::size_t tail_encrypt_size = \ | |
345 | std::min(AES_BLOCK_LEN, out.max_length - main_encrypt_size); | |
346 | AES_cbc_encrypt(last_block.data(), out.buf + main_encrypt_size, | |
347 | tail_encrypt_size, &enc_key, iv.data(), AES_ENCRYPT); | |
348 | ||
349 | return main_encrypt_size + tail_encrypt_size; | |
350 | } | |
7c673cae | 351 | |
11fdf7f2 TL |
352 | std::size_t decrypt(const in_slice_t& in, |
353 | const out_slice_t& out) const override { | |
354 | if (in.length % AES_BLOCK_LEN != 0 || in.length < AES_BLOCK_LEN) { | |
355 | throw std::runtime_error("input not aligned to AES_BLOCK_LEN"); | |
356 | } else if (out.buf == nullptr) { | |
357 | // essentially it would be possible to decrypt into a buffer that | |
358 | // doesn't include space for any PKCS#7 padding. We don't do that | |
359 | // for the sake of performance and simplicity. | |
360 | return in.length; | |
361 | } else if (out.max_length < in.length) { | |
362 | throw std::runtime_error("output buffer too small"); | |
7c673cae FG |
363 | } |
364 | ||
11fdf7f2 TL |
365 | static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN); |
366 | std::array<unsigned char, AES_BLOCK_LEN> iv; | |
367 | memcpy(iv.data(), CEPH_AES_IV, AES_BLOCK_LEN); | |
7c673cae | 368 | |
11fdf7f2 TL |
369 | AES_cbc_encrypt(in.buf, out.buf, in.length, &dec_key, iv.data(), |
370 | AES_DECRYPT); | |
371 | ||
372 | // NOTE: we aren't handling partial decrypt. PKCS#7 padding must be | |
373 | // at the end. If it's malformed, don't say a word to avoid risk of | |
374 | // having an oracle. All we need to ensure is valid buffer boundary. | |
375 | const auto pad_len = \ | |
376 | std::min<std::uint8_t>(out.buf[in.length - 1], AES_BLOCK_LEN); | |
377 | return in.length - pad_len; | |
7c673cae FG |
378 | } |
379 | }; | |
380 | ||
381 | #else | |
382 | # error "No supported crypto implementation found." | |
383 | #endif | |
384 | ||
385 | ||
386 | ||
387 | // ------------------------------------------------------------ | |
388 | ||
11fdf7f2 | 389 | int CryptoAES::create(CryptoRandom *random, bufferptr& secret) |
7c673cae | 390 | { |
11fdf7f2 TL |
391 | bufferptr buf(AES_KEY_LEN); |
392 | random->get_bytes(buf.c_str(), buf.length()); | |
393 | secret = std::move(buf); | |
7c673cae FG |
394 | return 0; |
395 | } | |
396 | ||
397 | int CryptoAES::validate_secret(const bufferptr& secret) | |
398 | { | |
11fdf7f2 | 399 | if (secret.length() < AES_KEY_LEN) { |
7c673cae FG |
400 | return -EINVAL; |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret, | |
407 | string& error) | |
408 | { | |
409 | CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler; | |
410 | ostringstream oss; | |
411 | if (ckh->init(secret, oss) < 0) { | |
412 | error = oss.str(); | |
413 | delete ckh; | |
414 | return NULL; | |
415 | } | |
416 | return ckh; | |
417 | } | |
418 | ||
419 | ||
420 | ||
421 | ||
422 | // -- | |
423 | ||
424 | ||
425 | // --------------------------------------------------- | |
426 | ||
427 | ||
428 | void CryptoKey::encode(bufferlist& bl) const | |
429 | { | |
11fdf7f2 TL |
430 | using ceph::encode; |
431 | encode(type, bl); | |
432 | encode(created, bl); | |
7c673cae | 433 | __u16 len = secret.length(); |
11fdf7f2 | 434 | encode(len, bl); |
7c673cae FG |
435 | bl.append(secret); |
436 | } | |
437 | ||
11fdf7f2 | 438 | void CryptoKey::decode(bufferlist::const_iterator& bl) |
7c673cae | 439 | { |
11fdf7f2 TL |
440 | using ceph::decode; |
441 | decode(type, bl); | |
442 | decode(created, bl); | |
7c673cae | 443 | __u16 len; |
11fdf7f2 | 444 | decode(len, bl); |
7c673cae FG |
445 | bufferptr tmp; |
446 | bl.copy_deep(len, tmp); | |
447 | if (_set_secret(type, tmp) < 0) | |
448 | throw buffer::malformed_input("malformed secret"); | |
449 | } | |
450 | ||
451 | int CryptoKey::set_secret(int type, const bufferptr& s, utime_t c) | |
452 | { | |
453 | int r = _set_secret(type, s); | |
454 | if (r < 0) | |
455 | return r; | |
456 | this->created = c; | |
457 | return 0; | |
458 | } | |
459 | ||
460 | int CryptoKey::_set_secret(int t, const bufferptr& s) | |
461 | { | |
462 | if (s.length() == 0) { | |
463 | secret = s; | |
464 | ckh.reset(); | |
465 | return 0; | |
466 | } | |
467 | ||
468 | CryptoHandler *ch = CryptoHandler::create(t); | |
469 | if (ch) { | |
470 | int ret = ch->validate_secret(s); | |
471 | if (ret < 0) { | |
472 | delete ch; | |
473 | return ret; | |
474 | } | |
475 | string error; | |
476 | ckh.reset(ch->get_key_handler(s, error)); | |
477 | delete ch; | |
478 | if (error.length()) { | |
479 | return -EIO; | |
480 | } | |
481 | } else { | |
482 | return -EOPNOTSUPP; | |
483 | } | |
484 | type = t; | |
485 | secret = s; | |
486 | return 0; | |
487 | } | |
488 | ||
489 | int CryptoKey::create(CephContext *cct, int t) | |
490 | { | |
491 | CryptoHandler *ch = CryptoHandler::create(t); | |
492 | if (!ch) { | |
493 | if (cct) | |
494 | lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl; | |
495 | return -EOPNOTSUPP; | |
496 | } | |
497 | bufferptr s; | |
11fdf7f2 | 498 | int r = ch->create(cct->random(), s); |
7c673cae FG |
499 | delete ch; |
500 | if (r < 0) | |
501 | return r; | |
502 | ||
503 | r = _set_secret(t, s); | |
504 | if (r < 0) | |
505 | return r; | |
506 | created = ceph_clock_now(); | |
507 | return r; | |
508 | } | |
509 | ||
510 | void CryptoKey::print(std::ostream &out) const | |
511 | { | |
512 | out << encode_base64(); | |
513 | } | |
514 | ||
515 | void CryptoKey::to_str(std::string& s) const | |
516 | { | |
517 | int len = secret.length() * 4; | |
518 | char buf[len]; | |
519 | hex2str(secret.c_str(), secret.length(), buf, len); | |
520 | s = buf; | |
521 | } | |
522 | ||
523 | void CryptoKey::encode_formatted(string label, Formatter *f, bufferlist &bl) | |
524 | { | |
525 | f->open_object_section(label.c_str()); | |
526 | f->dump_string("key", encode_base64()); | |
527 | f->close_section(); | |
528 | f->flush(bl); | |
529 | } | |
530 | ||
531 | void CryptoKey::encode_plaintext(bufferlist &bl) | |
532 | { | |
533 | bl.append(encode_base64()); | |
534 | } | |
535 | ||
536 | ||
537 | // ------------------ | |
538 | ||
539 | CryptoHandler *CryptoHandler::create(int type) | |
540 | { | |
541 | switch (type) { | |
542 | case CEPH_CRYPTO_NONE: | |
543 | return new CryptoNone; | |
544 | case CEPH_CRYPTO_AES: | |
545 | return new CryptoAES; | |
546 | default: | |
547 | return NULL; | |
548 | } | |
549 | } |