2017
[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 <openssl/evp.h>
20 #include <openssl/hmac.h>
21 #include <openssl/sha.h>
22
23 #include <folly/Range.h>
24 #include <folly/io/IOBuf.h>
25
26 namespace folly {
27 namespace ssl {
28
29 /// Warning:
30 /// These functions are not thread-safe unless you initialize OpenSSL.
31 class OpenSSLHash {
32  public:
33
34   class Digest {
35    public:
36     Digest() {
37       EVP_MD_CTX_init(&ctx_);
38     }
39     ~Digest() {
40       EVP_MD_CTX_cleanup(&ctx_);
41     }
42     void hash_init(const EVP_MD* md) {
43       md_ = md;
44       check_libssl_result(1, EVP_DigestInit_ex(&ctx_, md, nullptr));
45     }
46     void hash_update(ByteRange data) {
47       check_libssl_result(1, EVP_DigestUpdate(&ctx_, data.data(), data.size()));
48     }
49     void hash_update(const IOBuf& data) {
50       for (auto r : data) {
51         hash_update(r);
52       }
53     }
54     void hash_final(MutableByteRange out) {
55       const auto size = EVP_MD_size(md_);
56       check_out_size(size, out);
57       unsigned int len = 0;
58       check_libssl_result(1, EVP_DigestFinal_ex(&ctx_, out.data(), &len));
59       check_libssl_result(size, len);
60       md_ = nullptr;
61     }
62    private:
63     const EVP_MD* md_ = nullptr;
64     EVP_MD_CTX ctx_;
65   };
66
67   static void hash(
68       MutableByteRange out,
69       const EVP_MD* md,
70       ByteRange data) {
71     Digest hash;
72     hash.hash_init(md);
73     hash.hash_update(data);
74     hash.hash_final(out);
75   }
76   static void hash(
77       MutableByteRange out,
78       const EVP_MD* md,
79       const IOBuf& data) {
80     Digest hash;
81     hash.hash_init(md);
82     hash.hash_update(data);
83     hash.hash_final(out);
84   }
85   static void sha1(MutableByteRange out, ByteRange data) {
86     hash(out, EVP_sha1(), data);
87   }
88   static void sha1(MutableByteRange out, const IOBuf& data) {
89     hash(out, EVP_sha1(), data);
90   }
91   static void sha256(MutableByteRange out, ByteRange data) {
92     hash(out, EVP_sha256(), data);
93   }
94   static void sha256(MutableByteRange out, const IOBuf& data) {
95     hash(out, EVP_sha256(), data);
96   }
97
98   class Hmac {
99    public:
100     Hmac() {
101       HMAC_CTX_init(&ctx_);
102     }
103     ~Hmac() {
104       HMAC_CTX_cleanup(&ctx_);
105     }
106     void hash_init(const EVP_MD* md, ByteRange key) {
107       md_ = md;
108       check_libssl_result(
109           1, HMAC_Init_ex(&ctx_, key.data(), int(key.size()), md_, nullptr));
110     }
111     void hash_update(ByteRange data) {
112       check_libssl_result(1, HMAC_Update(&ctx_, data.data(), data.size()));
113     }
114     void hash_update(const IOBuf& data) {
115       for (auto r : data) {
116         hash_update(r);
117       }
118     }
119     void hash_final(MutableByteRange out) {
120       const auto size = EVP_MD_size(md_);
121       check_out_size(size, out);
122       unsigned int len = 0;
123       check_libssl_result(1, HMAC_Final(&ctx_, out.data(), &len));
124       check_libssl_result(size, int(len));
125       md_ = nullptr;
126     }
127    private:
128     const EVP_MD* md_ = nullptr;
129     HMAC_CTX ctx_;
130   };
131
132   static void hmac(
133       MutableByteRange out,
134       const EVP_MD* md,
135       ByteRange key,
136       ByteRange data) {
137     Hmac hmac;
138     hmac.hash_init(md, key);
139     hmac.hash_update(data);
140     hmac.hash_final(out);
141   }
142   static void hmac(
143       MutableByteRange out,
144       const EVP_MD* md,
145       ByteRange key,
146       const IOBuf& data) {
147     Hmac hmac;
148     hmac.hash_init(md, key);
149     hmac.hash_update(data);
150     hmac.hash_final(out);
151   }
152   static void hmac_sha1(
153       MutableByteRange out, ByteRange key, ByteRange data) {
154     hmac(out, EVP_sha1(), key, data);
155   }
156   static void hmac_sha1(
157       MutableByteRange out, ByteRange key, const IOBuf& data) {
158     hmac(out, EVP_sha1(), key, data);
159   }
160   static void hmac_sha256(
161       MutableByteRange out, ByteRange key, ByteRange data) {
162     hmac(out, EVP_sha256(), key, data);
163   }
164   static void hmac_sha256(
165       MutableByteRange out, ByteRange key, const IOBuf& data) {
166     hmac(out, EVP_sha256(), key, data);
167   }
168
169  private:
170   static inline void check_out_size(size_t size, MutableByteRange out) {
171     if (LIKELY(size == out.size())) {
172       return;
173     }
174     check_out_size_throw(size, out);
175   }
176   [[noreturn]] static void check_out_size_throw(
177       size_t size,
178       MutableByteRange out);
179
180   static inline void check_libssl_result(int expected, int result) {
181     if (LIKELY(result == expected)) {
182       return;
183     }
184     check_libssl_result_throw();
185   }
186   [[noreturn]] static void check_libssl_result_throw();
187 };
188
189 }
190 }