Add basic support for SHA256.

This adds an openssl 0.9.8 dependency.  Let's see if anybody cares.
This commit is contained in:
Nick Mathewson 2009-08-19 19:21:29 -04:00
parent b9e45cc508
commit f57883a39e
3 changed files with 106 additions and 17 deletions

View File

@ -1394,9 +1394,23 @@ crypto_digest(char *digest, const char *m, size_t len)
return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
}
int
crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm)
{
tor_assert(m);
tor_assert(digest);
tor_assert(algorithm == DIGEST_SHA256);
return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
}
/** Intermediate information about the digest of a stream of data. */
struct crypto_digest_env_t {
SHA_CTX d;
union {
SHA_CTX sha1;
SHA256_CTX sha2;
} d;
digest_algorithm_t algorithm : 8;
};
/** Allocate and return a new digest object.
@ -1406,7 +1420,19 @@ crypto_new_digest_env(void)
{
crypto_digest_env_t *r;
r = tor_malloc(sizeof(crypto_digest_env_t));
SHA1_Init(&r->d);
SHA1_Init(&r->d.sha1);
r->algorithm = DIGEST_SHA1;
return r;
}
crypto_digest_env_t *
crypto_new_digest256_env(digest_algorithm_t algorithm)
{
crypto_digest_env_t *r;
tor_assert(algorithm == DIGEST_SHA256);
r = tor_malloc(sizeof(crypto_digest_env_t));
SHA256_Init(&r->d.sha2);
r->algorithm = algorithm;
return r;
}
@ -1427,30 +1453,51 @@ crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
{
tor_assert(digest);
tor_assert(data);
/* Using the SHA1_*() calls directly means we don't support doing
* SHA1 in hardware. But so far the delay of getting the question
/* Using the SHA*_*() calls directly means we don't support doing
* SHA in hardware. But so far the delay of getting the question
* to the hardware, and hearing the answer, is likely higher than
* just doing it ourselves. Hashes are fast.
*/
SHA1_Update(&digest->d, (void*)data, len);
switch (digest->algorithm) {
case DIGEST_SHA1:
SHA1_Update(&digest->d.sha1, (void*)data, len);
break;
case DIGEST_SHA256:
SHA256_Update(&digest->d.sha2, (void*)data, len);
break;
default:
tor_fragile_assert();
break;
}
}
/** Compute the hash of the data that has been passed to the digest
* object; write the first out_len bytes of the result to <b>out</b>.
* <b>out_len</b> must be \<= DIGEST_LEN.
* <b>out_len</b> must be \<= DIGEST256_LEN.
*/
void
crypto_digest_get_digest(crypto_digest_env_t *digest,
char *out, size_t out_len)
{
unsigned char r[DIGEST_LEN];
SHA_CTX tmpctx;
unsigned char r[DIGEST256_LEN];
crypto_digest_env_t tmpenv;
tor_assert(digest);
tor_assert(out);
tor_assert(out_len <= DIGEST_LEN);
/* memcpy into a temporary ctx, since SHA1_Final clears the context */
memcpy(&tmpctx, &digest->d, sizeof(SHA_CTX));
SHA1_Final(r, &tmpctx);
/* memcpy into a temporary ctx, since SHA*_Final clears the context */
memcpy(&tmpenv, digest, sizeof(crypto_digest_env_t));
switch (digest->algorithm) {
case DIGEST_SHA1:
tor_assert(out_len <= DIGEST_LEN);
SHA1_Final(r, &digest->d.sha1);
break;
case DIGEST_SHA256:
tor_assert(out_len <= DIGEST256_LEN);
SHA256_Final(r, &digest->d.sha2);
break;
default:
tor_fragile_assert();
break;
}
memcpy(out, r, out_len);
memset(r, 0, sizeof(r));
}

View File

@ -18,6 +18,9 @@
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
* this is just sha256, but any it can be any other 256-byte digest). */
#define DIGEST256_LEN 32
/** Length of our symmetric cipher's keys. */
#define CIPHER_KEY_LEN 16
/** Length of our symmetric cipher's IV. */
@ -27,9 +30,12 @@
/** Length of our DH keys. */
#define DH_BYTES (1024/8)
/** Length of a message digest when encoded in base64 with trailing = signs
* removed. */
/** Length of a sha1 message digest when encoded in base64 with trailing =
* signs removed. */
#define BASE64_DIGEST_LEN 27
/** Length of a sha256 message digest when encoded in base64 with trailing =
* signs removed. */
#define BASE64_DIGEST256_LEN 43
/** Constants used to indicate no padding for public-key encryption */
#define PK_NO_PADDING 60000
@ -48,6 +54,13 @@
#define FINGERPRINT_LEN 49
/** Length of hex encoding of SHA1 digest, not including final NUL. */
#define HEX_DIGEST_LEN 40
/** Length of hex encoding of SHA256 digest, not including final NUL. */
#define HEX_DIGEST256_LEN 64
typedef enum {
DIGEST_SHA1,
DIGEST_SHA256,
} digest_algorithm_t;
typedef struct crypto_pk_env_t crypto_pk_env_t;
typedef struct crypto_cipher_env_t crypto_cipher_env_t;
@ -145,7 +158,10 @@ int crypto_cipher_decrypt_with_iv(crypto_cipher_env_t *env,
/* SHA-1 */
int crypto_digest(char *digest, const char *m, size_t len);
int crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm);
crypto_digest_env_t *crypto_new_digest_env(void);
crypto_digest_env_t *crypto_new_digest256_env(digest_algorithm_t algorithm);
void crypto_free_digest_env(crypto_digest_env_t *digest);
void crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
size_t len);

View File

@ -618,14 +618,19 @@ test_crypto_sha(void)
crypto_digest_env_t *d1 = NULL, *d2 = NULL;
int i;
char key[80];
char digest[20];
char digest[32];
char data[50];
char d_out1[DIGEST_LEN], d_out2[DIGEST_LEN];
char d_out1[DIGEST_LEN], d_out2[DIGEST256_LEN];
/* Test SHA-1 with a test vector from the specification. */
i = crypto_digest(data, "abc", 3);
test_memeq_hex(data, "A9993E364706816ABA3E25717850C26C9CD0D89D");
/* Test SHA-256 with a test vector from the specification. */
i = crypto_digest256(data, "abc", 3, DIGEST_SHA256);
test_memeq_hex(data, "BA7816BF8F01CFEA414140DE5DAE2223B00361A3"
"96177A9CB410FF61F20015AD");
/* Test HMAC-SHA-1 with test cases from RFC2202. */
/* Case 1. */
@ -646,7 +651,7 @@ test_crypto_sha(void)
test_streq(hex_str(digest, 20),
"4C9007F4026250C6BC8414F9BF50C86C2D7235DA");
/* Case . */
/* Case 5. */
memset(key, 0xaa, 80);
crypto_hmac_sha1(digest, key, 80,
"Test Using Larger Than Block-Size Key - Hash Key First",
@ -672,6 +677,27 @@ test_crypto_sha(void)
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdef", 6);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_free_digest_env(d1);
crypto_free_digest_env(d2);
/* Incremental digest code with sha256 */
d1 = crypto_new_digest256_env(DIGEST_SHA256);
test_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
test_assert(d2);
crypto_digest_add_bytes(d2, "ghijkl", 6);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefghijkl", 12, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_assign(d2, d1);
crypto_digest_add_bytes(d2, "mno", 3);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefmno", 9, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
done:
if (d1)