mirror of
https://github.com/python/cpython
synced 2026-09-28 07:18:17 +03:00
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.
This commit is contained in:
parent
96bf24380e
commit
fcadc7e405
24 changed files with 2498 additions and 699 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue