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