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
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 <stdlib.h>
#include <string.h>
+#include <stdint.h> // For uint32_t
+#include <netinet/in.h> // For htonl/ntohl
#include <openssl/opensslconf.h>
#include <openssl/sha.h>
@@ -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<SHA_LBLOCK; 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<SHA_LBLOCK; 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 <openssl/sha.h>
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<md>, which must have space
for SHA_DIGEST_LENGTH == 20 bytes of output, and erases the B<SHA_CTX>.
+SHA1_Save_State() writes the internal state of a B<SHA_CTX> to buffer B<data>.
+SHA1_State_Size() returns the required size of the buffer.
+SHA1_State_Default_Version() returns the normal value for
+B<required_version>. However, specific values of B<SHA_STATE_VERSION_*> can
+be used if required to get backward compatibility with a specific older
+version of OpenSSL.
+
+SHA1_Drop() cleans up the B<SHA_CTX>. 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<EVP_DigestInit(3)|EVP_DigestInit(3)>
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <openssl/sha.h>
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<sizeof(data); i++)
data[i] = i;
SHA1_Init(&a);
SHA1_Init(&b);
for (i=0; i<sizeof(data); 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;
}