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

v2 of the SHA save patch.

Now against the top level of the source tree.

* Now lets user alloc the buffer.
* '_Default_Version()' call added.
* Man page documentation added.


Nanno


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

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

+#define SHA_STATE_VERSION_1 1
+
typedef struct SHAstate_st
{
SHA_LONG h0,h1,h2,h3,h4;
@@ -118,6 +120,11 @@
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);
+int SHA1_State_Default_Version();
+unsigned int SHA1_State_Size(SHA_CTX *c, int requested_version);
+int SHA1_Save_State(SHA_CTX *c, unsigned char *data, int requested_version);
+int SHA1_Load_State(SHA_CTX *c, unsigned char *data, unsigned int length);
+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 crypto/sha/sha_locl.h
--- ../openssl-0.9.8e/crypto/sha/sha_locl.h 2005-07-20 01:10:04.000000000 +0200
+++ crypto/sha/sha_locl.h 2007-06-12 16:35:08.934751528 +0200
@@ -58,6 +58,8 @@

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

#include
#include
@@ -603,3 +605,101 @@
#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))
+
+int SHA1_State_Default_Version()
+ {
+ return SHA_STATE_VERSION_1;
+ }
+
+unsigned int SHA1_State_Size(SHA_CTX *c, int requested_version)
+ {
+ switch (requested_version)
+ {
+ case SHA_STATE_VERSION_1:
+ return SHA_STATE_V1_SIZE;
+ }
+
+ return 0;
+ }
+
+int SHA1_Save_State (SHA_CTX *c, unsigned char *data, int requested_version)
+ {
+ unsigned char *p;
+ int i;
+
+ switch (requested_version)
+ {
+ case SHA_STATE_VERSION_1:
+ break;
+ default:
+ return 0;
+ }
+
+ 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);
+
+ return 1;
+ }
+
+int SHA1_Load_State (SHA_CTX *c, unsigned char *data, unsigned int length)
+ {
+ int version, i;
+
+ if (length < sizeof(uint32_t))
+ return 0;
+
+ memget_betoh32(version, data);
+ if (version != SHA_STATE_VERSION_1)
+ return 0;
+ if (length < SHA_STATE_V1_SIZE)
+ return 0;
+
+ 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
+
diff -Nru ../openssl-0.9.8e/doc/crypto/sha.pod doc/crypto/sha.pod
--- ../openssl-0.9.8e/doc/crypto/sha.pod 2006-10-27 23:59:48.000000000 +0200
+++ doc/crypto/sha.pod 2007-06-12 16:45:28.459569440 +0200
@@ -9,13 +9,19 @@
#include

unsigned char *SHA1(const unsigned char *d, unsigned long n,
- unsigned char *md);
+ unsigned char *md);

int SHA1_Init(SHA_CTX *c);
int SHA1_Update(SHA_CTX *c, const void *data,
unsigned long len);
int SHA1_Final(unsigned char *md, SHA_CTX *c);

+ unsigned int SHA1_Save_State(SHA_CTX *c, unsigned char *data,
+ int requested_version);
+ void SHA1_Drop(SHA_CTX *c);
+ int SHA1_Load_State(SHA_CTX *c, unsigned char *data, unsigned int length);
+ int SHA1_State_Default_Version();
+
=head1 DESCRIPTION

SHA-1 (Secure Hash Algorithm) is a cryptographic hash function with a
@@ -37,6 +43,19 @@
SHA1_Final() places the message digest in B, which must have space
for SHA_DIGEST_LENGTH == 20 bytes of output, and erases the B.

+SHA1_Save_State() writes the internal state of a B to buffer B.
+SHA1_State_Size() returns the required size of the buffer.
+SHA1_State_Default_Version() returns the normal value for
+B. However, specific values of B can
+be used if required to get backward compatibility with a specific older
+version of OpenSSL.
+
+SHA1_Drop() cleans up the B. An application must call either
+SHA1_Final() or SHA1_Drop() (not both).
+
+SHA1_Load_State() restores internal state saved earlier with SHA1_Save_State().
+An application must call either SHA1_Init() or SHA1_Load_State() (not both).
+
Applications should use the higher level functions
L
etc. instead of calling the hash functions directly.
@@ -44,11 +63,35 @@
The predecessor of SHA-1, SHA, is also implemented, but it should be
used only when backward compatibility is required.

+=head1 EXAMPLES
+
+Save state and load it later:
+
+ SHA1_Init(&a);
+ SHA1_Update(&a);
+ ...
+ state_len = SHA1_State_Size(&a, SHA1_State_Default_Version());
+ if ((state = malloc(state_len)) == NULL)
+ // error
+ if ( ! SHA1_Save_State(&a, state, SHA1_State_Default_Version()))
+ // error
+ SHA1_Drop(&a);
+ ...
+ if ( ! SHA1_Load_State(&b, state, state_len))
+ // error
+ free(state);
+
+ SHA1_Update(&b);
+ SHA1_Final(digest, &b);
+
=head1 RETURN VALUES

SHA1() returns a pointer to the hash value.

-SHA1_Init(), SHA1_Update() and SHA1_Final() return 1 for success, 0 otherwise.
+SHA1_Init(), SHA1_Update(), SHA1_Final(), SHA1_Save_State() and SHA1_Load_State()
+return 1 for success, 0 otherwise.
+
+SHA1_State_Size() returns 0 for error, the required buffer size otherwise.

=head1 CONFORMING TO


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

#include
#include
#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, ret;

equal = true;

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

SHA1_Init(&a);
SHA1_Init(&b);

for (i=0; i state_len = SHA1_State_Size(&b, SHA1_State_Default_Version());
state = malloc(state_len);
if (state == NULL) {
printf("Error!\n");
return 1;
}
ret = SHA1_Save_State(&b, state, SHA1_State_Default_Version());
if (ret != 1) {
printf("Error!\n");
return 1;
}
SHA1_Drop(&b);

memset(&b, 0, sizeof(b));

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

free(state);

SHA1_Update(&a, data, i);
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;
}

--------------010504080202020404000108--

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