return r;
}
+
// ---------------------------------------------------
+class CryptoNoneKeyHandler : public CryptoKeyHandler {
+public:
+ void encrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ out = in;
+ }
+ void decrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ out = in;
+ }
+};
+
class CryptoNone : public CryptoHandler {
public:
CryptoNone() { }
int get_type() const {
return CEPH_CRYPTO_NONE;
}
- int create(bufferptr& secret);
- int validate_secret(bufferptr& secret);
- void encrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const;
- void decrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const;
+ int create(bufferptr& secret) {
+ return 0;
+ }
+ int validate_secret(const bufferptr& secret) {
+ return 0;
+ }
+ CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) {
+ return new CryptoNoneKeyHandler;
+ }
};
-int CryptoNone::create(bufferptr& secret)
-{
- return 0;
-}
-
-int CryptoNone::validate_secret(bufferptr& secret)
-{
- return 0;
-}
-
-void CryptoNone::encrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const
-{
- out = in;
-}
-
-void CryptoNone::decrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const
-{
- out = in;
-}
-
// ---------------------------------------------------
+
class CryptoAES : public CryptoHandler {
public:
CryptoAES() { }
return CEPH_CRYPTO_AES;
}
int create(bufferptr& secret);
- int validate_secret(bufferptr& secret);
- void encrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const;
- void decrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const;
+ int validate_secret(const bufferptr& secret);
+ CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error);
};
-
#ifdef USE_CRYPTOPP
# define AES_KEY_LEN ((size_t)CryptoPP::AES::DEFAULT_KEYLENGTH)
# define AES_BLOCK_LEN ((size_t)CryptoPP::AES::BLOCKSIZE)
+
+class CryptoAESKeyHandler : public CryptoKeyHandler {
+public:
+ int init(const bufferptr& s, ostringstream& err) {
+ secret = s;
+ return 0;
+ }
+
+ void encrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ const unsigned char *key = (const unsigned char *)secret.c_str();
+
+ string ciphertext;
+ CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
+ CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(
+ aesEncryption, (const byte*)CEPH_AES_IV);
+ CryptoPP::StringSink *sink = new CryptoPP::StringSink(ciphertext);
+ CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, sink);
+
+ for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
+ it != in.buffers().end(); ++it) {
+ const unsigned char *in_buf = (const unsigned char *)it->c_str();
+ stfEncryptor.Put(in_buf, it->length());
+ }
+ try {
+ stfEncryptor.MessageEnd();
+ } catch (CryptoPP::Exception& e) {
+ ostringstream oss;
+ oss << "encryptor.MessageEnd::Exception: " << e.GetWhat();
+ error = oss.str();
+ return;
+ }
+ out.append((const char *)ciphertext.c_str(), ciphertext.length());
+ }
+
+ void decrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ const unsigned char *key = (const unsigned char *)secret.c_str();
+
+ CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
+ CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(
+ aesDecryption, (const byte*)CEPH_AES_IV );
+
+ string decryptedtext;
+ CryptoPP::StringSink *sink = new CryptoPP::StringSink(decryptedtext);
+ CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, sink);
+ for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
+ it != in.buffers().end(); ++it) {
+ const unsigned char *in_buf = (const unsigned char *)it->c_str();
+ stfDecryptor.Put(in_buf, it->length());
+ }
+
+ try {
+ stfDecryptor.MessageEnd();
+ } catch (CryptoPP::Exception& e) {
+ ostringstream oss;
+ oss << "decryptor.MessageEnd::Exception: " << e.GetWhat();
+ error = oss.str();
+ return;
+ }
+
+ out.append((const char *)decryptedtext.c_str(), decryptedtext.length());
+ }
+};
+
#elif USE_NSS
// when we say AES, we mean AES-128
# define AES_KEY_LEN 16
# define AES_BLOCK_LEN 16
-static void nss_aes_operation(CK_ATTRIBUTE_TYPE op, const bufferptr& secret,
- const bufferlist& in, bufferlist& out, std::string &error)
+static void nss_aes_operation(CK_ATTRIBUTE_TYPE op,
+ const bufferptr& secret,
+ const bufferlist& in, bufferlist& out,
+ std::string& error)
{
- const CK_MECHANISM_TYPE mechanism = CKM_AES_CBC_PAD;
-
- // sample source said this has to be at least size of input + 8,
- // but i see 15 still fail with SEC_ERROR_OUTPUT_LEN
- bufferptr out_tmp(in.length()+16);
-
- bufferlist incopy;
-
+ CK_MECHANISM_TYPE mechanism = CKM_AES_CBC_PAD;
PK11SlotInfo *slot;
+ PK11SymKey *key;
+ SECItem *param;
slot = PK11_GetBestSlot(mechanism, NULL);
if (!slot) {
- ostringstream oss;
- oss << "cannot find NSS slot to use: " << PR_GetError();
- error = oss.str();
- goto err;
+ ostringstream err;
+ err << "cannot find NSS slot to use: " << PR_GetError();
+ error = err.str();
+ return;
}
SECItem keyItem;
-
keyItem.type = siBuffer;
keyItem.data = (unsigned char*)secret.c_str();
keyItem.len = secret.length();
-
- PK11SymKey *key;
-
key = PK11_ImportSymKey(slot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT,
&keyItem, NULL);
if (!key) {
- ostringstream oss;
- oss << "cannot convert AES key for NSS: " << PR_GetError();
- error = oss.str();
- goto err_slot;
+ ostringstream err;
+ err << "cannot convert AES key for NSS: " << PR_GetError();
+ error = err.str();
+ return;
}
SECItem ivItem;
-
ivItem.type = siBuffer;
// losing constness due to SECItem.data; IV should never be
// modified, regardless
ivItem.data = (unsigned char*)CEPH_AES_IV;
ivItem.len = sizeof(CEPH_AES_IV);
- SECItem *param;
-
param = PK11_ParamFromIV(mechanism, &ivItem);
if (!param) {
- ostringstream oss;
- oss << "cannot set NSS IV param: " << PR_GetError();
- error = oss.str();
- goto err_key;
+ ostringstream err;
+ err << "cannot set NSS IV param: " << PR_GetError();
+ error = err.str();
+ return;
}
- PK11Context *ctx;
-
- ctx = PK11_CreateContextBySymKey(mechanism, op, key, param);
- if (!ctx) {
- ostringstream oss;
- oss << "cannot create NSS context: " << PR_GetError();
- error = oss.str();
- goto err_param;
- }
+ // sample source said this has to be at least size of input + 8,
+ // but i see 15 still fail with SEC_ERROR_OUTPUT_LEN
+ bufferptr out_tmp(in.length()+16);
+ bufferlist incopy;
SECStatus ret;
int written;
unsigned char *in_buf;
+ PK11Context *ectx;
+ ectx = PK11_CreateContextBySymKey(mechanism, op, key, param);
+ assert(ectx);
+
incopy = in; // it's a shallow copy!
in_buf = (unsigned char*)incopy.c_str();
- ret = PK11_CipherOp(ctx,
+ ret = PK11_CipherOp(ectx,
(unsigned char*)out_tmp.c_str(), &written, out_tmp.length(),
in_buf, in.length());
if (ret != SECSuccess) {
ostringstream oss;
oss << "NSS AES failed: " << PR_GetError();
error = oss.str();
- goto err_op;
+ return;
}
unsigned int written2;
- ret = PK11_DigestFinal(ctx, (unsigned char*)out_tmp.c_str()+written, &written2,
+ ret = PK11_DigestFinal(ectx,
+ (unsigned char*)out_tmp.c_str()+written, &written2,
out_tmp.length()-written);
if (ret != SECSuccess) {
ostringstream oss;
oss << "NSS AES final round failed: " << PR_GetError();
error = oss.str();
- goto err_op;
+ return;
}
- out_tmp.set_length(written + written2);
- out.append(out_tmp);
-
- PK11_DestroyContext(ctx, PR_TRUE);
+ PK11_DestroyContext(ectx, PR_TRUE);
SECITEM_FreeItem(param, PR_TRUE);
PK11_FreeSymKey(key);
PK11_FreeSlot(slot);
- return;
- err_op:
- PK11_DestroyContext(ctx, PR_TRUE);
- err_param:
- SECITEM_FreeItem(param, PR_TRUE);
- err_key:
- PK11_FreeSymKey(key);
- err_slot:
- PK11_FreeSlot(slot);
- err:
- ;
+ out_tmp.set_length(written + written2);
+ out.append(out_tmp);
}
+class CryptoAESKeyHandler : public CryptoKeyHandler {
+public:
+ int init(const bufferptr& s, ostringstream& err) {
+ secret = s;
+ return 0;
+ }
+
+ void encrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ nss_aes_operation(CKA_ENCRYPT, secret, in, out, error);
+ }
+ void decrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const {
+ nss_aes_operation(CKA_DECRYPT, secret, in, out, error);
+ }
+};
+
#else
# error "No supported crypto implementation found."
#endif
+
+
+// ------------------------------------------------------------
+
int CryptoAES::create(bufferptr& secret)
{
bufferlist bl;
return 0;
}
-int CryptoAES::validate_secret(bufferptr& secret)
+int CryptoAES::validate_secret(const bufferptr& secret)
{
if (secret.length() < (size_t)AES_KEY_LEN) {
return -EINVAL;
return 0;
}
-void CryptoAES::encrypt(const bufferptr& secret, const bufferlist& in, bufferlist& out,
- std::string &error) const
+CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret,
+ string& error)
{
- if (secret.length() < AES_KEY_LEN) {
- error = "key is too short";
- return;
- }
-#ifdef USE_CRYPTOPP
- {
- const unsigned char *key = (const unsigned char *)secret.c_str();
-
- string ciphertext;
- CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
- CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, (const byte*)CEPH_AES_IV );
- CryptoPP::StringSink *sink = new CryptoPP::StringSink(ciphertext);
- CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, sink);
-
- for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
- it != in.buffers().end(); ++it) {
- const unsigned char *in_buf = (const unsigned char *)it->c_str();
- stfEncryptor.Put(in_buf, it->length());
- }
- try {
- stfEncryptor.MessageEnd();
- } catch (CryptoPP::Exception& e) {
- ostringstream oss;
- oss << "encryptor.MessageEnd::Exception: " << e.GetWhat();
- error = oss.str();
- return;
- }
- out.append((const char *)ciphertext.c_str(), ciphertext.length());
+ CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler;
+ ostringstream oss;
+ if (ckh->init(secret, oss) < 0) {
+ error = oss.str();
+ return NULL;
}
-#elif USE_NSS
- nss_aes_operation(CKA_ENCRYPT, secret, in, out, error);
-#else
-# error "No supported crypto implementation found."
-#endif
+ return ckh;
}
-void CryptoAES::decrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const
-{
-#ifdef USE_CRYPTOPP
- const unsigned char *key = (const unsigned char *)secret.c_str();
-
- CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
- CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, (const byte*)CEPH_AES_IV );
- string decryptedtext;
- CryptoPP::StringSink *sink = new CryptoPP::StringSink(decryptedtext);
- CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, sink);
- for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
- it != in.buffers().end(); ++it) {
- const unsigned char *in_buf = (const unsigned char *)it->c_str();
- stfDecryptor.Put(in_buf, it->length());
- }
- try {
- stfDecryptor.MessageEnd();
- } catch (CryptoPP::Exception& e) {
- ostringstream oss;
- oss << "decryptor.MessageEnd::Exception: " << e.GetWhat();
- error = oss.str();
- return;
- }
- out.append((const char *)decryptedtext.c_str(), decryptedtext.length());
-#elif USE_NSS
- nss_aes_operation(CKA_DECRYPT, secret, in, out, error);
-#else
-# error "No supported crypto implementation found."
-#endif
-}
+// --
// ---------------------------------------------------
-int CryptoKey::set_secret(CephContext *cct, int type, bufferptr& s)
-{
- this->type = type;
- created = ceph_clock_now(cct);
- CryptoHandler *h = cct->get_crypto_handler(type);
- if (!h) {
- lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << type << ") returned NULL" << dendl;
- return -EOPNOTSUPP;
- }
- int ret = h->validate_secret(s);
-
- if (ret < 0)
- return ret;
+void CryptoKey::encode(bufferlist& bl) const
+{
+ ::encode(type, bl);
+ ::encode(created, bl);
+ __u16 len = secret.length();
+ ::encode(len, bl);
+ bl.append(secret);
+}
- secret = s;
+void CryptoKey::decode(bufferlist::iterator& bl)
+{
+ ::decode(type, bl);
+ ::decode(created, bl);
+ __u16 len;
+ ::decode(len, bl);
+ bufferptr tmp;
+ bl.copy(len, tmp);
+ if (_set_secret(type, tmp) < 0)
+ throw buffer::malformed_input("malformed secret");
+}
+int CryptoKey::set_secret(int type, const bufferptr& s, utime_t c)
+{
+ int r = _set_secret(type, s);
+ if (r < 0)
+ return r;
+ this->created = c;
return 0;
}
-int CryptoKey::create(CephContext *cct, int t)
+int CryptoKey::_set_secret(int t, const bufferptr& s)
{
- type = t;
- created = ceph_clock_now(cct);
-
- CryptoHandler *h = cct->get_crypto_handler(type);
- if (!h) {
- lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << type << ") returned NULL" << dendl;
- return -EOPNOTSUPP;
+ if (s.length() == 0) {
+ secret = s;
+ ckh.reset();
+ return 0;
}
- return h->create(secret);
-}
-void CryptoKey::encrypt(CephContext *cct, const bufferlist& in, bufferlist& out, std::string &error) const
-{
- if (!ch || ch->get_type() != type) {
- ch = cct->get_crypto_handler(type);
- if (!ch) {
- ostringstream oss;
- oss << "CryptoKey::encrypt: key type " << type << " not supported.";
- return;
+ CryptoHandler *ch = CryptoHandler::create(t);
+ if (ch) {
+ int ret = ch->validate_secret(s);
+ if (ret < 0) {
+ delete ch;
+ return ret;
+ }
+ string error;
+ ckh.reset(ch->get_key_handler(s, error));
+ delete ch;
+ if (error.length()) {
+ return -EIO;
}
}
- ch->encrypt(this->secret, in, out, error);
+ type = t;
+ secret = s;
+ return 0;
}
-void CryptoKey::decrypt(CephContext *cct, const bufferlist& in, bufferlist& out, std::string &error) const
+int CryptoKey::create(CephContext *cct, int t)
{
- if (!ch || ch->get_type() != type) {
- ch = cct->get_crypto_handler(type);
- if (!ch) {
- ostringstream oss;
- oss << "CryptoKey::decrypt: key type " << type << " not supported.";
- return;
- }
+ CryptoHandler *ch = CryptoHandler::create(t);
+ if (!ch) {
+ if (cct)
+ lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl;
+ return -EOPNOTSUPP;
}
- ch->decrypt(this->secret, in, out, error);
+ bufferptr s;
+ int r = ch->create(s);
+ delete ch;
+ if (r < 0)
+ return r;
+
+ r = _set_secret(t, s);
+ if (r < 0)
+ return r;
+ created = ceph_clock_now(cct);
+ return r;
}
void CryptoKey::print(std::ostream &out) const
#include "include/types.h"
#include "include/utime.h"
+#include "include/memory.h"
#include "common/Formatter.h"
#include "include/buffer.h"
class CephContext;
class CryptoHandler;
+class CryptoKeyContext;
+
+/*
+ * some per-key context that is specific to a particular crypto backend
+ */
+class CryptoKeyHandler {
+public:
+ bufferptr secret;
+
+ virtual ~CryptoKeyHandler() {}
+
+ virtual void encrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const = 0;
+ virtual void decrypt(const bufferlist& in,
+ bufferlist& out, std::string &error) const = 0;
+};
/*
* match encoding of struct ceph_secret
protected:
__u16 type;
utime_t created;
- bufferptr secret;
+ bufferptr secret; // must set this via set_secret()!
+
+ // cache a pointer to the implementation-specific key handler, so we
+ // don't have to create it for every crypto operation.
+ mutable ceph::shared_ptr<CryptoKeyHandler> ckh;
- // cache a pointer to the handler, so we don't have to look it up
- // for each crypto operation
- mutable CryptoHandler *ch;
+ int _set_secret(int type, const bufferptr& s);
public:
- CryptoKey() : type(0), ch(NULL) { }
- CryptoKey(int t, utime_t c, bufferptr& s) : type(t), created(c), secret(s), ch(NULL) { }
-
- void encode(bufferlist& bl) const {
- ::encode(type, bl);
- ::encode(created, bl);
- __u16 len = secret.length();
- ::encode(len, bl);
- bl.append(secret);
+ CryptoKey() : type(0) { }
+ CryptoKey(int t, utime_t c, bufferptr& s)
+ : created(c) {
+ _set_secret(t, s);
}
- void decode(bufferlist::iterator& bl) {
- ::decode(type, bl);
- ::decode(created, bl);
- __u16 len;
- ::decode(len, bl);
- bl.copy(len, secret);
- secret.c_str(); // make sure it's a single buffer!
+ ~CryptoKey() {
}
+ void encode(bufferlist& bl) const;
+ void decode(bufferlist::iterator& bl);
+
int get_type() const { return type; }
utime_t get_created() const { return created; }
void print(std::ostream& out) const;
- int set_secret(CephContext *cct, int type, bufferptr& s);
- bufferptr& get_secret() { return secret; }
+ int set_secret(int type, const bufferptr& s, utime_t created);
+ const bufferptr& get_secret() { return secret; }
const bufferptr& get_secret() const { return secret; }
void encode_base64(string& s) const {
// --
int create(CephContext *cct, int type);
- void encrypt(CephContext *cct, const bufferlist& in, bufferlist& out, std::string &error) const;
- void decrypt(CephContext *cct, const bufferlist& in, bufferlist& out, std::string &error) const;
+ void encrypt(CephContext *cct, const bufferlist& in, bufferlist& out,
+ std::string &error) const {
+ ckh->encrypt(in, out, error);
+ }
+ void decrypt(CephContext *cct, const bufferlist& in, bufferlist& out,
+ std::string &error) const {
+ ckh->decrypt(in, out, error);
+ }
void to_str(std::string& s) const;
};
virtual ~CryptoHandler() {}
virtual int get_type() const = 0;
virtual int create(bufferptr& secret) = 0;
- virtual int validate_secret(bufferptr& secret) = 0;
- virtual void encrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const = 0;
- virtual void decrypt(const bufferptr& secret, const bufferlist& in,
- bufferlist& out, std::string &error) const = 0;
+ virtual int validate_secret(const bufferptr& secret) = 0;
+ virtual CryptoKeyHandler *get_key_handler(const bufferptr& secret,
+ string& error) = 0;
static CryptoHandler *create(int type);
};