summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-08-19 19:21:29 -0400
committerNick Mathewson <nickm@torproject.org>2009-08-19 19:43:54 -0400
commitf57883a39e09e16f495a6b8706ca0d3b3a8df2a4 (patch)
treeccb95523a00311bd2b98bcb42253232401c252f7
parentb9e45cc508b6fbf596e1ba40761e11d0629a3291 (diff)
downloadtor-f57883a39e09e16f495a6b8706ca0d3b3a8df2a4.tar.gz
tor-f57883a39e09e16f495a6b8706ca0d3b3a8df2a4.zip
Add basic support for SHA256.
This adds an openssl 0.9.8 dependency. Let's see if anybody cares.
-rw-r--r--src/common/crypto.c71
-rw-r--r--src/common/crypto.h20
-rw-r--r--src/or/test.c32
3 files changed, 106 insertions, 17 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 57c636db68..51d4059f3e 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -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));
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index fa6735d788..515b870f3d 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -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);
diff --git a/src/or/test.c b/src/or/test.c
index b86ced723a..db4b6784f4 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -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)