From 44758f2a6035803e504a06ec1d6b47f6336bb8cb Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Wed, 7 Feb 2024 02:29:02 +0900 Subject: [PATCH] core/crypto: Stop using context.temp_allocator The max digest size for the foreseeable future will be 512 bits, and the max block size is currently 1152 bits (SHA3-224). If people add more exotic hash algorithms without bumping the constants when required, tests will fail. The stream buffer will currently be 576 bytes, which is "fine" to just stick on the stack, and is a sensible multiple of the more common block size of 64 bytes. --- core/crypto/hash/hash.odin | 12 ++++------ core/crypto/hash/low_level.odin | 7 ++++++ core/crypto/hmac/hmac.odin | 13 +++++----- tests/core/crypto/test_core_crypto_hash.odin | 25 ++++++++++++++++++++ 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/core/crypto/hash/hash.odin b/core/crypto/hash/hash.odin index 0840910c1..e4b3d4be1 100644 --- a/core/crypto/hash/hash.odin +++ b/core/crypto/hash/hash.odin @@ -56,17 +56,13 @@ hash_stream :: proc( ) { ctx: Context + buf: [MAX_BLOCK_SIZE * 4]byte + defer mem.zero_explicit(&buf, size_of(buf)) + init(&ctx, algorithm) - buffer_size := block_size(&ctx) * 4 - buf := make([]byte, buffer_size, context.temp_allocator) - defer { - mem.zero_explicit(raw_data(buf), buffer_size) - delete(buf, context.temp_allocator) - } - loop: for { - n, err := io.read(s, buf) + n, err := io.read(s, buf[:]) if n > 0 { // XXX/yawning: Can io.read return n > 0 and EOF? update(&ctx, buf[:n]) diff --git a/core/crypto/hash/low_level.odin b/core/crypto/hash/low_level.odin index 2b40a0a7c..242eadd5f 100644 --- a/core/crypto/hash/low_level.odin +++ b/core/crypto/hash/low_level.odin @@ -11,6 +11,13 @@ import "core:crypto/legacy/sha1" import "core:reflect" +// MAX_DIGEST_SIZE is the maximum size digest that can be returned by any +// of the Algorithms supported via this package. +MAX_DIGEST_SIZE :: 64 +// MAX_BLOCK_SIZE is the maximum block size used by any of Algorithms +// supported by this package. +MAX_BLOCK_SIZE :: sha3.BLOCK_SIZE_224 + // Algorithm is the algorithm identifier associated with a given Context. Algorithm :: enum { Invalid, diff --git a/core/crypto/hmac/hmac.odin b/core/crypto/hmac/hmac.odin index e9bd3b5ae..f720d2181 100644 --- a/core/crypto/hmac/hmac.odin +++ b/core/crypto/hmac/hmac.odin @@ -6,7 +6,6 @@ See: */ package hmac -import "base:runtime" import "core:crypto" import "core:crypto/hash" import "core:mem" @@ -26,10 +25,9 @@ sum :: proc(algorithm: hash.Algorithm, dst, msg, key: []byte) { // and key over msg and return true iff the tag is valid. It requires // that the tag is correctly sized. verify :: proc(algorithm: hash.Algorithm, tag, msg, key: []byte) -> bool { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - tag_sz := hash.DIGEST_SIZES[algorithm] + tag_buf: [hash.MAX_DIGEST_SIZE]byte - derived_tag := make([]byte, tag_sz, context.temp_allocator) + derived_tag := tag_buf[:hash.DIGEST_SIZES[algorithm]] sum(algorithm, derived_tag, msg, key) return crypto.compare_constant_time(derived_tag, tag) == 1 @@ -113,11 +111,12 @@ _O_PAD :: 0x5c @(private) _init_hashes :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + K0_buf: [hash.MAX_BLOCK_SIZE]byte + kPad_buf: [hash.MAX_BLOCK_SIZE]byte kLen := len(key) B := hash.BLOCK_SIZES[algorithm] - K0 := make([]byte, B, context.temp_allocator) + K0 := K0_buf[:B] defer mem.zero_explicit(raw_data(K0), B) switch { @@ -148,7 +147,7 @@ _init_hashes :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) { hash.init(&ctx._o_hash, algorithm) hash.init(&ctx._i_hash, algorithm) - kPad := make([]byte, B, context.temp_allocator) + kPad := kPad_buf[:B] defer mem.zero_explicit(raw_data(kPad), B) for v, i in K0 { diff --git a/tests/core/crypto/test_core_crypto_hash.odin b/tests/core/crypto/test_core_crypto_hash.odin index 1646c1baf..7dc559681 100644 --- a/tests/core/crypto/test_core_crypto_hash.odin +++ b/tests/core/crypto/test_core_crypto_hash.odin @@ -514,6 +514,31 @@ test_hash :: proc(t: ^testing.T) { algo_name := hash.ALGORITHM_NAMES[algo] + // Ensure that the MAX_(DIGEST_SIZE, BLOCK_SIZE) constants are + // still correct. + digest_sz := hash.DIGEST_SIZES[algo] + block_sz := hash.BLOCK_SIZES[algo] + expect( + t, + digest_sz <= hash.MAX_DIGEST_SIZE, + fmt.tprintf( + "%s: Digest size %d exceeds max %d", + algo_name, + digest_sz, + hash.MAX_DIGEST_SIZE, + ), + ) + expect( + t, + block_sz <= hash.MAX_BLOCK_SIZE, + fmt.tprintf( + "%s: Block size %d exceeds max %d", + algo_name, + block_sz, + hash.MAX_BLOCK_SIZE, + ), + ) + // Exercise most of the happy-path for the high level interface. rd: bytes.Reader bytes.reader_init(&rd, transmute([]byte)(data_1_000_000_a))