Merge branch 'feature17796_squashed'

This commit is contained in:
Nick Mathewson 2015-12-29 09:48:39 -05:00
commit 603110aa1d
3 changed files with 58 additions and 21 deletions

6
changes/feature17796 Normal file
View File

@ -0,0 +1,6 @@
o Minor features (crypto):
- When allocating a digest state object, allocate no more space than we
actually need. Previously, we were allocating as much space as the
state for the largest algorithm would need. This change saves up to
672 bytes per circuit. Closes ticket 17796.

View File

@ -1737,23 +1737,57 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg)
/** Intermediate information about the digest of a stream of data. */
struct crypto_digest_t {
digest_algorithm_t algorithm; /**< Which algorithm is in use? */
/** State for the digest we're using. Only one member of the
* union is usable, depending on the value of <b>algorithm</b>. Note also
* that space for other members might not even be allocated!
*/
union {
SHA_CTX sha1; /**< state for SHA1 */
SHA256_CTX sha2; /**< state for SHA256 */
SHA512_CTX sha512; /**< state for SHA512 */
keccak_state sha3; /**< state for SHA3-[256,512] */
} 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? */
} d;
};
/**
* Return the number of bytes we need to malloc in order to get a
* crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe
* when we free one.
*/
static size_t
crypto_digest_alloc_bytes(digest_algorithm_t alg)
{
/* Helper: returns the number of bytes in the 'f' field of 'st' */
#define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f ))
/* Gives the length of crypto_digest_t through the end of the field 'd' */
#define END_OF_FIELD(f) (STRUCT_OFFSET(crypto_digest_t, f) + \
STRUCT_FIELD_SIZE(crypto_digest_t, f))
switch (alg) {
case DIGEST_SHA1:
return END_OF_FIELD(d.sha1);
case DIGEST_SHA256:
return END_OF_FIELD(d.sha2);
case DIGEST_SHA512:
return END_OF_FIELD(d.sha512);
case DIGEST_SHA3_256:
case DIGEST_SHA3_512:
return END_OF_FIELD(d.sha3);
default:
tor_assert(0);
return 0;
}
#undef END_OF_FIELD
#undef STRUCT_FIELD_SIZE
}
/** Allocate and return a new digest object to compute SHA1 digests.
*/
crypto_digest_t *
crypto_digest_new(void)
{
crypto_digest_t *r;
r = tor_malloc(sizeof(crypto_digest_t));
r = tor_malloc(crypto_digest_alloc_bytes(DIGEST_SHA1));
SHA1_Init(&r->d.sha1);
r->algorithm = DIGEST_SHA1;
return r;
@ -1766,7 +1800,7 @@ crypto_digest256_new(digest_algorithm_t algorithm)
{
crypto_digest_t *r;
tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
r = tor_malloc(sizeof(crypto_digest_t));
r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
if (algorithm == DIGEST_SHA256)
SHA256_Init(&r->d.sha2);
else
@ -1782,7 +1816,7 @@ crypto_digest512_new(digest_algorithm_t algorithm)
{
crypto_digest_t *r;
tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
r = tor_malloc(sizeof(crypto_digest_t));
r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
if (algorithm == DIGEST_SHA512)
SHA512_Init(&r->d.sha512);
else
@ -1798,7 +1832,8 @@ crypto_digest_free(crypto_digest_t *digest)
{
if (!digest)
return;
memwipe(digest, 0, sizeof(crypto_digest_t));
size_t bytes = crypto_digest_alloc_bytes(digest->algorithm);
memwipe(digest, 0, bytes);
tor_free(digest);
}
@ -1857,8 +1892,9 @@ crypto_digest_get_digest(crypto_digest_t *digest,
return;
}
const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
/* memcpy into a temporary ctx, since SHA*_Final clears the context */
memcpy(&tmpenv, digest, sizeof(crypto_digest_t));
memcpy(&tmpenv, digest, alloc_bytes);
switch (digest->algorithm) {
case DIGEST_SHA1:
SHA1_Final(r, &tmpenv.d.sha1);
@ -1874,12 +1910,7 @@ crypto_digest_get_digest(crypto_digest_t *digest,
log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
tor_assert(0); /* This is fatal, because it should never happen. */
default:
log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm);
/* If fragile_assert is not enabled, then we should at least not
* leak anything. */
memwipe(r, 0xff, sizeof(r));
memwipe(&tmpenv, 0, sizeof(crypto_digest_t));
tor_fragile_assert();
tor_assert(0); /* Unreachable. */
break;
}
memcpy(out, r, out_len);
@ -1892,15 +1923,14 @@ crypto_digest_get_digest(crypto_digest_t *digest,
crypto_digest_t *
crypto_digest_dup(const crypto_digest_t *digest)
{
crypto_digest_t *r;
tor_assert(digest);
r = tor_malloc(sizeof(crypto_digest_t));
memcpy(r,digest,sizeof(crypto_digest_t));
return r;
const size_t alloc_bytes = crypto_digest_alloc_bytes(digest->algorithm);
return tor_memdup(digest, alloc_bytes);
}
/** Replace the state of the digest object <b>into</b> with the state
* of the digest object <b>from</b>.
* of the digest object <b>from</b>. Requires that 'into' and 'from'
* have the same digest type.
*/
void
crypto_digest_assign(crypto_digest_t *into,
@ -1908,7 +1938,9 @@ crypto_digest_assign(crypto_digest_t *into,
{
tor_assert(into);
tor_assert(from);
memcpy(into,from,sizeof(crypto_digest_t));
tor_assert(into->algorithm == from->algorithm);
const size_t alloc_bytes = crypto_digest_alloc_bytes(from->algorithm);
memcpy(into,from,alloc_bytes);
}
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest

View File

@ -100,7 +100,6 @@ typedef enum {
DIGEST_SHA3_512 = 4,
} digest_algorithm_t;
#define N_DIGEST_ALGORITHMS (DIGEST_SHA3_512+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 512 bits are right-padded