summaryrefslogtreecommitdiffstats
path: root/Modules/sha1module.c
diff options
context:
space:
mode:
authorJonathan Protzenko <protz@microsoft.com>2023-02-22 21:18:43 (GMT)
committerGitHub <noreply@github.com>2023-02-22 21:18:43 (GMT)
commitfcadc7e405141847ab10daf5cff16be880083a24 (patch)
tree404c9bc7b90e95882765731171033632aa6c9b80 /Modules/sha1module.c
parent96bf24380e44dfa1516d65480250995e737c0cb9 (diff)
downloadcpython-fcadc7e405141847ab10daf5cff16be880083a24.zip
cpython-fcadc7e405141847ab10daf5cff16be880083a24.tar.gz
cpython-fcadc7e405141847ab10daf5cff16be880083a24.tar.bz2
gh-99108: Import MD5 and SHA1 from HACL* (#102089)
Replaces our fallback non-OpenSSL MD5 and SHA1 implementations with those from HACL* as we've already done with SHA2.
Diffstat (limited to 'Modules/sha1module.c')
-rw-r--r--Modules/sha1module.c282
1 files changed, 21 insertions, 261 deletions
diff --git a/Modules/sha1module.c b/Modules/sha1module.c
index 9153557..0f50d53 100644
--- a/Modules/sha1module.c
+++ b/Modules/sha1module.c
@@ -43,260 +43,16 @@ typedef long long SHA1_INT64; /* 64-bit integer */
#define SHA1_BLOCKSIZE 64
#define SHA1_DIGESTSIZE 20
-/* The structure for storing SHA1 info */
-
-struct sha1_state {
- SHA1_INT64 length;
- SHA1_INT32 state[5], curlen;
- unsigned char buf[SHA1_BLOCKSIZE];
-};
+#include "_hacl/Hacl_Hash_SHA1.h"
typedef struct {
PyObject_HEAD
- struct sha1_state hash_state;
+ Hacl_Streaming_SHA1_state *hash_state;
} SHA1object;
#include "clinic/sha1module.c.h"
-/* ------------------------------------------------------------------------
- *
- * This code for the SHA1 algorithm was noted as public domain. The
- * original headers are pasted below.
- *
- * Several changes have been made to make it more compatible with the
- * Python environment and desired interface.
- *
- */
-
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, https://www.libtom.net
- */
-
-/* rotate the hard way (platform optimizations could be done) */
-#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-
-/* Endian Neutral macros that work on all platforms */
-
-#define STORE32H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-
-/* SHA1 macros */
-
-#define F0(x,y,z) (z ^ (x & (y ^ z)))
-#define F1(x,y,z) (x ^ y ^ z)
-#define F2(x,y,z) ((x & y) | (z & (x | y)))
-#define F3(x,y,z) (x ^ y ^ z)
-
-static void sha1_compress(struct sha1_state *sha1, unsigned char *buf)
-{
- SHA1_INT32 a,b,c,d,e,W[80],i;
-
- /* copy the state into 512-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD32H(W[i], buf + (4*i));
- }
-
- /* copy state */
- a = sha1->state[0];
- b = sha1->state[1];
- c = sha1->state[2];
- d = sha1->state[3];
- e = sha1->state[4];
-
- /* expand it */
- for (i = 16; i < 80; i++) {
- W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
- }
-
- /* compress */
- /* round one */
- #define FF_0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
- #define FF_1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
- #define FF_2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
- #define FF_3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
-
- for (i = 0; i < 20; ) {
- FF_0(a,b,c,d,e,i++);
- FF_0(e,a,b,c,d,i++);
- FF_0(d,e,a,b,c,i++);
- FF_0(c,d,e,a,b,i++);
- FF_0(b,c,d,e,a,i++);
- }
-
- /* round two */
- for (; i < 40; ) {
- FF_1(a,b,c,d,e,i++);
- FF_1(e,a,b,c,d,i++);
- FF_1(d,e,a,b,c,i++);
- FF_1(c,d,e,a,b,i++);
- FF_1(b,c,d,e,a,i++);
- }
-
- /* round three */
- for (; i < 60; ) {
- FF_2(a,b,c,d,e,i++);
- FF_2(e,a,b,c,d,i++);
- FF_2(d,e,a,b,c,i++);
- FF_2(c,d,e,a,b,i++);
- FF_2(b,c,d,e,a,i++);
- }
-
- /* round four */
- for (; i < 80; ) {
- FF_3(a,b,c,d,e,i++);
- FF_3(e,a,b,c,d,i++);
- FF_3(d,e,a,b,c,i++);
- FF_3(c,d,e,a,b,i++);
- FF_3(b,c,d,e,a,i++);
- }
-
- #undef FF_0
- #undef FF_1
- #undef FF_2
- #undef FF_3
-
- /* store */
- sha1->state[0] = sha1->state[0] + a;
- sha1->state[1] = sha1->state[1] + b;
- sha1->state[2] = sha1->state[2] + c;
- sha1->state[3] = sha1->state[3] + d;
- sha1->state[4] = sha1->state[4] + e;
-}
-
-/**
- Initialize the hash state
- @param sha1 The hash state you wish to initialize
-*/
-static void
-sha1_init(struct sha1_state *sha1)
-{
- assert(sha1 != NULL);
- sha1->state[0] = 0x67452301UL;
- sha1->state[1] = 0xefcdab89UL;
- sha1->state[2] = 0x98badcfeUL;
- sha1->state[3] = 0x10325476UL;
- sha1->state[4] = 0xc3d2e1f0UL;
- sha1->curlen = 0;
- sha1->length = 0;
-}
-
-/**
- Process a block of memory though the hash
- @param sha1 The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
-*/
-static void
-sha1_process(struct sha1_state *sha1,
- const unsigned char *in, Py_ssize_t inlen)
-{
- Py_ssize_t n;
-
- assert(sha1 != NULL);
- assert(in != NULL);
- assert(sha1->curlen <= sizeof(sha1->buf));
-
- while (inlen > 0) {
- if (sha1->curlen == 0 && inlen >= SHA1_BLOCKSIZE) {
- sha1_compress(sha1, (unsigned char *)in);
- sha1->length += SHA1_BLOCKSIZE * 8;
- in += SHA1_BLOCKSIZE;
- inlen -= SHA1_BLOCKSIZE;
- } else {
- n = Py_MIN(inlen, (Py_ssize_t)(SHA1_BLOCKSIZE - sha1->curlen));
- memcpy(sha1->buf + sha1->curlen, in, (size_t)n);
- sha1->curlen += (SHA1_INT32)n;
- in += n;
- inlen -= n;
- if (sha1->curlen == SHA1_BLOCKSIZE) {
- sha1_compress(sha1, sha1->buf);
- sha1->length += 8*SHA1_BLOCKSIZE;
- sha1->curlen = 0;
- }
- }
- }
-}
-
-/**
- Terminate the hash to get the digest
- @param sha1 The hash state
- @param out [out] The destination of the hash (20 bytes)
-*/
-static void
-sha1_done(struct sha1_state *sha1, unsigned char *out)
-{
- int i;
-
- assert(sha1 != NULL);
- assert(out != NULL);
- assert(sha1->curlen < sizeof(sha1->buf));
-
- /* increase the length of the message */
- sha1->length += sha1->curlen * 8;
-
- /* append the '1' bit */
- sha1->buf[sha1->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (sha1->curlen > 56) {
- while (sha1->curlen < 64) {
- sha1->buf[sha1->curlen++] = (unsigned char)0;
- }
- sha1_compress(sha1, sha1->buf);
- sha1->curlen = 0;
- }
-
- /* pad up to 56 bytes of zeroes */
- while (sha1->curlen < 56) {
- sha1->buf[sha1->curlen++] = (unsigned char)0;
- }
-
- /* store length */
- STORE64H(sha1->length, sha1->buf+56);
- sha1_compress(sha1, sha1->buf);
-
- /* copy output */
- for (i = 0; i < 5; i++) {
- STORE32H(sha1->state[i], out+(4*i));
- }
-}
-
-
-/* .Source: /cvs/libtom/libtomcrypt/src/hashes/sha1.c,v $ */
-/* .Revision: 1.10 $ */
-/* .Date: 2007/05/12 14:25:28 $ */
-
-/*
- * End of copied SHA1 code.
- *
- * ------------------------------------------------------------------------
- */
typedef struct {
PyTypeObject* sha1_type;
@@ -328,8 +84,9 @@ SHA1_traverse(PyObject *ptr, visitproc visit, void *arg)
}
static void
-SHA1_dealloc(PyObject *ptr)
+SHA1_dealloc(SHA1object *ptr)
{
+ Hacl_Streaming_SHA1_legacy_free(ptr->hash_state);
PyTypeObject *tp = Py_TYPE(ptr);
PyObject_GC_UnTrack(ptr);
PyObject_GC_Del(ptr);
@@ -357,7 +114,7 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls)
if ((newobj = newSHA1object(st)) == NULL)
return NULL;
- newobj->hash_state = self->hash_state;
+ newobj->hash_state = Hacl_Streaming_SHA1_legacy_copy(self->hash_state);
return (PyObject *)newobj;
}
@@ -372,10 +129,7 @@ SHA1Type_digest_impl(SHA1object *self)
/*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- struct sha1_state temp;
-
- temp = self->hash_state;
- sha1_done(&temp, digest);
+ Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest);
return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE);
}
@@ -390,15 +144,21 @@ SHA1Type_hexdigest_impl(SHA1object *self)
/*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- struct sha1_state temp;
-
- /* Get the raw (binary) digest value */
- temp = self->hash_state;
- sha1_done(&temp, digest);
-
+ Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest);
return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE);
}
+static void update(Hacl_Streaming_SHA1_state *state, uint8_t *buf, Py_ssize_t len) {
+#if PY_SSIZE_T_MAX > UINT32_MAX
+ while (len > UINT32_MAX) {
+ Hacl_Streaming_SHA1_legacy_update(state, buf, UINT32_MAX);
+ len -= UINT32_MAX;
+ buf += UINT32_MAX;
+ }
+#endif
+ Hacl_Streaming_SHA1_legacy_update(state, buf, (uint32_t) len);
+}
+
/*[clinic input]
SHA1Type.update
@@ -416,7 +176,7 @@ SHA1Type_update(SHA1object *self, PyObject *obj)
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
- sha1_process(&self->hash_state, buf.buf, buf.len);
+ update(self->hash_state, buf.buf, buf.len);
PyBuffer_Release(&buf);
Py_RETURN_NONE;
@@ -509,7 +269,7 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity)
return NULL;
}
- sha1_init(&new->hash_state);
+ new->hash_state = Hacl_Streaming_SHA1_legacy_create_in();
if (PyErr_Occurred()) {
Py_DECREF(new);
@@ -518,7 +278,7 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity)
return NULL;
}
if (string) {
- sha1_process(&new->hash_state, buf.buf, buf.len);
+ update(new->hash_state, buf.buf, buf.len);
PyBuffer_Release(&buf);
}