Treat OpenSSL as a non-portable include
[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/io/async/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     void hash_init(const EVP_MD* md) {
37       md_ = md;
38       check_libssl_result(1, EVP_DigestInit_ex(ctx_.get(), md, nullptr));
39     }
40     void hash_update(ByteRange data) {
41       check_libssl_result(
42           1, EVP_DigestUpdate(ctx_.get(), data.data(), data.size()));
43     }
44     void hash_update(const IOBuf& data) {
45       for (auto r : data) {
46         hash_update(r);
47       }
48     }
49     void hash_final(MutableByteRange out) {
50       const auto size = EVP_MD_size(md_);
51       check_out_size(size_t(size), out);
52       unsigned int len = 0;
53       check_libssl_result(1, EVP_DigestFinal_ex(ctx_.get(), out.data(), &len));
54       check_libssl_result(size, int(len));
55       md_ = nullptr;
56     }
57    private:
58     const EVP_MD* md_ = nullptr;
59     EvpMdCtxUniquePtr ctx_{nullptr};
60   };
61
62   static void hash(
63       MutableByteRange out,
64       const EVP_MD* md,
65       ByteRange data) {
66     Digest hash;
67     hash.hash_init(md);
68     hash.hash_update(data);
69     hash.hash_final(out);
70   }
71   static void hash(
72       MutableByteRange out,
73       const EVP_MD* md,
74       const IOBuf& data) {
75     Digest hash;
76     hash.hash_init(md);
77     hash.hash_update(data);
78     hash.hash_final(out);
79   }
80   static void sha1(MutableByteRange out, ByteRange data) {
81     hash(out, EVP_sha1(), data);
82   }
83   static void sha1(MutableByteRange out, const IOBuf& data) {
84     hash(out, EVP_sha1(), data);
85   }
86   static void sha256(MutableByteRange out, ByteRange data) {
87     hash(out, EVP_sha256(), data);
88   }
89   static void sha256(MutableByteRange out, const IOBuf& data) {
90     hash(out, EVP_sha256(), data);
91   }
92
93   class Hmac {
94    public:
95     Hmac() : ctx_(HMAC_CTX_new()) {}
96
97     void hash_init(const EVP_MD* md, ByteRange key) {
98       md_ = md;
99       check_libssl_result(
100           1,
101           HMAC_Init_ex(ctx_.get(), key.data(), int(key.size()), md_, nullptr));
102     }
103     void hash_update(ByteRange data) {
104       check_libssl_result(1, HMAC_Update(ctx_.get(), data.data(), data.size()));
105     }
106     void hash_update(const IOBuf& data) {
107       for (auto r : data) {
108         hash_update(r);
109       }
110     }
111     void hash_final(MutableByteRange out) {
112       const auto size = EVP_MD_size(md_);
113       check_out_size(size_t(size), out);
114       unsigned int len = 0;
115       check_libssl_result(1, HMAC_Final(ctx_.get(), out.data(), &len));
116       check_libssl_result(size, int(len));
117       md_ = nullptr;
118     }
119    private:
120     const EVP_MD* md_ = nullptr;
121     HmacCtxUniquePtr ctx_{nullptr};
122   };
123
124   static void hmac(
125       MutableByteRange out,
126       const EVP_MD* md,
127       ByteRange key,
128       ByteRange data) {
129     Hmac hmac;
130     hmac.hash_init(md, key);
131     hmac.hash_update(data);
132     hmac.hash_final(out);
133   }
134   static void hmac(
135       MutableByteRange out,
136       const EVP_MD* md,
137       ByteRange key,
138       const IOBuf& data) {
139     Hmac hmac;
140     hmac.hash_init(md, key);
141     hmac.hash_update(data);
142     hmac.hash_final(out);
143   }
144   static void hmac_sha1(
145       MutableByteRange out, ByteRange key, ByteRange data) {
146     hmac(out, EVP_sha1(), key, data);
147   }
148   static void hmac_sha1(
149       MutableByteRange out, ByteRange key, const IOBuf& data) {
150     hmac(out, EVP_sha1(), key, data);
151   }
152   static void hmac_sha256(
153       MutableByteRange out, ByteRange key, ByteRange data) {
154     hmac(out, EVP_sha256(), key, data);
155   }
156   static void hmac_sha256(
157       MutableByteRange out, ByteRange key, const IOBuf& data) {
158     hmac(out, EVP_sha256(), key, data);
159   }
160
161  private:
162   static inline void check_out_size(size_t size, MutableByteRange out) {
163     if (LIKELY(size == out.size())) {
164       return;
165     }
166     check_out_size_throw(size, out);
167   }
168   [[noreturn]] static void check_out_size_throw(
169       size_t size,
170       MutableByteRange out);
171
172   static inline void check_libssl_result(int expected, int result) {
173     if (LIKELY(result == expected)) {
174       return;
175     }
176     check_libssl_result_throw();
177   }
178   [[noreturn]] static void check_libssl_result_throw();
179 };
180
181 }
182 }