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