]> git.proxmox.com Git - ceph.git/blob - ceph/src/auth/Crypto.cc
150052bfef1710840ff2cee09d704c8333013836
[ceph.git] / ceph / src / auth / Crypto.cc
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 <sstream>
15 #include <limits>
16 #include <fcntl.h>
17
18 #include "Crypto.h"
19 #ifdef USE_CRYPTOPP
20 # include <cryptopp/modes.h>
21 # include <cryptopp/aes.h>
22 # include <cryptopp/filters.h>
23 #elif defined(USE_NSS)
24 # include <nspr.h>
25 # include <nss.h>
26 # include <pk11pub.h>
27 #endif
28
29 #include "include/assert.h"
30 #include "common/Clock.h"
31 #include "common/armor.h"
32 #include "common/ceph_crypto.h"
33 #include "common/hex.h"
34 #include "common/safe_io.h"
35 #include "include/ceph_fs.h"
36 #include "include/compat.h"
37 #include "common/Formatter.h"
38 #include "common/debug.h"
39 #include <errno.h>
40
41 int get_random_bytes(char *buf, int len)
42 {
43 int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY|O_CLOEXEC));
44 if (fd < 0)
45 return -errno;
46 int ret = safe_read_exact(fd, buf, len);
47 VOID_TEMP_FAILURE_RETRY(::close(fd));
48 return ret;
49 }
50
51 static int get_random_bytes(int len, bufferlist& bl)
52 {
53 char buf[len];
54 get_random_bytes(buf, len);
55 bl.append(buf, len);
56 return 0;
57 }
58
59 uint64_t get_random(uint64_t min_val, uint64_t max_val)
60 {
61 uint64_t r;
62 get_random_bytes((char *)&r, sizeof(r));
63 r = min_val + r % (max_val - min_val + 1);
64 return r;
65 }
66
67
68 // ---------------------------------------------------
69
70 class CryptoNoneKeyHandler : public CryptoKeyHandler {
71 public:
72 int encrypt(const bufferlist& in,
73 bufferlist& out, std::string *error) const override {
74 out = in;
75 return 0;
76 }
77 int decrypt(const bufferlist& in,
78 bufferlist& out, std::string *error) const override {
79 out = in;
80 return 0;
81 }
82 };
83
84 class CryptoNone : public CryptoHandler {
85 public:
86 CryptoNone() { }
87 ~CryptoNone() override {}
88 int get_type() const override {
89 return CEPH_CRYPTO_NONE;
90 }
91 int create(bufferptr& secret) override {
92 return 0;
93 }
94 int validate_secret(const bufferptr& secret) override {
95 return 0;
96 }
97 CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override {
98 return new CryptoNoneKeyHandler;
99 }
100 };
101
102
103 // ---------------------------------------------------
104
105
106 class CryptoAES : public CryptoHandler {
107 public:
108 CryptoAES() { }
109 ~CryptoAES() override {}
110 int get_type() const override {
111 return CEPH_CRYPTO_AES;
112 }
113 int create(bufferptr& secret) override;
114 int validate_secret(const bufferptr& secret) override;
115 CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override;
116 };
117
118 #ifdef USE_CRYPTOPP
119 # define AES_KEY_LEN ((size_t)CryptoPP::AES::DEFAULT_KEYLENGTH)
120 # define AES_BLOCK_LEN ((size_t)CryptoPP::AES::BLOCKSIZE)
121
122 class CryptoAESKeyHandler : public CryptoKeyHandler {
123 public:
124 CryptoPP::AES::Encryption *enc_key;
125 CryptoPP::AES::Decryption *dec_key;
126
127 CryptoAESKeyHandler()
128 : enc_key(NULL),
129 dec_key(NULL) {}
130 ~CryptoAESKeyHandler() {
131 delete enc_key;
132 delete dec_key;
133 }
134
135 int init(const bufferptr& s, ostringstream& err) {
136 secret = s;
137
138 enc_key = new CryptoPP::AES::Encryption(
139 (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
140 dec_key = new CryptoPP::AES::Decryption(
141 (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
142
143 return 0;
144 }
145
146 int encrypt(const bufferlist& in,
147 bufferlist& out, std::string *error) const {
148 string ciphertext;
149 CryptoPP::StringSink *sink = new CryptoPP::StringSink(ciphertext);
150 CryptoPP::CBC_Mode_ExternalCipher::Encryption cbc(
151 *enc_key, (const byte*)CEPH_AES_IV);
152 CryptoPP::StreamTransformationFilter stfEncryptor(cbc, sink);
153
154 for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
155 it != in.buffers().end(); ++it) {
156 const unsigned char *in_buf = (const unsigned char *)it->c_str();
157 stfEncryptor.Put(in_buf, it->length());
158 }
159 try {
160 stfEncryptor.MessageEnd();
161 } catch (CryptoPP::Exception& e) {
162 if (error) {
163 ostringstream oss;
164 oss << "encryptor.MessageEnd::Exception: " << e.GetWhat();
165 *error = oss.str();
166 }
167 return -1;
168 }
169 out.append((const char *)ciphertext.c_str(), ciphertext.length());
170 return 0;
171 }
172
173 int decrypt(const bufferlist& in,
174 bufferlist& out, std::string *error) const {
175 string decryptedtext;
176 CryptoPP::StringSink *sink = new CryptoPP::StringSink(decryptedtext);
177 CryptoPP::CBC_Mode_ExternalCipher::Decryption cbc(
178 *dec_key, (const byte*)CEPH_AES_IV );
179 CryptoPP::StreamTransformationFilter stfDecryptor(cbc, sink);
180 for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
181 it != in.buffers().end(); ++it) {
182 const unsigned char *in_buf = (const unsigned char *)it->c_str();
183 stfDecryptor.Put(in_buf, it->length());
184 }
185
186 try {
187 stfDecryptor.MessageEnd();
188 } catch (CryptoPP::Exception& e) {
189 if (error) {
190 ostringstream oss;
191 oss << "decryptor.MessageEnd::Exception: " << e.GetWhat();
192 *error = oss.str();
193 }
194 return -1;
195 }
196
197 out.append((const char *)decryptedtext.c_str(), decryptedtext.length());
198 return 0;
199 }
200 };
201
202 #elif defined(USE_NSS)
203 // when we say AES, we mean AES-128
204 # define AES_KEY_LEN 16
205 # define AES_BLOCK_LEN 16
206
207 static int nss_aes_operation(CK_ATTRIBUTE_TYPE op,
208 CK_MECHANISM_TYPE mechanism,
209 PK11SymKey *key,
210 SECItem *param,
211 const bufferlist& in, bufferlist& out,
212 std::string *error)
213 {
214 // sample source said this has to be at least size of input + 8,
215 // but i see 15 still fail with SEC_ERROR_OUTPUT_LEN
216 bufferptr out_tmp(in.length()+16);
217 bufferlist incopy;
218
219 SECStatus ret;
220 int written;
221 unsigned char *in_buf;
222
223 PK11Context *ectx;
224 ectx = PK11_CreateContextBySymKey(mechanism, op, key, param);
225 assert(ectx);
226
227 incopy = in; // it's a shallow copy!
228 in_buf = (unsigned char*)incopy.c_str();
229 ret = PK11_CipherOp(ectx,
230 (unsigned char*)out_tmp.c_str(), &written, out_tmp.length(),
231 in_buf, in.length());
232 if (ret != SECSuccess) {
233 PK11_DestroyContext(ectx, PR_TRUE);
234 if (error) {
235 ostringstream oss;
236 oss << "NSS AES failed: " << PR_GetError();
237 *error = oss.str();
238 }
239 return -1;
240 }
241
242 unsigned int written2;
243 ret = PK11_DigestFinal(ectx,
244 (unsigned char*)out_tmp.c_str()+written, &written2,
245 out_tmp.length()-written);
246 PK11_DestroyContext(ectx, PR_TRUE);
247 if (ret != SECSuccess) {
248 if (error) {
249 ostringstream oss;
250 oss << "NSS AES final round failed: " << PR_GetError();
251 *error = oss.str();
252 }
253 return -1;
254 }
255
256 out_tmp.set_length(written + written2);
257 out.append(out_tmp);
258 return 0;
259 }
260
261 class CryptoAESKeyHandler : public CryptoKeyHandler {
262 CK_MECHANISM_TYPE mechanism;
263 PK11SlotInfo *slot;
264 PK11SymKey *key;
265 SECItem *param;
266
267 public:
268 CryptoAESKeyHandler()
269 : mechanism(CKM_AES_CBC_PAD),
270 slot(NULL),
271 key(NULL),
272 param(NULL) {}
273 ~CryptoAESKeyHandler() override {
274 SECITEM_FreeItem(param, PR_TRUE);
275 if (key)
276 PK11_FreeSymKey(key);
277 if (slot)
278 PK11_FreeSlot(slot);
279 }
280
281 int init(const bufferptr& s, ostringstream& err) {
282 secret = s;
283
284 slot = PK11_GetBestSlot(mechanism, NULL);
285 if (!slot) {
286 err << "cannot find NSS slot to use: " << PR_GetError();
287 return -1;
288 }
289
290 SECItem keyItem;
291 keyItem.type = siBuffer;
292 keyItem.data = (unsigned char*)secret.c_str();
293 keyItem.len = secret.length();
294 key = PK11_ImportSymKey(slot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT,
295 &keyItem, NULL);
296 if (!key) {
297 err << "cannot convert AES key for NSS: " << PR_GetError();
298 return -1;
299 }
300
301 SECItem ivItem;
302 ivItem.type = siBuffer;
303 // losing constness due to SECItem.data; IV should never be
304 // modified, regardless
305 ivItem.data = (unsigned char*)CEPH_AES_IV;
306 ivItem.len = sizeof(CEPH_AES_IV);
307
308 param = PK11_ParamFromIV(mechanism, &ivItem);
309 if (!param) {
310 err << "cannot set NSS IV param: " << PR_GetError();
311 return -1;
312 }
313
314 return 0;
315 }
316
317 int encrypt(const bufferlist& in,
318 bufferlist& out, std::string *error) const override {
319 return nss_aes_operation(CKA_ENCRYPT, mechanism, key, param, in, out, error);
320 }
321 int decrypt(const bufferlist& in,
322 bufferlist& out, std::string *error) const override {
323 return nss_aes_operation(CKA_DECRYPT, mechanism, key, param, in, out, error);
324 }
325 };
326
327 #else
328 # error "No supported crypto implementation found."
329 #endif
330
331
332
333 // ------------------------------------------------------------
334
335 int CryptoAES::create(bufferptr& secret)
336 {
337 bufferlist bl;
338 int r = get_random_bytes(AES_KEY_LEN, bl);
339 if (r < 0)
340 return r;
341 secret = buffer::ptr(bl.c_str(), bl.length());
342 return 0;
343 }
344
345 int CryptoAES::validate_secret(const bufferptr& secret)
346 {
347 if (secret.length() < (size_t)AES_KEY_LEN) {
348 return -EINVAL;
349 }
350
351 return 0;
352 }
353
354 CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret,
355 string& error)
356 {
357 CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler;
358 ostringstream oss;
359 if (ckh->init(secret, oss) < 0) {
360 error = oss.str();
361 delete ckh;
362 return NULL;
363 }
364 return ckh;
365 }
366
367
368
369
370 // --
371
372
373 // ---------------------------------------------------
374
375
376 void CryptoKey::encode(bufferlist& bl) const
377 {
378 ::encode(type, bl);
379 ::encode(created, bl);
380 __u16 len = secret.length();
381 ::encode(len, bl);
382 bl.append(secret);
383 }
384
385 void CryptoKey::decode(bufferlist::iterator& bl)
386 {
387 ::decode(type, bl);
388 ::decode(created, bl);
389 __u16 len;
390 ::decode(len, bl);
391 bufferptr tmp;
392 bl.copy_deep(len, tmp);
393 if (_set_secret(type, tmp) < 0)
394 throw buffer::malformed_input("malformed secret");
395 }
396
397 int CryptoKey::set_secret(int type, const bufferptr& s, utime_t c)
398 {
399 int r = _set_secret(type, s);
400 if (r < 0)
401 return r;
402 this->created = c;
403 return 0;
404 }
405
406 int CryptoKey::_set_secret(int t, const bufferptr& s)
407 {
408 if (s.length() == 0) {
409 secret = s;
410 ckh.reset();
411 return 0;
412 }
413
414 CryptoHandler *ch = CryptoHandler::create(t);
415 if (ch) {
416 int ret = ch->validate_secret(s);
417 if (ret < 0) {
418 delete ch;
419 return ret;
420 }
421 string error;
422 ckh.reset(ch->get_key_handler(s, error));
423 delete ch;
424 if (error.length()) {
425 return -EIO;
426 }
427 } else {
428 return -EOPNOTSUPP;
429 }
430 type = t;
431 secret = s;
432 return 0;
433 }
434
435 int CryptoKey::create(CephContext *cct, int t)
436 {
437 CryptoHandler *ch = CryptoHandler::create(t);
438 if (!ch) {
439 if (cct)
440 lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl;
441 return -EOPNOTSUPP;
442 }
443 bufferptr s;
444 int r = ch->create(s);
445 delete ch;
446 if (r < 0)
447 return r;
448
449 r = _set_secret(t, s);
450 if (r < 0)
451 return r;
452 created = ceph_clock_now();
453 return r;
454 }
455
456 void CryptoKey::print(std::ostream &out) const
457 {
458 out << encode_base64();
459 }
460
461 void CryptoKey::to_str(std::string& s) const
462 {
463 int len = secret.length() * 4;
464 char buf[len];
465 hex2str(secret.c_str(), secret.length(), buf, len);
466 s = buf;
467 }
468
469 void CryptoKey::encode_formatted(string label, Formatter *f, bufferlist &bl)
470 {
471 f->open_object_section(label.c_str());
472 f->dump_string("key", encode_base64());
473 f->close_section();
474 f->flush(bl);
475 }
476
477 void CryptoKey::encode_plaintext(bufferlist &bl)
478 {
479 bl.append(encode_base64());
480 }
481
482
483 // ------------------
484
485 CryptoHandler *CryptoHandler::create(int type)
486 {
487 switch (type) {
488 case CEPH_CRYPTO_NONE:
489 return new CryptoNone;
490 case CEPH_CRYPTO_AES:
491 return new CryptoAES;
492 default:
493 return NULL;
494 }
495 }