Move OpenSSLPtrTypes.h from folly/io/async/ssl to folly/ssl
[folly.git] / folly / ssl / OpenSSLHash.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/Range.h>
20 #include <folly/io/IOBuf.h>
21 #include <folly/ssl/OpenSSLPtrTypes.h>
22 #include <folly/portability/OpenSSL.h>
23
24 namespace folly {
25 namespace ssl {
26
27 /// Warning:
28 /// These functions are not thread-safe unless you initialize OpenSSL.
29 class OpenSSLHash {
30  public:
31
32   class Digest {
33    public:
34     Digest() : ctx_(EVP_MD_CTX_new()) {}
35
36     Digest(const Digest& other) {
37       ctx_ = EvpMdCtxUniquePtr(EVP_MD_CTX_new());
38       if (other.md_ != nullptr) {
39         hash_init(other.md_);
40         check_libssl_result(
41             1, EVP_MD_CTX_copy_ex(ctx_.get(), other.ctx_.get()));
42       }
43     }
44
45     Digest& operator=(const Digest& other) {
46       this->~Digest();
47       return *new (this) Digest(other);
48     }
49
50     void hash_init(const EVP_MD* md) {
51       md_ = md;
52       check_libssl_result(1, EVP_DigestInit_ex(ctx_.get(), md, nullptr));
53     }
54     void hash_update(ByteRange data) {
55       check_libssl_result(
56           1, EVP_DigestUpdate(ctx_.get(), data.data(), data.size()));
57     }
58     void hash_update(const IOBuf& data) {
59       for (auto r : data) {
60         hash_update(r);
61       }
62     }
63     void hash_final(MutableByteRange out) {
64       const auto size = EVP_MD_size(md_);
65       check_out_size(size_t(size), out);
66       unsigned int len = 0;
67       check_libssl_result(1, EVP_DigestFinal_ex(ctx_.get(), out.data(), &len));
68       check_libssl_result(size, int(len));
69       md_ = nullptr;
70     }
71
72    private:
73     const EVP_MD* md_ = nullptr;
74     EvpMdCtxUniquePtr ctx_{nullptr};
75   };
76
77   static void hash(
78       MutableByteRange out,
79       const EVP_MD* md,
80       ByteRange data) {
81     Digest hash;
82     hash.hash_init(md);
83     hash.hash_update(data);
84     hash.hash_final(out);
85   }
86   static void hash(
87       MutableByteRange out,
88       const EVP_MD* md,
89       const IOBuf& data) {
90     Digest hash;
91     hash.hash_init(md);
92     hash.hash_update(data);
93     hash.hash_final(out);
94   }
95   static void sha1(MutableByteRange out, ByteRange data) {
96     hash(out, EVP_sha1(), data);
97   }
98   static void sha1(MutableByteRange out, const IOBuf& data) {
99     hash(out, EVP_sha1(), data);
100   }
101   static void sha256(MutableByteRange out, ByteRange data) {
102     hash(out, EVP_sha256(), data);
103   }
104   static void sha256(MutableByteRange out, const IOBuf& data) {
105     hash(out, EVP_sha256(), data);
106   }
107
108   class Hmac {
109    public:
110     Hmac() : ctx_(HMAC_CTX_new()) {}
111
112     void hash_init(const EVP_MD* md, ByteRange key) {
113       md_ = md;
114       check_libssl_result(
115           1,
116           HMAC_Init_ex(ctx_.get(), key.data(), int(key.size()), md_, nullptr));
117     }
118     void hash_update(ByteRange data) {
119       check_libssl_result(1, HMAC_Update(ctx_.get(), data.data(), data.size()));
120     }
121     void hash_update(const IOBuf& data) {
122       for (auto r : data) {
123         hash_update(r);
124       }
125     }
126     void hash_final(MutableByteRange out) {
127       const auto size = EVP_MD_size(md_);
128       check_out_size(size_t(size), out);
129       unsigned int len = 0;
130       check_libssl_result(1, HMAC_Final(ctx_.get(), out.data(), &len));
131       check_libssl_result(size, int(len));
132       md_ = nullptr;
133     }
134    private:
135     const EVP_MD* md_ = nullptr;
136     HmacCtxUniquePtr ctx_{nullptr};
137   };
138
139   static void hmac(
140       MutableByteRange out,
141       const EVP_MD* md,
142       ByteRange key,
143       ByteRange data) {
144     Hmac hmac;
145     hmac.hash_init(md, key);
146     hmac.hash_update(data);
147     hmac.hash_final(out);
148   }
149   static void hmac(
150       MutableByteRange out,
151       const EVP_MD* md,
152       ByteRange key,
153       const IOBuf& data) {
154     Hmac hmac;
155     hmac.hash_init(md, key);
156     hmac.hash_update(data);
157     hmac.hash_final(out);
158   }
159   static void hmac_sha1(
160       MutableByteRange out, ByteRange key, ByteRange data) {
161     hmac(out, EVP_sha1(), key, data);
162   }
163   static void hmac_sha1(
164       MutableByteRange out, ByteRange key, const IOBuf& data) {
165     hmac(out, EVP_sha1(), key, data);
166   }
167   static void hmac_sha256(
168       MutableByteRange out, ByteRange key, ByteRange data) {
169     hmac(out, EVP_sha256(), key, data);
170   }
171   static void hmac_sha256(
172       MutableByteRange out, ByteRange key, const IOBuf& data) {
173     hmac(out, EVP_sha256(), key, data);
174   }
175
176  private:
177   static inline void check_out_size(size_t size, MutableByteRange out) {
178     if (LIKELY(size == out.size())) {
179       return;
180     }
181     check_out_size_throw(size, out);
182   }
183   [[noreturn]] static void check_out_size_throw(
184       size_t size,
185       MutableByteRange out);
186
187   static inline void check_libssl_result(int expected, int result) {
188     if (LIKELY(result == expected)) {
189       return;
190     }
191     check_libssl_result_throw();
192   }
193   [[noreturn]] static void check_libssl_result_throw();
194 };
195
196 }
197 }