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;
}

Reply via email to