[tor-commits] [tor/master] add SHA512 support to crypto

nickm at torproject.org nickm at torproject.org
Wed Nov 25 14:04:21 UTC 2015


commit ff54cc8481f88ecbc40a8abc0a1812fcf583ea73
Author: George Tankersley <george.tankersley at gmail.com>
Date:   Wed Nov 18 08:37:05 2015 +0000

    add SHA512 support to crypto
---
 src/common/crypto.c    |   67 ++++++++++++++++++++++++++++++++++++++++++------
 src/common/crypto.h    |   19 +++++++++++---
 src/test/test_crypto.c |   28 ++++++++++++++++++++
 3 files changed, 102 insertions(+), 12 deletions(-)

diff --git a/src/common/crypto.c b/src/common/crypto.c
index ffbeb81..161ea37 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1609,6 +1609,19 @@ crypto_digest256(char *digest, const char *m, size_t len,
   return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
 }
 
+/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
+ * using the algorithm <b>algorithm</b>.  Write the DIGEST_LEN512-byte result
+ * into <b>digest</b>.  Return 0 on success, -1 on failure. */
+int
+crypto_digest512(char *digest, const char *m, size_t len,
+                 digest_algorithm_t algorithm)
+{
+  tor_assert(m);
+  tor_assert(digest);
+  tor_assert(algorithm == DIGEST_SHA512);
+  return (SHA512((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
+}
+
 /** Set the digests_t in <b>ds_out</b> to contain every digest on the
  * <b>len</b> bytes in <b>m</b> that we know how to compute.  Return 0 on
  * success, -1 on failure. */
@@ -1621,8 +1634,18 @@ crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
   if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
     return -1;
   for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) {
-    if (crypto_digest256(ds_out->d[i], m, len, i) < 0)
-      return -1;
+      switch (i) {
+        case DIGEST_SHA256:
+          if (crypto_digest256(ds_out->d[i], m, len, i) < 0)
+            return -1;
+          break;
+        case DIGEST_SHA512:
+          if (crypto_digest512(ds_out->d[i], m, len, i) < 0)
+            return -1;
+          break;
+        default:
+          return -1;
+      }
   }
   return 0;
 }
@@ -1636,6 +1659,8 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg)
       return "sha1";
     case DIGEST_SHA256:
       return "sha256";
+    case DIGEST_SHA512:
+      return "sha512";
     default:
       tor_fragile_assert();
       return "??unknown_digest??";
@@ -1651,6 +1676,8 @@ crypto_digest_algorithm_parse_name(const char *name)
     return DIGEST_SHA1;
   else if (!strcmp(name, "sha256"))
     return DIGEST_SHA256;
+  else if (!strcmp(name, "sha512"))
+    return DIGEST_SHA512;
   else
     return -1;
 }
@@ -1660,6 +1687,7 @@ struct crypto_digest_t {
   union {
     SHA_CTX sha1; /**< state for SHA1 */
     SHA256_CTX sha2; /**< state for SHA256 */
+    SHA512_CTX sha512; /**< state for SHA512 */
   } d; /**< State for the digest we're using.  Only one member of the
         * union is usable, depending on the value of <b>algorithm</b>. */
   digest_algorithm_bitfield_t algorithm : 8; /**< Which algorithm is in use? */
@@ -1690,6 +1718,19 @@ crypto_digest256_new(digest_algorithm_t algorithm)
   return r;
 }
 
+/** Allocate and return a new digest object to compute 512-bit digests
+ * using <b>algorithm</b>. */
+crypto_digest_t *
+crypto_digest512_new(digest_algorithm_t algorithm)
+{
+  crypto_digest_t *r;
+  tor_assert(algorithm == DIGEST_SHA512);
+  r = tor_malloc(sizeof(crypto_digest_t));
+  SHA512_Init(&r->d.sha512);
+  r->algorithm = algorithm;
+  return r;
+}
+
 /** Deallocate a digest object.
  */
 void
@@ -1721,6 +1762,9 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
     case DIGEST_SHA256:
       SHA256_Update(&digest->d.sha2, (void*)data, len);
       break;
+    case DIGEST_SHA512:
+      SHA512_Update(&digest->d.sha512, (void*)data, len);
+      break;
     default:
       tor_fragile_assert();
       break;
