[or-cvs] [tor/master] Add basic support for SHA256.

Nick Mathewson nickm at seul.org
Wed Aug 19 23:43:53 UTC 2009


Author: Nick Mathewson <nickm at torproject.org>
Date: Wed, 19 Aug 2009 19:21:29 -0400
Subject: Add basic support for SHA256.
Commit: f57883a39e09e16f495a6b8706ca0d3b3a8df2a4

This adds an openssl 0.9.8 dependency.  Let's see if anybody cares.
---
 src/common/crypto.c |   71 ++++++++++++++++++++++++++++++++++++++++++--------
 src/common/crypto.h |   20 +++++++++++++-
 src/or/test.c       |   32 +++++++++++++++++++++--
 3 files changed, 106 insertions(+), 17 deletions(-)

diff --git a/src/common/crypto.c b/src/common/crypto.c
index 57c636d..51d4059 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 fa6735d..515b870 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 b86ced7..db4b678 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)
-- 
1.5.6.5



More information about the tor-commits mailing list