@@ -111,14 +111,9 @@ class Hash::CNGContext : public Hash::Context {
111
111
unsigned long m_hashLength;
112
112
};
113
113
114
- #else // Unix systems
115
-
116
- # ifdef __APPLE__
117
- # define COMMON_DIGEST_FOR_OPENSSL
118
- # include < CommonCrypto/CommonDigest.h>
119
- # else
120
- # include < openssl/sha.h>
121
- # endif
114
+ #elif __APPLE__
115
+ # define COMMON_DIGEST_FOR_OPENSSL
116
+ # include < CommonCrypto/CommonDigest.h>
122
117
123
118
class Hash ::SHA256Context : public Hash::Context {
124
119
public:
@@ -146,6 +141,120 @@ class Hash::SHA256Context : public Hash::Context {
146
141
SHA256_CTX m_context;
147
142
};
148
143
144
+ #else
145
+ # include < openssl/evp.h>
146
+
147
+ # ifdef RUNTIME_OPENSSL
148
+ # include < dlfcn.h>
149
+
150
+ static struct OpenSSL {
151
+ OpenSSL ()
152
+ : m_loaded { true }
153
+ {
154
+ constexpr const char *names[] { " libcrypto.so.3" , " libcrypto.so.1.1" };
155
+
156
+ for (const char *name : names) {
157
+ if ((m_so = dlopen (name, RTLD_LAZY)))
158
+ return ;
159
+ }
160
+
161
+ m_loaded = false ;
162
+ }
163
+
164
+ ~OpenSSL ()
165
+ {
166
+ if (m_so)
167
+ dlclose (m_so);
168
+ }
169
+
170
+ bool isLoaded () const { return m_loaded; }
171
+
172
+ template <typename T> T get (const char *name)
173
+ {
174
+ const T func { m_so ? reinterpret_cast <T>(dlsym (m_so, name)) : nullptr };
175
+ if (!func)
176
+ m_loaded = false ;
177
+ return func;
178
+ }
179
+
180
+ private:
181
+ void *m_so;
182
+ bool m_loaded;
183
+ } g_openssl;
184
+
185
+ # define IMPORT_OPENSSL (func ) \
186
+ static auto _##func { g_openssl.get <decltype (&func)>(#func) };
187
+
188
+ IMPORT_OPENSSL (EVP_DigestFinal_ex);
189
+ # define EVP_DigestFinal_ex _EVP_DigestFinal_ex
190
+ IMPORT_OPENSSL (EVP_DigestInit_ex);
191
+ # define EVP_DigestInit_ex _EVP_DigestInit_ex
192
+ IMPORT_OPENSSL (EVP_DigestUpdate);
193
+ # define EVP_DigestUpdate _EVP_DigestUpdate
194
+ IMPORT_OPENSSL (EVP_MD_CTX_new);
195
+ # define EVP_MD_CTX_new _EVP_MD_CTX_new
196
+ IMPORT_OPENSSL (EVP_MD_CTX_free);
197
+ # define EVP_MD_CTX_free _EVP_MD_CTX_free
198
+ # ifdef EVP_MD_size // OpenSSL 3
199
+ IMPORT_OPENSSL (EVP_MD_get_size);
200
+ # undef EVP_MD_size
201
+ # define EVP_MD_size _EVP_MD_get_size
202
+ # else
203
+ IMPORT_OPENSSL (EVP_MD_size);
204
+ # define EVP_MD_size _EVP_MD_size
205
+ # endif
206
+ IMPORT_OPENSSL (EVP_sha256);
207
+ # define EVP_sha256 _EVP_sha256
208
+ # endif
209
+
210
+ class Hash ::EVPContext : public Hash::Context {
211
+ public:
212
+ static const EVP_MD *getAlgo (const Algorithm algo)
213
+ {
214
+ #ifdef RUNTIME_OPENSSL
215
+ if (!g_openssl.isLoaded ())
216
+ return nullptr ;
217
+ #endif
218
+
219
+ switch (algo) {
220
+ case SHA256:
221
+ return EVP_sha256 ();
222
+ default :
223
+ return nullptr ;
224
+ }
225
+ }
226
+
227
+ EVPContext (const EVP_MD *md)
228
+ : m_md { md }
229
+ {
230
+ m_ctx = EVP_MD_CTX_new ();
231
+ EVP_DigestInit_ex (m_ctx, m_md, nullptr );
232
+ }
233
+
234
+ ~EVPContext ()
235
+ {
236
+ EVP_MD_CTX_free (m_ctx);
237
+ }
238
+
239
+ size_t hashSize () const override
240
+ {
241
+ return EVP_MD_size (m_md);
242
+ }
243
+
244
+ void addData (const char *data, const size_t len) override
245
+ {
246
+ EVP_DigestUpdate (m_ctx, data, len);
247
+ }
248
+
249
+ void getHash (unsigned char *out) override
250
+ {
251
+ EVP_DigestFinal_ex (m_ctx, out, nullptr );
252
+ }
253
+
254
+ private:
255
+ EVP_MD_CTX *m_ctx;
256
+ const EVP_MD *m_md;
257
+ };
149
258
#endif
150
259
151
260
Hash::Hash (const Algorithm algo)
@@ -154,12 +263,15 @@ Hash::Hash(const Algorithm algo)
154
263
#ifdef _WIN32
155
264
if (const auto &algoProvider = CNGAlgorithmProvider::get (algo))
156
265
m_context = std::make_unique<CNGContext>(algoProvider);
157
- #else
266
+ #elif __APPLE__
158
267
switch (algo) {
159
268
case SHA256:
160
269
m_context = std::make_unique<SHA256Context>();
161
270
break ;
162
271
}
272
+ #else
273
+ if (const auto &algoDesc = EVPContext::getAlgo (algo))
274
+ m_context = std::make_unique<EVPContext>(algoDesc);
163
275
#endif
164
276
}
165
277
0 commit comments