diff options
| author | Yawning Angel <yawning@schwanenlied.me> | 2021-11-06 02:36:30 +0000 |
|---|---|---|
| committer | Yawning Angel <yawning@schwanenlied.me> | 2021-11-17 13:59:53 +0000 |
| commit | d1e76ee4f299fa2a47306c3dc8a4929abfdd4886 (patch) | |
| tree | 7a55165b94a94147a6fe5ff0ccd7847131e4f6cd /core | |
| parent | 9be0d18e5df63895e66782bb07484ee242e7028c (diff) | |
core/crypto: Add constant-time memory comparison routines
Using a constant-time comparison is required when comparing things like
MACs, password digests, and etc to avoid exposing sensitive data via
trivial timing attacks.
These routines could also live under core:mem, but they are somewhat
specialized, and are likely only useful for cryptographic applications.
Diffstat (limited to 'core')
| -rw-r--r-- | core/crypto/crypto.odin | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin new file mode 100644 index 000000000..ddcc5d367 --- /dev/null +++ b/core/crypto/crypto.odin @@ -0,0 +1,41 @@ +package crypto + +import "core:mem" + +// compare_constant_time returns 1 iff a and b are equal, 0 otherwise. +// +// The execution time of this routine is constant regardless of the contents +// of the slices being compared, as long as the length of the slices is equal. +// If the length of the two slices is different, it will early-return 0. +compare_constant_time :: proc "contextless" (a, b: []byte) -> int { + // If the length of the slices is different, early return. + // + // This leaks the fact that the slices have a different length, + // but the routine is primarily intended for comparing things + // like MACS and password digests. + n := len(a) + if n != len(b) { + return 0 + } + + return compare_byte_ptrs_constant_time(raw_data(a), raw_data(b), n) +} + +// compare_byte_ptrs_constant_time returns 1 iff the bytes pointed to by +// a and b are equal, 0 otherwise. +// +// The execution time of this routine is constant regardless of the +// contents of the memory being compared. +compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> int { + x := mem.slice_ptr(a, n) + y := mem.slice_ptr(b, n) + + v: byte + for i in 0..<n { + v |= x[i] ~ y[i] + } + + // After the loop, v == 0 iff a == b. The subtraction will underflow + // iff v == 0, setting the sign-bit, which gets returned. + return int((u32(v)-1) >> 31) +} |