diff options
Diffstat (limited to 'src/common/ceph_crypto.h')
-rw-r--r-- | src/common/ceph_crypto.h | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/common/ceph_crypto.h b/src/common/ceph_crypto.h new file mode 100644 index 000000000..bcdc0044c --- /dev/null +++ b/src/common/ceph_crypto.h @@ -0,0 +1,215 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +#ifndef CEPH_CRYPTO_H +#define CEPH_CRYPTO_H + +#include "acconfig.h" +#include <stdexcept> + +#include "include/common_fwd.h" +#include "include/buffer.h" +#include "include/types.h" + +#define CEPH_CRYPTO_MD5_DIGESTSIZE 16 +#define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20 +#define CEPH_CRYPTO_SHA1_DIGESTSIZE 20 +#define CEPH_CRYPTO_HMACSHA256_DIGESTSIZE 32 +#define CEPH_CRYPTO_SHA256_DIGESTSIZE 32 +#define CEPH_CRYPTO_SHA512_DIGESTSIZE 64 + +#include <openssl/evp.h> +#include <openssl/ossl_typ.h> +#include <openssl/hmac.h> + +#include "include/ceph_assert.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +extern "C" { + const EVP_MD *EVP_md5(void); + const EVP_MD *EVP_sha1(void); + const EVP_MD *EVP_sha256(void); + const EVP_MD *EVP_sha512(void); +} + +namespace TOPNSPC::crypto { + void assert_init(); + void init(); + void shutdown(bool shared=true); + + void zeroize_for_security(void *s, size_t n); + + class DigestException : public std::runtime_error + { + public: + DigestException(const char* what_arg) : runtime_error(what_arg) + {} + }; + + namespace ssl { + class OpenSSLDigest { + private: + EVP_MD_CTX *mpContext; + const EVP_MD *mpType; + EVP_MD *mpType_FIPS = nullptr; + public: + OpenSSLDigest (const EVP_MD *_type); + ~OpenSSLDigest (); + void Restart(); + void SetFlags(int flags); + void Update (const unsigned char *input, size_t length); + void Final (unsigned char *digest); + }; + + class MD5 : public OpenSSLDigest { + public: + static constexpr size_t digest_size = CEPH_CRYPTO_MD5_DIGESTSIZE; + MD5 () : OpenSSLDigest(EVP_md5()) { } + }; + + class SHA1 : public OpenSSLDigest { + public: + static constexpr size_t digest_size = CEPH_CRYPTO_SHA1_DIGESTSIZE; + SHA1 () : OpenSSLDigest(EVP_sha1()) { } + }; + + class SHA256 : public OpenSSLDigest { + public: + static constexpr size_t digest_size = CEPH_CRYPTO_SHA256_DIGESTSIZE; + SHA256 () : OpenSSLDigest(EVP_sha256()) { } + }; + + class SHA512 : public OpenSSLDigest { + public: + static constexpr size_t digest_size = CEPH_CRYPTO_SHA512_DIGESTSIZE; + SHA512 () : OpenSSLDigest(EVP_sha512()) { } + }; + + +# if OPENSSL_VERSION_NUMBER < 0x10100000L + class HMAC { + private: + HMAC_CTX mContext; + const EVP_MD *mpType; + + public: + HMAC (const EVP_MD *type, const unsigned char *key, size_t length) + : mpType(type) { + // the strict FIPS zeroization doesn't seem to be necessary here. + // just in the case. + ::TOPNSPC::crypto::zeroize_for_security(&mContext, sizeof(mContext)); + const auto r = HMAC_Init_ex(&mContext, key, length, mpType, nullptr); + if (r != 1) { + throw DigestException("HMAC_Init_ex() failed"); + } + } + ~HMAC () { + HMAC_CTX_cleanup(&mContext); + } + + void Restart () { + const auto r = HMAC_Init_ex(&mContext, nullptr, 0, mpType, nullptr); + if (r != 1) { + throw DigestException("HMAC_Init_ex() failed"); + } + } + void Update (const unsigned char *input, size_t length) { + if (length) { + const auto r = HMAC_Update(&mContext, input, length); + if (r != 1) { + throw DigestException("HMAC_Update() failed"); + } + } + } + void Final (unsigned char *digest) { + unsigned int s; + const auto r = HMAC_Final(&mContext, digest, &s); + if (r != 1) { + throw DigestException("HMAC_Final() failed"); + } + } + }; +# else + class HMAC { + private: + HMAC_CTX *mpContext; + + public: + HMAC (const EVP_MD *type, const unsigned char *key, size_t length) + : mpContext(HMAC_CTX_new()) { + const auto r = HMAC_Init_ex(mpContext, key, length, type, nullptr); + if (r != 1) { + throw DigestException("HMAC_Init_ex() failed"); + } + } + ~HMAC () { + HMAC_CTX_free(mpContext); + } + + void Restart () { + const EVP_MD * const type = HMAC_CTX_get_md(mpContext); + const auto r = HMAC_Init_ex(mpContext, nullptr, 0, type, nullptr); + if (r != 1) { + throw DigestException("HMAC_Init_ex() failed"); + } + } + void Update (const unsigned char *input, size_t length) { + if (length) { + const auto r = HMAC_Update(mpContext, input, length); + if (r != 1) { + throw DigestException("HMAC_Update() failed"); + } + } + } + void Final (unsigned char *digest) { + unsigned int s; + const auto r = HMAC_Final(mpContext, digest, &s); + if (r != 1) { + throw DigestException("HMAC_Final() failed"); + } + } + }; +# endif // OPENSSL_VERSION_NUMBER < 0x10100000L + + struct HMACSHA1 : public HMAC { + HMACSHA1 (const unsigned char *key, size_t length) + : HMAC(EVP_sha1(), key, length) { + } + }; + + struct HMACSHA256 : public HMAC { + HMACSHA256 (const unsigned char *key, size_t length) + : HMAC(EVP_sha256(), key, length) { + } + }; +} + + + using ssl::SHA256; + using ssl::MD5; + using ssl::SHA1; + using ssl::SHA512; + + using ssl::HMACSHA256; + using ssl::HMACSHA1; + +template<class Digest> +auto digest(const ceph::buffer::list& bl) +{ + unsigned char fingerprint[Digest::digest_size]; + Digest gen; + for (auto& p : bl.buffers()) { + gen.Update((const unsigned char *)p.c_str(), p.length()); + } + gen.Final(fingerprint); + return sha_digest_t<Digest::digest_size>{fingerprint}; +} +} + +#pragma clang diagnostic pop +#pragma GCC diagnostic pop + +#endif |