Skip to content

Commit 0629750

Browse files
committed
implement hash information lookup
This commit implements the bits needed for finding static hash information data from an algorithm name. Search is case-insensitive and only algorithm names given as strings are supported.
1 parent de095ab commit 0629750

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

Modules/hmacmodule.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include "_hacl/Hacl_Streaming_HMAC.h" // Hacl_Agile_Hash_* identifiers
2323

24+
#include <stdbool.h>
25+
2426
// --- HMAC underlying hash function static information -----------------------
2527

2628
#define Py_hmac_hash_max_block_size 128
@@ -198,6 +200,94 @@ static const py_hmac_hinfo py_hmac_static_hinfo[] = {
198200
},
199201
};
200202

203+
static inline bool
204+
find_hash_info_by_utf8name(hmacmodule_state *state,
205+
const char *name,
206+
const py_hmac_hinfo **info)
207+
{
208+
assert(name != NULL);
209+
*info = _Py_hashtable_get(state->hinfo_table, name);
210+
return *info != NULL;
211+
}
212+
213+
static int
214+
find_hash_info_by_name(hmacmodule_state *state,
215+
PyObject *name,
216+
const py_hmac_hinfo **info)
217+
{
218+
const char *utf8name = PyUnicode_AsUTF8(name);
219+
if (utf8name == NULL) {
220+
goto error;
221+
}
222+
if (find_hash_info_by_utf8name(state, utf8name, info)) {
223+
return 1;
224+
}
225+
226+
// try to find an alternative using the lowercase name
227+
PyObject *lower = PyObject_CallMethodNoArgs(name, state->str_lower);
228+
if (lower == NULL) {
229+
goto error;
230+
}
231+
const char *utf8lower = PyUnicode_AsUTF8(lower);
232+
if (utf8lower == NULL) {
233+
Py_DECREF(lower);
234+
goto error;
235+
}
236+
int found = find_hash_info_by_utf8name(state, utf8lower, info);
237+
Py_DECREF(lower);
238+
return found;
239+
240+
error:
241+
*info = NULL;
242+
return -1;
243+
}
244+
245+
/*
246+
* Find the corresponding HMAC hash function static information.
247+
*
248+
* If an error occurs or if nothing can be found, this
249+
* returns -1 or 0 respectively, and sets 'info' to NULL.
250+
* Otherwise, this returns 1 and stores the result in 'info'.
251+
*
252+
* Parameters
253+
*
254+
* state The HMAC module state.
255+
* hash_info_ref An input to hashlib.new().
256+
* info The deduced information, if any.
257+
*/
258+
static int
259+
find_hash_info_impl(hmacmodule_state *state,
260+
PyObject *hash_info_ref,
261+
const py_hmac_hinfo **info)
262+
{
263+
if (PyUnicode_Check(hash_info_ref)) {
264+
return find_hash_info_by_name(state, hash_info_ref, info);
265+
}
266+
// NOTE(picnixz): For now, we only support named algorithms.
267+
// In the future, we need to decide whether 'hashlib.openssl_md5'
268+
// would make sense as an alias to 'md5' and how to remove OpenSSL.
269+
*info = NULL;
270+
return 0;
271+
}
272+
273+
static const py_hmac_hinfo *
274+
find_hash_info(hmacmodule_state *state, PyObject *hash_info_ref)
275+
{
276+
const py_hmac_hinfo *info = NULL;
277+
int rc = find_hash_info_impl(state, hash_info_ref, &info);
278+
// The code below could be simplfied with only 'rc == 0' case,
279+
// but we are deliberately verbose to ease future improvements.
280+
if (rc < 0) {
281+
return NULL;
282+
}
283+
if (rc == 0) {
284+
PyErr_Format(state->unknown_hash_error,
285+
"unsupported hash type: %R", hash_info_ref);
286+
return NULL;
287+
}
288+
return info;
289+
}
290+
201291
// --- HMAC module methods ----------------------------------------------------
202292

203293
static PyMethodDef hmacmodule_methods[] = {

0 commit comments

Comments
 (0)