]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_crypto.h
import ceph quincy 17.2.4
[ceph.git] / ceph / src / common / ceph_crypto.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 #ifndef CEPH_CRYPTO_H
3 #define CEPH_CRYPTO_H
4
5 #include "acconfig.h"
6 #include <stdexcept>
7
8 #include "include/common_fwd.h"
9 #include "include/buffer.h"
10 #include "include/types.h"
11
12 #define CEPH_CRYPTO_MD5_DIGESTSIZE 16
13 #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20
14 #define CEPH_CRYPTO_SHA1_DIGESTSIZE 20
15 #define CEPH_CRYPTO_HMACSHA256_DIGESTSIZE 32
16 #define CEPH_CRYPTO_SHA256_DIGESTSIZE 32
17 #define CEPH_CRYPTO_SHA512_DIGESTSIZE 64
18
19 #include <openssl/evp.h>
20 #include <openssl/ossl_typ.h>
21 #include <openssl/hmac.h>
22
23 #include "include/ceph_assert.h"
24
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
27
28 #pragma clang diagnostic push
29 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
30
31 extern "C" {
32 const EVP_MD *EVP_md5(void);
33 const EVP_MD *EVP_sha1(void);
34 const EVP_MD *EVP_sha256(void);
35 const EVP_MD *EVP_sha512(void);
36 }
37
38 namespace TOPNSPC::crypto {
39 void assert_init();
40 void init();
41 void shutdown(bool shared=true);
42
43 void zeroize_for_security(void *s, size_t n);
44
45 class DigestException : public std::runtime_error
46 {
47 public:
48 DigestException(const char* what_arg) : runtime_error(what_arg)
49 {}
50 };
51
52 namespace ssl {
53 class OpenSSLDigest {
54 private:
55 EVP_MD_CTX *mpContext;
56 const EVP_MD *mpType;
57 public:
58 OpenSSLDigest (const EVP_MD *_type);
59 ~OpenSSLDigest ();
60 void Restart();
61 void SetFlags(int flags);
62 void Update (const unsigned char *input, size_t length);
63 void Final (unsigned char *digest);
64 };
65
66 class MD5 : public OpenSSLDigest {
67 public:
68 static constexpr size_t digest_size = CEPH_CRYPTO_MD5_DIGESTSIZE;
69 MD5 () : OpenSSLDigest(EVP_md5()) { }
70 };
71
72 class SHA1 : public OpenSSLDigest {
73 public:
74 static constexpr size_t digest_size = CEPH_CRYPTO_SHA1_DIGESTSIZE;
75 SHA1 () : OpenSSLDigest(EVP_sha1()) { }
76 };
77
78 class SHA256 : public OpenSSLDigest {
79 public:
80 static constexpr size_t digest_size = CEPH_CRYPTO_SHA256_DIGESTSIZE;
81 SHA256 () : OpenSSLDigest(EVP_sha256()) { }
82 };
83
84 class SHA512 : public OpenSSLDigest {
85 public:
86 static constexpr size_t digest_size = CEPH_CRYPTO_SHA512_DIGESTSIZE;
87 SHA512 () : OpenSSLDigest(EVP_sha512()) { }
88 };
89
90
91 # if OPENSSL_VERSION_NUMBER < 0x10100000L
92 class HMAC {
93 private:
94 HMAC_CTX mContext;
95 const EVP_MD *mpType;
96
97 public:
98 HMAC (const EVP_MD *type, const unsigned char *key, size_t length)
99 : mpType(type) {
100 // the strict FIPS zeroization doesn't seem to be necessary here.
101 // just in the case.
102 ::TOPNSPC::crypto::zeroize_for_security(&mContext, sizeof(mContext));
103 const auto r = HMAC_Init_ex(&mContext, key, length, mpType, nullptr);
104 if (r != 1) {
105 throw DigestException("HMAC_Init_ex() failed");
106 }
107 }
108 ~HMAC () {
109 HMAC_CTX_cleanup(&mContext);
110 }
111
112 void Restart () {
113 const auto r = HMAC_Init_ex(&mContext, nullptr, 0, mpType, nullptr);
114 if (r != 1) {
115 throw DigestException("HMAC_Init_ex() failed");
116 }
117 }
118 void Update (const unsigned char *input, size_t length) {
119 if (length) {
120 const auto r = HMAC_Update(&mContext, input, length);
121 if (r != 1) {
122 throw DigestException("HMAC_Update() failed");
123 }
124 }
125 }
126 void Final (unsigned char *digest) {
127 unsigned int s;
128 const auto r = HMAC_Final(&mContext, digest, &s);
129 if (r != 1) {
130 throw DigestException("HMAC_Final() failed");
131 }
132 }
133 };
134 # else
135 class HMAC {
136 private:
137 HMAC_CTX *mpContext;
138
139 public:
140 HMAC (const EVP_MD *type, const unsigned char *key, size_t length)
141 : mpContext(HMAC_CTX_new()) {
142 const auto r = HMAC_Init_ex(mpContext, key, length, type, nullptr);
143 if (r != 1) {
144 throw DigestException("HMAC_Init_ex() failed");
145 }
146 }
147 ~HMAC () {
148 HMAC_CTX_free(mpContext);
149 }
150
151 void Restart () {
152 const EVP_MD * const type = HMAC_CTX_get_md(mpContext);
153 const auto r = HMAC_Init_ex(mpContext, nullptr, 0, type, nullptr);
154 if (r != 1) {
155 throw DigestException("HMAC_Init_ex() failed");
156 }
157 }
158 void Update (const unsigned char *input, size_t length) {
159 if (length) {
160 const auto r = HMAC_Update(mpContext, input, length);
161 if (r != 1) {
162 throw DigestException("HMAC_Update() failed");
163 }
164 }
165 }
166 void Final (unsigned char *digest) {
167 unsigned int s;
168 const auto r = HMAC_Final(mpContext, digest, &s);
169 if (r != 1) {
170 throw DigestException("HMAC_Final() failed");
171 }
172 }
173 };
174 # endif // OPENSSL_VERSION_NUMBER < 0x10100000L
175
176 struct HMACSHA1 : public HMAC {
177 HMACSHA1 (const unsigned char *key, size_t length)
178 : HMAC(EVP_sha1(), key, length) {
179 }
180 };
181
182 struct HMACSHA256 : public HMAC {
183 HMACSHA256 (const unsigned char *key, size_t length)
184 : HMAC(EVP_sha256(), key, length) {
185 }
186 };
187 }
188
189
190 using ssl::SHA256;
191 using ssl::MD5;
192 using ssl::SHA1;
193 using ssl::SHA512;
194
195 using ssl::HMACSHA256;
196 using ssl::HMACSHA1;
197
198 template<class Digest>
199 auto digest(const ceph::buffer::list& bl)
200 {
201 unsigned char fingerprint[Digest::digest_size];
202 Digest gen;
203 for (auto& p : bl.buffers()) {
204 gen.Update((const unsigned char *)p.c_str(), p.length());
205 }
206 gen.Final(fingerprint);
207 return sha_digest_t<Digest::digest_size>{fingerprint};
208 }
209 }
210
211 #pragma clang diagnostic pop
212 #pragma GCC diagnostic pop
213
214 #endif