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
14 #include <array>
15 #include <sstream>
16 #include <limits>
17 #include <fcntl.h>
18
19 #include <openssl/aes.h>
20
21 #include "Crypto.h"
22
23 #include "include/ceph_assert.h"
24 #include "common/Clock.h"
25 #include "common/armor.h"
26 #include "common/ceph_context.h"
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
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
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 }
64
65 void CryptoRandom::get_bytes(char *buf, int len)
66 {
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 }
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()
84 : fd{open_urandom()}
85 {
86 if (fd < 0) {
87 throw std::system_error(errno, std::system_category());
88 }
89 }
90
91 CryptoRandom::~CryptoRandom()
92 {
93 VOID_TEMP_FAILURE_RETRY(::close(fd));
94 }
95
96 void CryptoRandom::get_bytes(char *buf, int len)
97 {
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
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 }
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;
141 }
142
143 std::size_t CryptoKeyHandler::decrypt(
144 const CryptoKeyHandler::in_slice_t& in,
145 const CryptoKeyHandler::out_slice_t& out) const
146 {
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;
165 }
166
167 sha256_digest_t CryptoKeyHandler::hmac_sha256(
168 const ceph::bufferlist& in) const
169 {
170 ceph::crypto::HMACSHA256 hmac((const unsigned char*)secret.c_str(), secret.length());
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 }
180
181 // ---------------------------------------------------
182
183 class CryptoNoneKeyHandler : public CryptoKeyHandler {
184 public:
185 CryptoNoneKeyHandler()
186 : CryptoKeyHandler(CryptoKeyHandler::BLOCK_SIZE_0B()) {
187 }
188
189 using CryptoKeyHandler::encrypt;
190 using CryptoKeyHandler::decrypt;
191
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 }
211 int create(CryptoRandom *random, bufferptr& secret) override {
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 }
233 int create(CryptoRandom *random, bufferptr& secret) override;
234 int validate_secret(const bufferptr& secret) override;
235 CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override;
236 };
237
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};
241
242 class CryptoAESKeyHandler : public CryptoKeyHandler {
243 AES_KEY enc_key;
244 AES_KEY dec_key;
245
246 public:
247 CryptoAESKeyHandler()
248 : CryptoKeyHandler(CryptoKeyHandler::BLOCK_SIZE_16B()) {
(2) Event uninit_member: |
Non-static class member field "enc_key.rounds" is not initialized in this constructor nor in any functions that it calls. |
(4) Event uninit_member: |
Non-static class member field "dec_key.rounds" is not initialized in this constructor nor in any functions that it calls. |
Also see events: |
[member_decl][member_decl] |
249 }
250
251 int init(const bufferptr& s, ostringstream& err) {
252 secret = s;
253
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;
259 return -1;
260 }
261
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;
267 return -1;
268 }
269
270 return 0;
271 }
272
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};
288 memset(pad_buf.c_str(), pad_len, pad_len);
289
290 // form contiguous buffer for block cipher. The ctor copies shallowly.
291 ceph::bufferlist incopy(in);
292 incopy.append(std::move(pad_buf));
293 const auto in_buf = reinterpret_cast<unsigned char*>(incopy.c_str());
294
295 // reinitialize IV each time. It might be unnecessary depending on
296 // actual implementation but at the interface layer we are obliged
297 // to deliver IV as non-const.
298 static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN);
299 unsigned char iv[AES_BLOCK_LEN];
300 memcpy(iv, CEPH_AES_IV, AES_BLOCK_LEN);
301
302 // we aren't using EVP because of performance concerns. Profiling
303 // shows the cost is quite high. Endianness might be an issue.
304 // However, as they would affect Cephx, any fallout should pop up
305 // rather early, hopefully.
306 AES_cbc_encrypt(in_buf, reinterpret_cast<unsigned char*>(out_tmp.c_str()),
307 out_tmp.length(), &enc_key, iv, AES_ENCRYPT);
308
309 out.append(out_tmp);
310 return 0;
311 }
312
313 int decrypt(const ceph::bufferlist& in,
314 ceph::bufferlist& out,
315 std::string* /* unused */) const override {
316 // PKCS#7 padding enlarges even empty plain-text to take 16 bytes.
317 if (in.length() < AES_BLOCK_LEN || in.length() % AES_BLOCK_LEN) {
318 return -1;
319 }
320
321 // needed because of .c_str() on const. It's a shallow copy.
322 ceph::bufferlist incopy(in);
323 const auto in_buf = reinterpret_cast<unsigned char*>(incopy.c_str());
324
325 // make a local, modifiable copy of IV.
326 static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN);
327 unsigned char iv[AES_BLOCK_LEN];
328 memcpy(iv, CEPH_AES_IV, AES_BLOCK_LEN);
329
330 ceph::bufferptr out_tmp{in.length()};
331 AES_cbc_encrypt(in_buf, reinterpret_cast<unsigned char*>(out_tmp.c_str()),
332 in.length(), &dec_key, iv, AES_DECRYPT);
333
334 // BE CAREFUL: we cannot expose any single bit of information about
335 // the cause of failure. Otherwise we'll face padding oracle attack.
336 // See: https://en.wikipedia.org/wiki/Padding_oracle_attack.
337 const auto pad_len = \
338 std::min<std::uint8_t>(out_tmp[in.length() - 1], AES_BLOCK_LEN);
339 out_tmp.set_length(in.length() - pad_len);
340 out.append(std::move(out_tmp));
341
342 return 0;
343 }
344
345 std::size_t encrypt(const in_slice_t& in,
346 const out_slice_t& out) const override {
347 if (out.buf == nullptr) {
348 // 16 + p2align(10, 16) -> 16
349 // 16 + p2align(16, 16) -> 32
350 return AES_BLOCK_LEN + p2align<std::size_t>(in.length, AES_BLOCK_LEN);
351 }
352
353 // how many bytes of in.buf hang outside the alignment boundary and how
354 // much padding we need.
355 // length = 23 -> tail_len = 7, pad_len = 9
356 // length = 32 -> tail_len = 0, pad_len = 16
357 const std::uint8_t tail_len = in.length % AES_BLOCK_LEN;
358 const std::uint8_t pad_len = AES_BLOCK_LEN - tail_len;
359 static_assert(std::numeric_limits<std::uint8_t>::max() > AES_BLOCK_LEN);
360
361 std::array<unsigned char, AES_BLOCK_LEN> last_block;
362 memcpy(last_block.data(), in.buf + in.length - tail_len, tail_len);
363 memset(last_block.data() + tail_len, pad_len, pad_len);
364
365 // need a local copy because AES_cbc_encrypt takes `iv` as non-const.
366 // Useful because it allows us to encrypt in two steps: main + tail.
367 static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN);
368 std::array<unsigned char, AES_BLOCK_LEN> iv;
369 memcpy(iv.data(), CEPH_AES_IV, AES_BLOCK_LEN);
370
371 const std::size_t main_encrypt_size = \
372 std::min(in.length - tail_len, out.max_length);
373 AES_cbc_encrypt(in.buf, out.buf, main_encrypt_size, &enc_key, iv.data(),
374 AES_ENCRYPT);
375
376 const std::size_t tail_encrypt_size = \
377 std::min(AES_BLOCK_LEN, out.max_length - main_encrypt_size);
378 AES_cbc_encrypt(last_block.data(), out.buf + main_encrypt_size,
379 tail_encrypt_size, &enc_key, iv.data(), AES_ENCRYPT);
380
381 return main_encrypt_size + tail_encrypt_size;
382 }
383
384 std::size_t decrypt(const in_slice_t& in,
385 const out_slice_t& out) const override {
386 if (in.length % AES_BLOCK_LEN != 0 || in.length < AES_BLOCK_LEN) {
387 throw std::runtime_error("input not aligned to AES_BLOCK_LEN");
388 } else if (out.buf == nullptr) {
389 // essentially it would be possible to decrypt into a buffer that
390 // doesn't include space for any PKCS#7 padding. We don't do that
391 // for the sake of performance and simplicity.
392 return in.length;
393 } else if (out.max_length < in.length) {
394 throw std::runtime_error("output buffer too small");
395 }
396
397 static_assert(strlen_ct(CEPH_AES_IV) == AES_BLOCK_LEN);
398 std::array<unsigned char, AES_BLOCK_LEN> iv;
399 memcpy(iv.data(), CEPH_AES_IV, AES_BLOCK_LEN);
400
401 AES_cbc_encrypt(in.buf, out.buf, in.length, &dec_key, iv.data(),
402 AES_DECRYPT);
403
404 // NOTE: we aren't handling partial decrypt. PKCS#7 padding must be
405 // at the end. If it's malformed, don't say a word to avoid risk of
406 // having an oracle. All we need to ensure is valid buffer boundary.
407 const auto pad_len = \
408 std::min<std::uint8_t>(out.buf[in.length - 1], AES_BLOCK_LEN);
409 return in.length - pad_len;
410 }
411 };
412
413
414 // ------------------------------------------------------------
415
416 int CryptoAES::create(CryptoRandom *random, bufferptr& secret)
417 {
418 bufferptr buf(AES_KEY_LEN);
419 random->get_bytes(buf.c_str(), buf.length());
420 secret = std::move(buf);
421 return 0;
422 }
423
424 int CryptoAES::validate_secret(const bufferptr& secret)
425 {
426 if (secret.length() < AES_KEY_LEN) {
427 return -EINVAL;
428 }
429
430 return 0;
431 }
432
433 CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret,
434 string& error)
435 {
436 CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler;
437 ostringstream oss;
438 if (ckh->init(secret, oss) < 0) {
439 error = oss.str();
440 delete ckh;
441 return NULL;
442 }
443 return ckh;
444 }
445
446
447
448
449 // --
450
451
452 // ---------------------------------------------------
453
454
455 void CryptoKey::encode(bufferlist& bl) const
456 {
457 using ceph::encode;
458 encode(type, bl);
459 encode(created, bl);
460 __u16 len = secret.length();
461 encode(len, bl);
462 bl.append(secret);
463 }
464
465 void CryptoKey::decode(bufferlist::const_iterator& bl)
466 {
467 using ceph::decode;
468 decode(type, bl);
469 decode(created, bl);
470 __u16 len;
471 decode(len, bl);
472 bufferptr tmp;
473 bl.copy_deep(len, tmp);
474 if (_set_secret(type, tmp) < 0)
475 throw buffer::malformed_input("malformed secret");
476 }
477
478 int CryptoKey::set_secret(int type, const bufferptr& s, utime_t c)
479 {
480 int r = _set_secret(type, s);
481 if (r < 0)
482 return r;
483 this->created = c;
484 return 0;
485 }
486
487 int CryptoKey::_set_secret(int t, const bufferptr& s)
488 {
489 if (s.length() == 0) {
490 secret = s;
491 ckh.reset();
492 return 0;
493 }
494
495 CryptoHandler *ch = CryptoHandler::create(t);
496 if (ch) {
497 int ret = ch->validate_secret(s);
498 if (ret < 0) {
499 delete ch;
500 return ret;
501 }
502 string error;
503 ckh.reset(ch->get_key_handler(s, error));
504 delete ch;
505 if (error.length()) {
506 return -EIO;
507 }
508 } else {
509 return -EOPNOTSUPP;
510 }
511 type = t;
512 secret = s;
513 return 0;
514 }
515
516 int CryptoKey::create(CephContext *cct, int t)
517 {
518 CryptoHandler *ch = CryptoHandler::create(t);
519 if (!ch) {
520 if (cct)
521 lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl;
522 return -EOPNOTSUPP;
523 }
524 bufferptr s;
525 int r = ch->create(cct->random(), s);
526 delete ch;
527 if (r < 0)
528 return r;
529
530 r = _set_secret(t, s);
531 if (r < 0)
532 return r;
533 created = ceph_clock_now();
534 return r;
535 }
536
537 void CryptoKey::print(std::ostream &out) const
538 {
539 out << encode_base64();
540 }
541
542 void CryptoKey::to_str(std::string& s) const
543 {
544 int len = secret.length() * 4;
545 char buf[len];
546 hex2str(secret.c_str(), secret.length(), buf, len);
547 s = buf;
548 }
549
550 void CryptoKey::encode_formatted(string label, Formatter *f, bufferlist &bl)
551 {
552 f->open_object_section(label.c_str());
553 f->dump_string("key", encode_base64());
554 f->close_section();
555 f->flush(bl);
556 }
557
558 void CryptoKey::encode_plaintext(bufferlist &bl)
559 {
560 bl.append(encode_base64());
561 }
562
563
564 // ------------------
565
566 CryptoHandler *CryptoHandler::create(int type)
567 {
568 switch (type) {
569 case CEPH_CRYPTO_NONE:
570 return new CryptoNone;
571 case CEPH_CRYPTO_AES:
572 return new CryptoAES;
573 default:
574 return NULL;
575 }
576 }
577