@@ -1729,13 +1773,13 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
 
 /** 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 \<= DIGEST256_LEN.
+ * <b>out_len</b> must be \<= DIGEST512_LEN.
  */
 void
 crypto_digest_get_digest(crypto_digest_t *digest,
                          char *out, size_t out_len)
 {
-  unsigned char r[DIGEST256_LEN];
+  unsigned char r[DIGEST512_LEN];
   crypto_digest_t tmpenv;
   tor_assert(digest);
   tor_assert(out);
@@ -1750,6 +1794,10 @@ crypto_digest_get_digest(crypto_digest_t *digest,
       tor_assert(out_len <= DIGEST256_LEN);
       SHA256_Final(r, &tmpenv.d.sha2);
       break;
+    case DIGEST_SHA512:
+      tor_assert(out_len <= DIGEST512_LEN);
+      SHA512_Final(r, &tmpenv.d.sha512);
+      break;
     default:
       log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm);
       /* If fragile_assert is not enabled, then we should at least not
@@ -1791,7 +1839,7 @@ crypto_digest_assign(crypto_digest_t *into,
  * at <b>digest_out</b> to the hash of the concatenation of those strings,
  * plus the optional string <b>append</b>, computed with the algorithm
  * <b>alg</b>.
- * <b>out_len</b> must be \<= DIGEST256_LEN. */
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
 void
 crypto_digest_smartlist(char *digest_out, size_t len_out,
                         const smartlist_t *lst,
@@ -1806,7 +1854,7 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
  * optional string <b>prepend</b>, those strings,
  * and the optional string <b>append</b>, computed with the algorithm
  * <b>alg</b>.
- * <b>out_len</b> must be \<= DIGEST256_LEN. */
+ * <b>out_len</b> must be \<= DIGEST512_LEN. */
 void
 crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
                         const char *prepend,
@@ -1815,10 +1863,13 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
                         digest_algorithm_t alg)
 {
   crypto_digest_t *d;
-  if (alg == DIGEST_SHA1)
+  if (alg == DIGEST_SHA1) {
     d = crypto_digest_new();
-  else
+  } else if (alg == DIGEST_SHA512) {
+    d = crypto_digest512_new(alg);
+  } else {
     d = crypto_digest256_new(alg);
+  }
   if (prepend)
     crypto_digest_add_bytes(d, prepend, strlen(prepend));
   SMARTLIST_FOREACH(lst, const char *, cp,
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 96e202d..4d231d8 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -54,6 +54,8 @@
 /** Length of the output of our second (improved) message digests.  (For now
  * this is just sha256, but it could be any other 256-bit digest.) */
 #define DIGEST256_LEN 32
+/** Length of the output of our 64-bit optimized message digests (SHA512). */
+#define DIGEST512_LEN 64
 /** Length of our symmetric cipher's keys. */
 #define CIPHER_KEY_LEN 16
 /** Length of our symmetric cipher's IV. */
@@ -69,6 +71,9 @@
 /** Length of a sha256 message digest when encoded in base64 with trailing =
  * signs removed. */
 #define BASE64_DIGEST256_LEN 43
+/** Length of a sha512 message digest when encoded in base64 with trailing =
+ * signs removed. */
+#define BASE64_DIGEST512_LEN 86
 
 /** Constant used to indicate OAEP padding for public-key encryption */
 #define PK_PKCS1_OAEP_PADDING 60002
@@ -83,24 +88,27 @@
 #define HEX_DIGEST_LEN 40
 /** Length of hex encoding of SHA256 digest, not including final NUL. */
 #define HEX_DIGEST256_LEN 64
+/** Length of hex encoding of SHA512 digest, not including final NUL. */
+#define HEX_DIGEST512_LEN 128
 
 typedef enum {
   DIGEST_SHA1 = 0,
   DIGEST_SHA256 = 1,
+  DIGEST_SHA512 = 2,
 } digest_algorithm_t;
-#define  N_DIGEST_ALGORITHMS (DIGEST_SHA256+1)
+#define  N_DIGEST_ALGORITHMS (DIGEST_SHA512+1)
 #define digest_algorithm_bitfield_t ENUM_BF(digest_algorithm_t)
 
 /** A set of all the digests we know how to compute, taken on a single
- * string.  Any digests that are shorter than 256 bits are right-padded
+ * string.  Any digests that are shorter than 512 bits are right-padded
  * with 0 bits.
  *
- * Note that this representation wastes 12 bytes for the SHA1 case, so
+ * Note that this representation wastes 44 bytes for the SHA1 case, so
  * don't use it for anything where we need to allocate a whole bunch at
  * once.
  **/
 typedef struct {
-  char d[N_DIGEST_ALGORITHMS][DIGEST256_LEN];
+  char d[N_DIGEST_ALGORITHMS][DIGEST512_LEN];
 } digests_t;
 
 typedef struct crypto_pk_t crypto_pk_t;
@@ -207,6 +215,8 @@ int crypto_cipher_decrypt_with_iv(const char *key,
 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);
+int crypto_digest512(char *digest, const char *m, size_t len,
+                     digest_algorithm_t algorithm);
 int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
 struct smartlist_t;
 void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
@@ -221,6 +231,7 @@ const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
 int crypto_digest_algorithm_parse_name(const char *name);
 crypto_digest_t *crypto_digest_new(void);
 crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
+crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
 void crypto_digest_free(crypto_digest_t *digest);
 void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
                              size_t len);
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index dbaec61..fcce2c5 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -302,6 +302,13 @@ test_crypto_sha(void *arg)
                        "96177A9CB410FF61F20015AD");
   tt_int_op(i, OP_EQ, 0);
 
+  /* Test SHA-512 with a test vector from the specification. */
+  i = crypto_digest512(data, "abc", 3, DIGEST_SHA512);
+  test_memeq_hex(data, "ddaf35a193617abacc417349ae20413112e6fa4e89a97"
+                       "ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3"
+                       "feebbd454d4423643ce80e2a9ac94fa54ca49f");
+  tt_int_op(i, OP_EQ, 0);
+
   /* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */
 
   /* Case empty (wikipedia) */
@@ -410,6 +417,27 @@ test_crypto_sha(void *arg)
   crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
   crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256);
   tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
+  crypto_digest_free(d1);
+  crypto_digest_free(d2);
+
+  /* Incremental digest code with sha512 */
+  d1 = crypto_digest512_new(DIGEST_SHA512);
+  tt_assert(d1);
+  crypto_digest_add_bytes(d1, "abcdef", 6);
+  d2 = crypto_digest_dup(d1);
+  tt_assert(d2);
+  crypto_digest_add_bytes(d2, "ghijkl", 6);
+  crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
+  crypto_digest512(d_out2, "abcdefghijkl", 12, DIGEST_SHA512);
+  tt_mem_op(d_out1,OP_EQ, 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_digest512(d_out2, "abcdefmno", 9, DIGEST_SHA512);
+  tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
+  crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
+  crypto_digest512(d_out2, "abcdef", 6, DIGEST_SHA512);
+  tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
 
  done:
   if (d1)





More information about the tor-commits mailing list