commit ff54cc8481f88ecbc40a8abc0a1812fcf583ea73 Author: George Tankersley george.tankersley@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)