This is a multi-part message in MIME format.
--------------030802070700080608080804
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hello,

We need to calculate SHA1 over a large sequence of messages. Related
messages can arrive with huge intervals (hours, days worst case),
including across program shutdown, and we can not keep old messages
around to do the SHA1 all at once.

Our situation requires the ability to save the state of a SHA1
calculation in progress to a file or database, and reload it later to
contiue with it.

Attached to this email is a patch against 0.9.8e that adds this ability
to OpenSSL.
cd openssl-0.9.8.e/crypto
patch -p0
Use example:
SHA1_Init();
SHA1_Update();
SHA1_Save_State(VERSION_DONT_CARE);
SHA1_Drop(); // Application must call this if it doesn't do
SHA1_Final on a context
...
anything, including program shutdown
...
SHA1_Load_State();
SHA1_Update();
SHA1_Final();

We think that some other users may encounter a situation similar to
ours, and we therefore submit this patch for inclusion.

If the patch is not rejected outright, I am willing to modify the patch
to make it eligible for inclusion. E.g. add the documentation, any
cleanups, etc.

Regards,
Nanno


--------------030802070700080608080804
Content-Type: text/x-patch;
name="openssl-sha-save-v1.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="openssl-sha-save-v1.patch"

diff -Nru ../../openssl-0.9.8e/crypto/sha/sha.h sha/sha.h
--- ../../openssl-0.9.8e/crypto/sha/sha.h 2006-12-22 17:04:56.000000000 +0100
+++ sha/sha.h 2007-06-08 01:47:07.203240896 +0200
@@ -97,6 +97,9 @@
#define SHA_LAST_BLOCK (SHA_CBLOCK-8)
#define SHA_DIGEST_LENGTH 20

+#define SHA_STATE_VERSION_DONT_CARE 0
+#define SHA_STATE_VERSION_1 1
+
typedef struct SHAstate_st
{
SHA_LONG h0,h1,h2,h3,h4;
@@ -118,6 +121,9 @@
int SHA1_Final(unsigned char *md, SHA_CTX *c);
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
+void SHA1_Save_State(SHA_CTX *c, unsigned char **data, unsigned int *len, int requested_version);
+int SHA1_Load_State(SHA_CTX *c, unsigned char *data, unsigned int len);
+void SHA1_Drop(SHA_CTX *c);
#endif

#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a
diff -Nru ../../openssl-0.9.8e/crypto/sha/sha_locl.h sha/sha_locl.h
--- ../../openssl-0.9.8e/crypto/sha/sha_locl.h 2005-07-20 01:10:04.000000000 +0200
+++ sha/sha_locl.h 2007-06-08 02:36:44.043692360 +0200
@@ -58,6 +58,8 @@

#include
#include
+#include // For uint32_t
+#include // For htonl/ntohl

#include
#include
@@ -603,3 +605,93 @@
#endif

#endif
+
+
+#if defined(SHA_1)
+#define memcat_htobe32(dst, src) { *(uint32_t*)(dst) = htonl(src); (dst) += sizeof(uint32_t); }
+#define memget_betoh32(dst, src) { (dst) = ntohl( *((uint32_t*)(src)) ); (src) += sizeof(uint32_t); }
+
+#define SHA_STATE_V1_SIZE ((1 + 5 + 2 + SHA_LBLOCK + 1) * sizeof(uint32_t))
+
+void SHA1_Save_State (SHA_CTX *c, unsigned char **data, unsigned int *len, int requested_version)
+ {
+ unsigned char *p;
+ int i;
+
+ switch (requested_version)
+ {
+ case SHA_STATE_VERSION_DONT_CARE:
+ requested_version = SHA_STATE_VERSION_1;
+ break;
+ case SHA_STATE_VERSION_1:
+ break;
+ default:
+ *data = NULL;
+ return;
+ }
+
+ *len = SHA_STATE_V1_SIZE;
+ *data = malloc(*len);
+ if (*data == NULL) {
+ return;
+ }
+
+ p = *data;
+
+ memcat_htobe32(p, requested_version);
+
+ memcat_htobe32(p, c->h0);
+ memcat_htobe32(p, c->h1);
+ memcat_htobe32(p, c->h2);
+ memcat_htobe32(p, c->h3);
+ memcat_htobe32(p, c->h4);
+
+ memcat_htobe32(p, c->Nl);
+ memcat_htobe32(p, c->Nh);
+
+ for (i=0; i + {
+ memcat_htobe32(p, c->data[i]);
+ }
+
+ memcat_htobe32(p, c->num);
+ }
+
+int SHA1_Load_State (SHA_CTX *c, unsigned char *data, unsigned int len)
+ {
+ int version, i;
+
+ if (len < sizeof(uint32_t))
+ return -1;
+
+ memget_betoh32(version, data);
+ if (version != SHA_STATE_VERSION_1)
+ return -2;
+ if (len < SHA_STATE_V1_SIZE)
+ return -3;
+
+ memget_betoh32(c->h0, data);
+ memget_betoh32(c->h1, data);
+ memget_betoh32(c->h2, data);
+ memget_betoh32(c->h3, data);
+ memget_betoh32(c->h4, data);
+
+ memget_betoh32(c->Nl, data);
+ memget_betoh32(c->Nh, data);
+
+ for (i=0; i + {
+ memget_betoh32(c->data[i], data);
+ }
+
+ memget_betoh32(c->num, data);
+
+ return 1;
+ }
+
+void SHA1_Drop (SHA_CTX *c)
+ {
+ // There is no dynamically allocated memory to clean up.
+ }
+#endif
+

--------------030802070700080608080804
Content-Type: text/x-csrc;
name="test-save.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="test-save.c"

#include
#include
#include
#include

int main()
{
SHA_CTX a, b;
uint8_t digest_a[SHA_DIGEST_LENGTH], digest_b[SHA_DIGEST_LENGTH];
uint8_t data[67];
bool equal;
unsigned char *state;
unsigned int state_len;
int i, cut, ret;

equal = true;

for (i=0; i data[i] = i;

for (cut=0; cut SHA1_Init(&a);
memset(&b, 0, sizeof(b));

for (i=0; i if (i == cut) {
SHA1_Save_State(&a, &state, &state_len, SHA_STATE_VERSION_DONT_CARE);
if (state == NULL) {
printf("Error!\n");
return 1;
}

ret = SHA1_Load_State(&b, state, state_len);
if (ret != 1) {
printf("Error!\n");
return 1;
}
}

SHA1_Update(&a, data, i);
if (i >= cut)
SHA1_Update(&b, data, i);
}

SHA1_Final(digest_a, &a);
SHA1_Final(digest_b, &b);

if (memcmp(digest_a, digest_b, SHA_DIGEST_LENGTH) != 0)
equal = false;
}

if ( ! equal)
printf("not ");
printf("equal!\n");

return 0;
}

--------------030802070700080608080804--

__________________________________________________ ____________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majordomo@openssl.org