add SHA512 support to crypto

This commit is contained in:
George Tankersley 2015-11-18 08:37:05 +00:00
parent 6cdd024c94
commit ff54cc8481
3 changed files with 102 additions and 12 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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)