Switch CRYPTO_BUFFER_POOL to SipHash-2-4. This hash table, in applications that use pooling, can dedup received certificates in memory and thus should use a keyed hash. Change-Id: Idc40dc8f7463025183121642b30ea0de43ebac0e Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51125 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pool/internal.h b/crypto/pool/internal.h index b39ee42..f9f4838 100644 --- a/crypto/pool/internal.h +++ b/crypto/pool/internal.h
@@ -39,6 +39,7 @@ struct crypto_buffer_pool_st { LHASH_OF(CRYPTO_BUFFER) *bufs; CRYPTO_MUTEX lock; + const uint64_t hash_key[2]; };
diff --git a/crypto/pool/pool.c b/crypto/pool/pool.c index 89bf4c2..e889f52 100644 --- a/crypto/pool/pool.c +++ b/crypto/pool/pool.c
@@ -19,6 +19,8 @@ #include <openssl/bytestring.h> #include <openssl/mem.h> +#include <openssl/rand.h> +#include <openssl/siphash.h> #include <openssl/thread.h> #include "../internal.h" @@ -26,10 +28,13 @@ static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) { - return OPENSSL_hash32(buf->data, buf->len); + return (uint32_t)SIPHASH_24(buf->pool->hash_key, buf->data, buf->len); } static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) { + // Only |CRYPTO_BUFFER|s from the same pool have compatible hashes. + assert(a->pool != NULL); + assert(a->pool == b->pool); if (a->len != b->len) { return 1; } @@ -50,6 +55,7 @@ } CRYPTO_MUTEX_init(&pool->lock); + RAND_bytes((uint8_t *)&pool->hash_key, sizeof(pool->hash_key)); return pool; } @@ -84,6 +90,7 @@ CRYPTO_BUFFER tmp; tmp.data = (uint8_t *) data; tmp.len = len; + tmp.pool = pool; CRYPTO_MUTEX_lock_read(&pool->lock); CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
diff --git a/tool/speed.cc b/tool/speed.cc index b91a4ce..c12ebb2 100644 --- a/tool/speed.cc +++ b/tool/speed.cc
@@ -41,6 +41,7 @@ #include <openssl/nid.h> #include <openssl/rand.h> #include <openssl/rsa.h> +#include <openssl/siphash.h> #include <openssl/trust_token.h> #if defined(OPENSSL_WINDOWS) @@ -561,20 +562,20 @@ static bool SpeedHashChunk(const EVP_MD *md, std::string name, size_t chunk_len) { bssl::ScopedEVP_MD_CTX ctx; - uint8_t scratch[16384]; + uint8_t input[16384] = {0}; - if (chunk_len > sizeof(scratch)) { + if (chunk_len > sizeof(input)) { return false; } name += ChunkLenSuffix(chunk_len); TimeResults results; - if (!TimeFunction(&results, [&ctx, md, chunk_len, &scratch]() -> bool { + if (!TimeFunction(&results, [&ctx, md, chunk_len, &input]() -> bool { uint8_t digest[EVP_MAX_MD_SIZE]; unsigned int md_len; return EVP_DigestInit_ex(ctx.get(), md, NULL /* ENGINE */) && - EVP_DigestUpdate(ctx.get(), scratch, chunk_len) && + EVP_DigestUpdate(ctx.get(), input, chunk_len) && EVP_DigestFinal_ex(ctx.get(), digest, &md_len); })) { fprintf(stderr, "EVP_DigestInit_ex failed.\n"); @@ -1035,6 +1036,29 @@ return true; } +static bool SpeedSipHash(const std::string &selected) { + if (!selected.empty() && selected.find("siphash") == std::string::npos) { + return true; + } + + uint64_t key[2] = {0}; + for (size_t len : g_chunk_lengths) { + std::vector<uint8_t> input(len); + TimeResults results; + if (!TimeFunction(&results, [&]() -> bool { + SIPHASH_24(key, input.data(), input.size()); + return true; + })) { + fprintf(stderr, "SIPHASH_24 failed.\n"); + ERR_print_errors_fp(stderr); + return false; + } + results.PrintWithBytes("SipHash-2-4" + ChunkLenSuffix(len), len); + } + + return true; +} + static TRUST_TOKEN_PRETOKEN *trust_token_pretoken_dup( TRUST_TOKEN_PRETOKEN *in) { TRUST_TOKEN_PRETOKEN *out = @@ -1434,7 +1458,8 @@ TRUST_TOKEN_experiment_v2_pmb(), 1, selected) || !SpeedTrustToken("TrustToken-Exp2PMB-Batch10", TRUST_TOKEN_experiment_v2_pmb(), 10, selected) || - !SpeedBase64(selected)) { + !SpeedBase64(selected) || + !SpeedSipHash(selected)) { return false; } #if defined(BORINGSSL_FIPS)