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