diff options
Diffstat (limited to '')
-rw-r--r-- | src/auth/Crypto.h | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/auth/Crypto.h b/src/auth/Crypto.h new file mode 100644 index 00000000..5ccc20fd --- /dev/null +++ b/src/auth/Crypto.h @@ -0,0 +1,216 @@ +// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_AUTH_CRYPTO_H +#define CEPH_AUTH_CRYPTO_H + +#include "include/types.h" +#include "include/utime.h" +#include "include/buffer.h" + +#include <string> + +class CephContext; +class CryptoKeyContext; +namespace ceph { class Formatter; } + +/* + * Random byte stream generator suitable for cryptographic use + */ +class CryptoRandom { +public: + CryptoRandom(); // throws on failure + ~CryptoRandom(); + /// copy up to 256 random bytes into the given buffer. throws on failure + void get_bytes(char *buf, int len); +private: + static int open_urandom(); + const int fd; +}; + +/* + * some per-key context that is specific to a particular crypto backend + */ +class CryptoKeyHandler { +public: + // The maximum size of a single block for all descendants of the class. + static constexpr std::size_t MAX_BLOCK_SIZE {16}; + + // A descendant pick-ups one from these and passes it to the ctor template. + typedef std::integral_constant<std::size_t, 0> BLOCK_SIZE_0B; + typedef std::integral_constant<std::size_t, 16> BLOCK_SIZE_16B; + + struct in_slice_t { + const std::size_t length; + const unsigned char* const buf; + }; + + struct out_slice_t { + const std::size_t max_length; + unsigned char* const buf; + }; + + ceph::bufferptr secret; + + template <class BlockSizeT> + CryptoKeyHandler(BlockSizeT) { + static_assert(BlockSizeT::value <= MAX_BLOCK_SIZE); + } + + virtual ~CryptoKeyHandler() {} + + virtual int encrypt(const bufferlist& in, + bufferlist& out, std::string *error) const = 0; + virtual int decrypt(const bufferlist& in, + bufferlist& out, std::string *error) const = 0; + + // TODO: provide nullptr in the out::buf to get/estimate size requirements? + // Or maybe dedicated methods? + virtual std::size_t encrypt(const in_slice_t& in, + const out_slice_t& out) const; + virtual std::size_t decrypt(const in_slice_t& in, + const out_slice_t& out) const; + + sha256_digest_t hmac_sha256(const ceph::bufferlist& in) const; +}; + +/* + * match encoding of struct ceph_secret + */ +class CryptoKey { +protected: + __u16 type; + utime_t created; + 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 std::shared_ptr<CryptoKeyHandler> ckh; + + int _set_secret(int type, const bufferptr& s); + +public: + CryptoKey() : type(0) { } + CryptoKey(int t, utime_t c, bufferptr& s) + : created(c) { + _set_secret(t, s); + } + ~CryptoKey() { + } + + void encode(bufferlist& bl) const; + void decode(bufferlist::const_iterator& bl); + + int get_type() const { return type; } + utime_t get_created() const { return created; } + void print(std::ostream& out) const; + + int set_secret(int type, const bufferptr& s, utime_t created); + const bufferptr& get_secret() { return secret; } + const bufferptr& get_secret() const { return secret; } + + bool empty() const { return ckh.get() == nullptr; } + + void encode_base64(string& s) const { + bufferlist bl; + encode(bl); + bufferlist e; + bl.encode_base64(e); + e.append('\0'); + s = e.c_str(); + } + string encode_base64() const { + string s; + encode_base64(s); + return s; + } + void decode_base64(const string& s) { + bufferlist e; + e.append(s); + bufferlist bl; + bl.decode_base64(e); + auto p = std::cbegin(bl); + decode(p); + } + + void encode_formatted(string label, Formatter *f, bufferlist &bl); + void encode_plaintext(bufferlist &bl); + + // -- + int create(CephContext *cct, int type); + int encrypt(CephContext *cct, const bufferlist& in, bufferlist& out, + std::string *error) const { + ceph_assert(ckh); // Bad key? + return ckh->encrypt(in, out, error); + } + int decrypt(CephContext *cct, const bufferlist& in, bufferlist& out, + std::string *error) const { + ceph_assert(ckh); // Bad key? + return ckh->decrypt(in, out, error); + } + + using in_slice_t = CryptoKeyHandler::in_slice_t; + using out_slice_t = CryptoKeyHandler::out_slice_t; + + std::size_t encrypt(CephContext*, const in_slice_t& in, + const out_slice_t& out) { + ceph_assert(ckh); + return ckh->encrypt(in, out); + } + std::size_t decrypt(CephContext*, const in_slice_t& in, + const out_slice_t& out) { + ceph_assert(ckh); + return ckh->encrypt(in, out); + } + + sha256_digest_t hmac_sha256(CephContext*, const ceph::bufferlist& in) { + ceph_assert(ckh); + return ckh->hmac_sha256(in); + } + + static constexpr std::size_t get_max_outbuf_size(std::size_t want_size) { + return want_size + CryptoKeyHandler::MAX_BLOCK_SIZE; + } + + void to_str(std::string& s) const; +}; +WRITE_CLASS_ENCODER(CryptoKey) + +static inline ostream& operator<<(ostream& out, const CryptoKey& k) +{ + k.print(out); + return out; +} + + +/* + * Driver for a particular algorithm + * + * To use these functions, you need to call ceph::crypto::init(), see + * common/ceph_crypto.h. common_init_finish does this for you. + */ +class CryptoHandler { +public: + virtual ~CryptoHandler() {} + virtual int get_type() const = 0; + virtual int create(CryptoRandom *random, bufferptr& secret) = 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); +}; + + +#endif |