mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-20 05:20:28 +00:00
core:crypto/_blake2: Cleanups and fixes
The fixes apply to "use it as a MAC" which was not part of the documented/exposed API. It now is, and is covered by the self-test routines from the RFC.
This commit is contained in:
@@ -19,17 +19,12 @@ BLAKE2S_SIZE :: 32
|
||||
BLAKE2B_BLOCK_SIZE :: 128
|
||||
BLAKE2B_SIZE :: 64
|
||||
|
||||
MAX_SIZE :: 255
|
||||
|
||||
Blake2s_Context :: struct {
|
||||
h: [8]u32,
|
||||
t: [2]u32,
|
||||
f: [2]u32,
|
||||
x: [BLAKE2S_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
ih: [8]u32,
|
||||
padded_key: [BLAKE2S_BLOCK_SIZE]byte,
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
|
||||
@@ -42,9 +37,6 @@ Blake2b_Context :: struct {
|
||||
f: [2]u64,
|
||||
x: [BLAKE2B_BLOCK_SIZE]byte,
|
||||
nx: int,
|
||||
ih: [8]u64,
|
||||
padded_key: [BLAKE2B_BLOCK_SIZE]byte,
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
|
||||
@@ -87,11 +79,12 @@ BLAKE2B_IV := [8]u64 {
|
||||
|
||||
init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) {
|
||||
when T == Blake2s_Context {
|
||||
max_size :: BLAKE2S_SIZE
|
||||
MAX_SIZE :: BLAKE2S_SIZE
|
||||
} else when T == Blake2b_Context {
|
||||
max_size :: BLAKE2B_SIZE
|
||||
MAX_SIZE :: BLAKE2B_SIZE
|
||||
}
|
||||
ensure_contextless(cfg.size <= max_size, "blake2: requested output size exceeeds algorithm max")
|
||||
ensure_contextless(cfg.size <= MAX_SIZE, "blake2: requested output size exceeeds algorithm max")
|
||||
ensure_contextless(len(cfg.key) <= MAX_SIZE, "blake2: requested key size exceeeds algorithm max")
|
||||
|
||||
// To save having to allocate a scratch buffer, use the internal
|
||||
// data buffer (`ctx.x`), as it is exactly the correct size.
|
||||
@@ -152,17 +145,11 @@ init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) {
|
||||
ctx.is_last_node = true
|
||||
}
|
||||
if len(cfg.key) > 0 {
|
||||
copy(ctx.padded_key[:], cfg.key)
|
||||
update(ctx, ctx.padded_key[:])
|
||||
ctx.is_keyed = true
|
||||
copy(ctx.x[:], cfg.key)
|
||||
ctx.nx = len(ctx.x)
|
||||
} else {
|
||||
ctx.nx = 0
|
||||
}
|
||||
copy(ctx.ih[:], ctx.h[:])
|
||||
copy(ctx.h[:], ctx.ih[:])
|
||||
if ctx.is_keyed {
|
||||
update(ctx, ctx.padded_key[:])
|
||||
}
|
||||
|
||||
ctx.nx = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
@@ -172,22 +159,22 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
|
||||
p := p
|
||||
when T == Blake2s_Context {
|
||||
block_size :: BLAKE2S_BLOCK_SIZE
|
||||
BLOCK_SIZE :: BLAKE2S_BLOCK_SIZE
|
||||
} else when T == Blake2b_Context {
|
||||
block_size :: BLAKE2B_BLOCK_SIZE
|
||||
BLOCK_SIZE :: BLAKE2B_BLOCK_SIZE
|
||||
}
|
||||
|
||||
left := block_size - ctx.nx
|
||||
left := BLOCK_SIZE - ctx.nx
|
||||
if len(p) > left {
|
||||
copy(ctx.x[ctx.nx:], p[:left])
|
||||
p = p[left:]
|
||||
blocks(ctx, ctx.x[:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
if len(p) > block_size {
|
||||
n := len(p) &~ (block_size - 1)
|
||||
if len(p) > BLOCK_SIZE {
|
||||
n := len(p) &~ (BLOCK_SIZE - 1)
|
||||
if n == len(p) {
|
||||
n -= block_size
|
||||
n -= BLOCK_SIZE
|
||||
}
|
||||
blocks(ctx, p[:n])
|
||||
p = p[n:]
|
||||
@@ -228,12 +215,6 @@ reset :: proc "contextless" (ctx: ^$T) {
|
||||
|
||||
@(private)
|
||||
blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
ctx.padded_key[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
dec := BLAKE2S_BLOCK_SIZE - u32(ctx.nx)
|
||||
if ctx.t[0] < dec {
|
||||
ctx.t[1] -= 1
|
||||
@@ -254,17 +235,11 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
for i := 0; i < BLAKE2S_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32le(dst[i * 4:], ctx.h[i])
|
||||
}
|
||||
copy(hash, dst[:])
|
||||
copy(hash, dst[:ctx.size])
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
ctx.padded_key[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
dec := BLAKE2B_BLOCK_SIZE - u64(ctx.nx)
|
||||
if ctx.t[0] < dec {
|
||||
ctx.t[1] -= 1
|
||||
|
||||
@@ -28,13 +28,24 @@ Context :: _blake2.Blake2b_Context
|
||||
|
||||
// init initializes a Context with the default BLAKE2b config.
|
||||
init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) {
|
||||
ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2b: invalid digest size")
|
||||
ensure(digest_size <= DIGEST_SIZE, "crypto/blake2b: invalid digest size")
|
||||
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = u8(digest_size)
|
||||
_blake2.init(ctx, &cfg)
|
||||
}
|
||||
|
||||
// init_mac initializes a Context with a user provided key.
|
||||
init_mac :: proc(ctx: ^Context, key: []byte, digest_size := DIGEST_SIZE) {
|
||||
ensure(digest_size <= DIGEST_SIZE, "crypto/blake2b: invalid digest size")
|
||||
ensure(len(key) <= DIGEST_SIZE, "crypto/blake2b: invalid key size")
|
||||
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = u8(digest_size)
|
||||
cfg.key = key
|
||||
_blake2.init(ctx, &cfg)
|
||||
}
|
||||
|
||||
// update adds more data to the Context.
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
|
||||
@@ -28,13 +28,24 @@ Context :: _blake2.Blake2s_Context
|
||||
|
||||
// init initializes a Context with the default BLAKE2s config.
|
||||
init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) {
|
||||
ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2s: invalid digest size")
|
||||
ensure(digest_size <= DIGEST_SIZE, "crypto/blake2s: invalid digest size")
|
||||
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = u8(digest_size)
|
||||
_blake2.init(ctx, &cfg)
|
||||
}
|
||||
|
||||
// init_mac initializes a Context with a user provided key.
|
||||
init_mac :: proc(ctx: ^Context, key: []byte, digest_size := DIGEST_SIZE) {
|
||||
ensure(digest_size <= DIGEST_SIZE, "crypto/blake2s: invalid digest size")
|
||||
ensure(len(key) <= DIGEST_SIZE, "crypto/blake2s: invalid key size")
|
||||
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = u8(digest_size)
|
||||
cfg.key = key
|
||||
_blake2.init(ctx, &cfg)
|
||||
}
|
||||
|
||||
// update adds more data to the Context.
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
|
||||
@@ -5,6 +5,9 @@ import "core:bytes"
|
||||
import "core:encoding/hex"
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
|
||||
import "core:crypto/blake2b"
|
||||
import "core:crypto/blake2s"
|
||||
import "core:crypto/hash"
|
||||
|
||||
@(test)
|
||||
@@ -596,4 +599,139 @@ test_hash :: proc(t: ^testing.T) {
|
||||
c_str,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
selftest_seq :: proc(dst: []byte, seed: u32) {
|
||||
a := 0xdead4bad * seed
|
||||
b: u32 = 1
|
||||
|
||||
for i in 0 ..< len(dst) {
|
||||
a, b = b, a + b
|
||||
dst[i] = byte(b >> 24)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_blake2b_self :: proc(t: ^testing.T) {
|
||||
expected := []byte{
|
||||
0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
|
||||
0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
|
||||
0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
|
||||
0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75,
|
||||
}
|
||||
md_lens := []int{20, 32, 48, 64}
|
||||
src_lens := []int{0, 3, 128, 129, 255, 1024}
|
||||
|
||||
b2b := proc(dst, src: []byte) {
|
||||
ctx: blake2b.Context
|
||||
|
||||
blake2b.init(&ctx, len(dst))
|
||||
blake2b.update(&ctx, src)
|
||||
blake2b.final(&ctx, dst)
|
||||
}
|
||||
b2b_keyed := proc(dst, key, src: []byte) {
|
||||
ctx: blake2b.Context
|
||||
|
||||
blake2b.init_mac(&ctx, key, len(dst))
|
||||
blake2b.update(&ctx, src)
|
||||
blake2b.final(&ctx, dst)
|
||||
}
|
||||
|
||||
buf: [1024]byte
|
||||
md, key: [64]byte
|
||||
|
||||
ctx: blake2b.Context
|
||||
blake2b.init(&ctx, 32)
|
||||
|
||||
for md_len in md_lens {
|
||||
dst := md[:md_len]
|
||||
for src_len in src_lens {
|
||||
src := buf[:src_len]
|
||||
|
||||
selftest_seq(src, u32(src_len))
|
||||
b2b(dst, src)
|
||||
blake2b.update(&ctx, dst)
|
||||
|
||||
k := key[:md_len]
|
||||
selftest_seq(k, u32(md_len))
|
||||
b2b_keyed(dst, k, src)
|
||||
blake2b.update(&ctx, dst)
|
||||
}
|
||||
}
|
||||
|
||||
blake2b.final(&ctx, md[:32])
|
||||
|
||||
expected_str := string(hex.encode(expected, context.temp_allocator))
|
||||
actual_str := string(hex.encode(md[:32], context.temp_allocator))
|
||||
|
||||
testing.expectf(
|
||||
t,
|
||||
expected_str == actual_str,
|
||||
"blake2b/self-test: Expected: %s Got %s",
|
||||
expected_str,
|
||||
actual_str,
|
||||
)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_blake2s_self :: proc(t: ^testing.T) {
|
||||
expected := []byte{
|
||||
0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD,
|
||||
0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC,
|
||||
0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87,
|
||||
0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE,
|
||||
}
|
||||
md_lens := []int{16, 20, 28, 32}
|
||||
src_lens := []int{0, 3, 64, 65, 255, 1024}
|
||||
|
||||
b2s := proc(dst, src: []byte) {
|
||||
ctx: blake2s.Context
|
||||
|
||||
blake2s.init(&ctx, len(dst))
|
||||
blake2s.update(&ctx, src)
|
||||
blake2s.final(&ctx, dst)
|
||||
}
|
||||
b2s_keyed := proc(dst, key, src: []byte) {
|
||||
ctx: blake2s.Context
|
||||
|
||||
blake2s.init_mac(&ctx, key, len(dst))
|
||||
blake2s.update(&ctx, src)
|
||||
blake2s.final(&ctx, dst)
|
||||
}
|
||||
|
||||
buf: [1024]byte
|
||||
md, key: [32]byte
|
||||
|
||||
ctx: blake2s.Context
|
||||
blake2s.init(&ctx)
|
||||
|
||||
for md_len in md_lens {
|
||||
dst := md[:md_len]
|
||||
for src_len in src_lens {
|
||||
src := buf[:src_len]
|
||||
|
||||
selftest_seq(src, u32(src_len))
|
||||
b2s(dst, src)
|
||||
blake2s.update(&ctx, dst)
|
||||
|
||||
k := key[:md_len]
|
||||
selftest_seq(k, u32(md_len))
|
||||
b2s_keyed(dst, k, src)
|
||||
blake2s.update(&ctx, dst)
|
||||
}
|
||||
}
|
||||
|
||||
blake2s.final(&ctx, md[:])
|
||||
|
||||
expected_str := string(hex.encode(expected, context.temp_allocator))
|
||||
actual_str := string(hex.encode(md[:], context.temp_allocator))
|
||||
|
||||
testing.expectf(
|
||||
t,
|
||||
expected_str == actual_str,
|
||||
"blake2s/self-test: Expected: %s Got %s",
|
||||
expected_str,
|
||||
actual_str,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user