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