diff --git a/core/crypto/README.md b/core/crypto/README.md index c21fba44b..5955f9c56 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -2,48 +2,43 @@ A crypto library for the Odin language ## Supported -This library offers various algorithms available in either native Odin or via bindings to the [Botan](https://botan.randombit.net/) crypto library. +This library offers various algorithms implemented in Odin. Please see the chart below for the options. -**Note:** All crypto hash algorithms, offered by [Botan\'s FFI](https://botan.randombit.net/handbook/api_ref/hash.html), have been added. ## Hashing algorithms -| Algorithm | Odin | Botan | -|:-------------------------------------------------------------------------------------------------------------|:-----------------|:---------------------| -| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ | | -| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | ✔️ | -| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | | -| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | ✔️ | -| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ | | -| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | | -| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | | -| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | -| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | | -| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | ✔️ | -| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | ✔️ | -| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | ✔️\* | -| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | ✔️ | -| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | ✔️ | -| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | -| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | ✔️ | -| [Skein](https://www.schneier.com/academic/skein/) | | ✔️\*\* | -| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | ✔️ | -| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | ✔️ | -| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | ✔️ | -| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | | -| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | ✔️ | - -\* Only `RIPEMD-160` -\*\* Only `SKEIN-512` +| Algorithm | | +|:-------------------------------------------------------------------------------------------------------------|:-----------------| +| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ | +| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | +| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ | +| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ | +| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ | +| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ | +| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ | +| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | +| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ | +| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ | +| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ | +| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ | +| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ | +| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ | +| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | +| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ | +| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ | +| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ | +| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | +| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ | +| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ | #### High level API -Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*\*\*. +Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. Included in these groups are four procedures. * `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally * `hash_bytes` - Hash a given byte slice and return the computed hash * `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it * `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) -\*\*\* On some algorithms there is another part to the name, since they might offer control about additional parameters. +\* On some algorithms there is another part to the name, since they might offer control about additional parameters. For instance, `HAVAL` offers different sizes as well as three different round amounts. Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`. @@ -51,13 +46,6 @@ Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.h The above mentioned procedures internally call three procedures: `init`, `update` and `final`. You may also directly call them, if you wish. -#### Context system -The library uses a context system internally to be able to switch between Odin / Botan implementations freely. -When an Odin implementation is available, it is the default. -You may change what is used during runtime by calling `foo.use_botan()` or `foo.use_odin()`. -It is also possible to set this during compile time via `USE_BOTAN_LIB=true`. -Internally a vtable is used to set the appropriate procedures when switching. This works for all the procedures mentioned in the APIs above. - #### Example ```odin package crypto_example @@ -67,12 +55,16 @@ import "core:crypto/md4" main :: proc() { input := "foo" - // Compute the hash via Odin implementation + + // Compute the hash, using the high level API computed_hash := md4.hash(input) - // Switch to Botan - md4.use_botan() - // Compute the hash via Botan bindings - computed_hash_botan := md4.hash(input) + + // Compute the hash, using the low level API + ctx: md4.Md4_Context + computed_hash_low: [16]byte + md4.init(&ctx) + md4.update(&ctx, transmute([]byte)input) + md4.final(&ctx, computed_hash_low[:]) } ``` For example uses of all available algorithms, please see the tests within `tests/core/crypto`. diff --git a/core/crypto/_blake2/_blake2.odin b/core/crypto/_blake2/_blake2.odin index b2e18d6c7..7b75541e9 100644 --- a/core/crypto/_blake2/_blake2.odin +++ b/core/crypto/_blake2/_blake2.odin @@ -6,7 +6,6 @@ package _blake2 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the BLAKE2 hashing algorithm, as defined in and */ @@ -76,7 +75,7 @@ BLAKE2B_IV := [8]u64 { 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, } -init_odin :: proc(ctx: ^$T) { +init :: proc(ctx: ^$T) { when T == Blake2s_Context { block_size :: BLAKE2S_BLOCK_SIZE } else when T == Blake2b_Context { @@ -139,17 +138,17 @@ init_odin :: proc(ctx: ^$T) { } if len(ctx.cfg.key) > 0 { copy(ctx.padded_key[:], ctx.cfg.key) - update_odin(ctx, ctx.padded_key[:]) + update(ctx, ctx.padded_key[:]) ctx.is_keyed = true } copy(ctx.ih[:], ctx.h[:]) copy(ctx.h[:], ctx.ih[:]) if ctx.is_keyed { - update_odin(ctx, ctx.padded_key[:]) + update(ctx, ctx.padded_key[:]) } } -update_odin :: proc(ctx: ^$T, p: []byte) { +update :: proc "contextless" (ctx: ^$T, p: []byte) { p := p when T == Blake2s_Context { block_size :: BLAKE2S_BLOCK_SIZE @@ -161,7 +160,7 @@ update_odin :: proc(ctx: ^$T, p: []byte) { if len(p) > left { copy(ctx.x[ctx.nx:], p[:left]) p = p[left:] - blake2_blocks(ctx, ctx.x[:]) + blocks(ctx, ctx.x[:]) ctx.nx = 0 } if len(p) > block_size { @@ -169,13 +168,22 @@ update_odin :: proc(ctx: ^$T, p: []byte) { if n == len(p) { n -= block_size } - blake2_blocks(ctx, p[:n]) + blocks(ctx, p[:n]) p = p[n:] } ctx.nx += copy(ctx.x[ctx.nx:], p) } -blake2s_final_odin :: proc(ctx: $T, hash: []byte) { +final :: proc "contextless" (ctx: ^$T, hash: []byte) { + when T == Blake2s_Context { + blake2s_final(ctx, hash) + } + when T == Blake2b_Context { + blake2b_final(ctx, hash) + } +} + +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 @@ -193,7 +201,7 @@ blake2s_final_odin :: proc(ctx: $T, hash: []byte) { ctx.f[1] = 0xffffffff } - blake2_blocks(ctx, ctx.x[:]) + blocks(ctx, ctx.x[:]) j := 0 for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] { @@ -205,7 +213,7 @@ blake2s_final_odin :: proc(ctx: $T, hash: []byte) { } } -blake2b_final_odin :: proc(ctx: $T, hash: []byte) { +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 @@ -223,7 +231,7 @@ blake2b_final_odin :: proc(ctx: $T, hash: []byte) { ctx.f[1] = 0xffffffffffffffff } - blake2_blocks(ctx, ctx.x[:]) + blocks(ctx, ctx.x[:]) j := 0 for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] { @@ -239,7 +247,7 @@ blake2b_final_odin :: proc(ctx: $T, hash: []byte) { } } -blake2_blocks :: proc(ctx: ^$T, p: []byte) { +blocks :: proc "contextless" (ctx: ^$T, p: []byte) { when T == Blake2s_Context { blake2s_blocks(ctx, p) } @@ -248,7 +256,7 @@ blake2_blocks :: proc(ctx: ^$T, p: []byte) { } } -blake2s_blocks :: #force_inline proc "contextless"(ctx: ^Blake2s_Context, p: []byte) { +blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []byte) { h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] p := p for len(p) >= BLAKE2S_BLOCK_SIZE { @@ -1404,7 +1412,7 @@ blake2s_blocks :: #force_inline proc "contextless"(ctx: ^Blake2s_Context, p: []b ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 } -blake2b_blocks :: #force_inline proc "contextless"(ctx: ^Blake2b_Context, p: []byte) { +blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []byte) { h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] p := p for len(p) >= BLAKE2B_BLOCK_SIZE { diff --git a/core/crypto/_ctx/_ctx.odin b/core/crypto/_ctx/_ctx.odin deleted file mode 100644 index 0a0e0e6cf..000000000 --- a/core/crypto/_ctx/_ctx.odin +++ /dev/null @@ -1,79 +0,0 @@ -package _ctx - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial creation and testing of the bindings. - - Implementation of the context, used internally by the crypto library. -*/ - -import "core:io" -import "core:os" - -Hash_Size :: enum { - _16, - _20, - _24, - _28, - _32, - _40, - _48, - _64, - _128, -} - -Hash_Context :: struct { - botan_hash_algo: cstring, - external_ctx: any, - internal_ctx: any, - hash_size: Hash_Size, - hash_size_val: int, - is_using_odin: bool, - using vtbl: ^Hash_Context_Vtable, -} - -Hash_Context_Vtable :: struct { - hash_bytes_16 : proc (ctx: ^Hash_Context, input: []byte) -> [16]byte, - hash_bytes_20 : proc (ctx: ^Hash_Context, input: []byte) -> [20]byte, - hash_bytes_24 : proc (ctx: ^Hash_Context, input: []byte) -> [24]byte, - hash_bytes_28 : proc (ctx: ^Hash_Context, input: []byte) -> [28]byte, - hash_bytes_32 : proc (ctx: ^Hash_Context, input: []byte) -> [32]byte, - hash_bytes_40 : proc (ctx: ^Hash_Context, input: []byte) -> [40]byte, - hash_bytes_48 : proc (ctx: ^Hash_Context, input: []byte) -> [48]byte, - hash_bytes_64 : proc (ctx: ^Hash_Context, input: []byte) -> [64]byte, - hash_bytes_128 : proc (ctx: ^Hash_Context, input: []byte) -> [128]byte, - hash_file_16 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool), - hash_file_20 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool), - hash_file_24 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool), - hash_file_28 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool), - hash_file_32 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool), - hash_file_40 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([40]byte, bool), - hash_file_48 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool), - hash_file_64 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool), - hash_file_128 : proc (ctx: ^Hash_Context, hd: os.Handle, load_at_once := false) -> ([128]byte, bool), - hash_stream_16 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([16]byte, bool), - hash_stream_20 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([20]byte, bool), - hash_stream_24 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([24]byte, bool), - hash_stream_28 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([28]byte, bool), - hash_stream_32 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([32]byte, bool), - hash_stream_40 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([40]byte, bool), - hash_stream_48 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([48]byte, bool), - hash_stream_64 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([64]byte, bool), - hash_stream_128 : proc (ctx: ^Hash_Context, s: io.Stream) -> ([128]byte, bool), - hash_bytes_slice : proc (ctx: ^Hash_Context, input: []byte, out_size: int, allocator := context.allocator) -> []byte, - hash_file_slice : proc (ctx: ^Hash_Context, hd: os.Handle, out_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool), - hash_stream_slice : proc (ctx: ^Hash_Context, s: io.Stream, out_size: int, allocator := context.allocator) -> ([]byte, bool), - init : proc (ctx: ^Hash_Context), - update : proc (ctx: ^Hash_Context, data: []byte), - final : proc (ctx: ^Hash_Context, hash: []byte), -} - -_init_vtable :: #force_inline proc() -> ^Hash_Context { - ctx := new(Hash_Context) - vtbl := new(Hash_Context_Vtable) - ctx.vtbl = vtbl - return ctx -} \ No newline at end of file diff --git a/core/crypto/_sha3/_sha3.odin b/core/crypto/_sha3/_sha3.odin index 1038eb77c..76e09bf24 100644 --- a/core/crypto/_sha3/_sha3.odin +++ b/core/crypto/_sha3/_sha3.odin @@ -6,7 +6,6 @@ package _sha3 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the Keccak hashing algorithm, standardized as SHA3 in To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding. @@ -115,14 +114,14 @@ keccakf :: proc "contextless" (st: ^[25]u64) { } } -init_odin :: proc "contextless" (c: ^Sha3_Context) { +init :: proc "contextless" (c: ^Sha3_Context) { for i := 0; i < 25; i += 1 { c.st.q[i] = 0 } c.rsiz = 200 - 2 * c.mdlen } -update_odin :: proc "contextless" (c: ^Sha3_Context, data: []byte) { +update :: proc "contextless" (c: ^Sha3_Context, data: []byte) { j := c.pt for i := 0; i < len(data); i += 1 { c.st.b[j] ~= data[i] @@ -135,7 +134,7 @@ update_odin :: proc "contextless" (c: ^Sha3_Context, data: []byte) { c.pt = j } -final_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { +final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { if c.is_keccak { c.st.b[c.pt] ~= 0x01 } else { @@ -149,14 +148,14 @@ final_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { } } -shake_xof_odin :: proc "contextless" (c: ^Sha3_Context) { +shake_xof :: proc "contextless" (c: ^Sha3_Context) { c.st.b[c.pt] ~= 0x1F c.st.b[c.rsiz - 1] ~= 0x80 keccakf(&c.st.q) c.pt = 0 } -shake_out_odin :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { +shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) { j := c.pt for i := 0; i < len(hash); i += 1 { if j >= c.rsiz { diff --git a/core/crypto/_tiger/_tiger.odin b/core/crypto/_tiger/_tiger.odin index 50caf0944..e1629c4ca 100644 --- a/core/crypto/_tiger/_tiger.odin +++ b/core/crypto/_tiger/_tiger.odin @@ -6,7 +6,6 @@ package _tiger List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the Tiger hashing algorithm, as defined in */ @@ -291,7 +290,7 @@ Tiger_Context :: struct { ver: int, } -round :: #force_inline proc "contextless"(a, b, c, x, mul: u64) -> (u64, u64, u64) { +round :: #force_inline proc "contextless" (a, b, c, x, mul: u64) -> (u64, u64, u64) { a, b, c := a, b, c c ~= x a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff] @@ -300,7 +299,7 @@ round :: #force_inline proc "contextless"(a, b, c, x, mul: u64) -> (u64, u64, u6 return a, b, c } -pass :: #force_inline proc "contextless"(a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) { +pass :: #force_inline proc "contextless" (a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) { x, y, z = round(a, b, c, d[0], mul) y, z, x = round(y, z, x, d[1], mul) z, x, y = round(z, x, y, d[2], mul) @@ -312,7 +311,7 @@ pass :: #force_inline proc "contextless"(a, b, c: u64, d: []u64, mul: u64) -> (x return } -key_schedule :: #force_inline proc "contextless"(x: []u64) { +key_schedule :: #force_inline proc "contextless" (x: []u64) { x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5 x[1] ~= x[0] x[2] += x[1] @@ -331,7 +330,7 @@ key_schedule :: #force_inline proc "contextless"(x: []u64) { x[7] -= x[6] ~ 0x0123456789abcdef } -compress :: #force_inline proc "contextless"(ctx: ^Tiger_Context, data: []byte) { +compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) { a := ctx.a b := ctx.b c := ctx.c @@ -346,13 +345,13 @@ compress :: #force_inline proc "contextless"(ctx: ^Tiger_Context, data: []byte) ctx.c += c } -init_odin :: proc(ctx: ^Tiger_Context) { +init :: proc "contextless" (ctx: ^Tiger_Context) { ctx.a = 0x0123456789abcdef ctx.b = 0xfedcba9876543210 ctx.c = 0xf096a5b4c3b2e187 } -update_odin :: proc(ctx: ^Tiger_Context, input: []byte) { +update :: proc(ctx: ^Tiger_Context, input: []byte) { p := make([]byte, len(input)) copy(p, input) @@ -380,7 +379,7 @@ update_odin :: proc(ctx: ^Tiger_Context, input: []byte) { } } -final_odin :: proc(ctx: ^Tiger_Context, hash: []byte) { +final :: proc(ctx: ^Tiger_Context, hash: []byte) { length := ctx.length tmp: [64]byte if ctx.ver == 1 { @@ -391,16 +390,16 @@ final_odin :: proc(ctx: ^Tiger_Context, hash: []byte) { size := length & 0x3f if size < 56 { - update_odin(ctx, tmp[:56 - size]) + update(ctx, tmp[:56 - size]) } else { - update_odin(ctx, tmp[:64 + 56 - size]) + update(ctx, tmp[:64 + 56 - size]) } length <<= 3 for i := uint(0); i < 8; i += 1 { tmp[i] = byte(length >> (8 * i)) } - update_odin(ctx, tmp[:8]) + update(ctx, tmp[:8]) for i := uint(0); i < 8; i += 1 { tmp[i] = byte(ctx.a >> (8 * i)) diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin index 5046523b8..9d53f8a89 100644 --- a/core/crypto/blake/blake.odin +++ b/core/crypto/blake/blake.odin @@ -6,7 +6,6 @@ package blake List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the BLAKE hashing algorithm, as defined in */ @@ -14,102 +13,59 @@ package blake import "core:os" import "core:io" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since BLAKE is not available in Botan -@(warning="BLAKE is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_blake256_ctx :: #force_inline proc(is224: bool, size: _ctx.Hash_Size) { - ctx: Blake256_Context - ctx.is224 = is224 - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = size -} - -@(private) -_create_blake512_ctx :: #force_inline proc(is384: bool, size: _ctx.Hash_Size) { - ctx: Blake512_Context - ctx.is384 = is384 - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = size -} - /* High level API */ // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc "contextless" (data: string) -> [28]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_blake256_ctx(true, ._28) - return _hash_impl->hash_bytes_28(data) +hash_bytes_224 :: proc "contextless" (data: []byte) -> [28]byte { + hash: [28]byte + ctx: Blake256_Context + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_blake256_ctx(true, ._28) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Blake256_Context + ctx.is224 = true + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_blake256_ctx(true, ._28) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -121,29 +77,53 @@ hash_224 :: proc { // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc "contextless" (data: string) -> [32]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_blake256_ctx(false, ._32) - return _hash_impl->hash_bytes_32(data) +hash_bytes_256 :: proc "contextless" (data: []byte) -> [32]byte { + hash: [32]byte + ctx: Blake256_Context + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_blake256_ctx(false, ._32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Blake256_Context + ctx.is224 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_blake256_ctx(false, ._32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -155,29 +135,53 @@ hash_256 :: proc { // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc "contextless" (data: string) -> [48]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_blake512_ctx(true, ._48) - return _hash_impl->hash_bytes_48(data) +hash_bytes_384 :: proc "contextless" (data: []byte) -> [48]byte { + hash: [48]byte + ctx: Blake512_Context + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_blake512_ctx(true, ._48) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: Blake512_Context + ctx.is384 = true + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_blake512_ctx(true, ._48) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -189,29 +193,53 @@ hash_384 :: proc { // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc "contextless" (data: string) -> [64]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_blake512_ctx(false, ._64) - return _hash_impl->hash_bytes_64(data) +hash_bytes_512 :: proc "contextless" (data: []byte) -> [64]byte { + hash: [64]byte + ctx: Blake512_Context + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_blake512_ctx(false, ._64) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Blake512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_blake512_ctx(false, ._64) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -225,231 +253,188 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() -} - -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } +init :: proc "contextless" (ctx: ^$T) { + when T == Blake256_Context { + if ctx.is224 { + ctx.h[0] = 0xc1059ed8 + ctx.h[1] = 0x367cd507 + ctx.h[2] = 0x3070dd17 + ctx.h[3] = 0xf70e5939 + ctx.h[4] = 0xffc00b31 + ctx.h[5] = 0x68581511 + ctx.h[6] = 0x64f98fa7 + ctx.h[7] = 0xbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667 + ctx.h[1] = 0xbb67ae85 + ctx.h[2] = 0x3c6ef372 + ctx.h[3] = 0xa54ff53a + ctx.h[4] = 0x510e527f + ctx.h[5] = 0x9b05688c + ctx.h[6] = 0x1f83d9ab + ctx.h[7] = 0x5be0cd19 } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok - } - } - return [28]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - if ctx.hash_size == ._28 || ctx.hash_size == ._32 { - _create_blake256_ctx(ctx.hash_size == ._28, ctx.hash_size) - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - init_odin(&c) - } - return - } - if ctx.hash_size == ._48 || ctx.hash_size == ._64 { - _create_blake512_ctx(ctx.hash_size == ._48, ctx.hash_size) - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - init_odin(&c) + } else when T == Blake512_Context { + if ctx.is384 { + ctx.h[0] = 0xcbbb9d5dc1059ed8 + ctx.h[1] = 0x629a292a367cd507 + ctx.h[2] = 0x9159015a3070dd17 + ctx.h[3] = 0x152fecd8f70e5939 + ctx.h[4] = 0x67332667ffc00b31 + ctx.h[5] = 0x8eb44a8768581511 + ctx.h[6] = 0xdb0c2e0d64f98fa7 + ctx.h[7] = 0x47b5481dbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667f3bcc908 + ctx.h[1] = 0xbb67ae8584caa73b + ctx.h[2] = 0x3c6ef372fe94f82b + ctx.h[3] = 0xa54ff53a5f1d36f1 + ctx.h[4] = 0x510e527fade682d1 + ctx.h[5] = 0x9b05688c2b3e6c1f + ctx.h[6] = 0x1f83d9abfb41bd6b + ctx.h[7] = 0x5be0cd19137e2179 } } } -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - #partial switch ctx.hash_size { - case ._28, ._32: - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - update_odin(&c, data) +update :: proc "contextless" (ctx: ^$T, data: []byte) { + data := data + when T == Blake256_Context { + if ctx.nx > 0 { + n := copy(ctx.x[ctx.nx:], data) + ctx.nx += n + if ctx.nx == BLOCKSIZE_256 { + block256(ctx, ctx.x[:]) + ctx.nx = 0 } - case ._48, ._64: - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - update_odin(&c, data) + data = data[n:] + } + if len(data) >= BLOCKSIZE_256 { + n := len(data) &~ (BLOCKSIZE_256 - 1) + block256(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.nx = copy(ctx.x[:], data) + } + } else when T == Blake512_Context { + if ctx.nx > 0 { + n := copy(ctx.x[ctx.nx:], data) + ctx.nx += n + if ctx.nx == BLOCKSIZE_512 { + block512(ctx, ctx.x[:]) + ctx.nx = 0 } + data = data[n:] + } + if len(data) >= BLOCKSIZE_512 { + n := len(data) &~ (BLOCKSIZE_512 - 1) + block512(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.nx = copy(ctx.x[:], data) + } } } -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - #partial switch ctx.hash_size { - case ._28, ._32: - if c, ok := ctx.internal_ctx.(Blake256_Context); ok { - final_odin(&c, hash) +final :: proc "contextless" (ctx: ^$T, hash: []byte) { + when T == Blake256_Context { + tmp: [65]byte + } else when T == Blake512_Context { + tmp: [129]byte + } + nx := u64(ctx.nx) + tmp[0] = 0x80 + length := (ctx.t + nx) << 3 + + when T == Blake256_Context { + if nx == 55 { + if ctx.is224 { + write_additional(ctx, {0x80}) + } else { + write_additional(ctx, {0x81}) } - case ._48, ._64: - if c, ok := ctx.internal_ctx.(Blake512_Context); ok { - final_odin(&c, hash) + } else { + if nx < 55 { + if nx == 0 { + ctx.nullt = true + } + write_additional(ctx, tmp[0 : 55 - nx]) + } else { + write_additional(ctx, tmp[0 : 64 - nx]) + write_additional(ctx, tmp[1:56]) + ctx.nullt = true } + if ctx.is224 { + write_additional(ctx, {0x00}) + } else { + write_additional(ctx, {0x01}) + } + } + + for i : uint = 0; i < 8; i += 1 { + tmp[i] = byte(length >> (56 - 8 * i)) + } + write_additional(ctx, tmp[0:8]) + + h := ctx.h[:] + if ctx.is224 { + h = h[0:7] + } + for s, i in h { + hash[i * 4] = byte(s >> 24) + hash[i * 4 + 1] = byte(s >> 16) + hash[i * 4 + 2] = byte(s >> 8) + hash[i * 4 + 3] = byte(s) + } + } else when T == Blake512_Context { + if nx == 111 { + if ctx.is384 { + write_additional(ctx, {0x80}) + } else { + write_additional(ctx, {0x81}) + } + } else { + if nx < 111 { + if nx == 0 { + ctx.nullt = true + } + write_additional(ctx, tmp[0 : 111 - nx]) + } else { + write_additional(ctx, tmp[0 : 128 - nx]) + write_additional(ctx, tmp[1:112]) + ctx.nullt = true + } + if ctx.is384 { + write_additional(ctx, {0x00}) + } else { + write_additional(ctx, {0x01}) + } + } + + for i : uint = 0; i < 16; i += 1 { + tmp[i] = byte(length >> (120 - 8 * i)) + } + write_additional(ctx, tmp[0:16]) + + h := ctx.h[:] + if ctx.is384 { + h = h[0:6] + } + for s, i in h { + hash[i * 8] = byte(s >> 56) + hash[i * 8 + 1] = byte(s >> 48) + hash[i * 8 + 2] = byte(s >> 40) + hash[i * 8 + 3] = byte(s >> 32) + hash[i * 8 + 4] = byte(s >> 24) + hash[i * 8 + 5] = byte(s >> 16) + hash[i * 8 + 6] = byte(s >> 8) + hash[i * 8 + 7] = byte(s) + } } } -/* - BLAKE implementation -*/ - SIZE_224 :: 28 SIZE_256 :: 32 SIZE_384 :: 48 @@ -542,8 +527,8 @@ G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int return a, b, c, d } -block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) { - i, j: int = ---, --- +block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check { + i, j: int = ---, --- v, m: [16]u32 = ---, --- p := p for len(p) >= BLOCKSIZE_256 { @@ -595,7 +580,7 @@ block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) { } block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check { - i, j: int = ---, --- + i, j: int = ---, --- v, m: [16]u64 = ---, --- p := p for len(p) >= BLOCKSIZE_512 { @@ -646,189 +631,7 @@ block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_ch } } -init_odin :: proc(ctx: ^$T) { - when T == Blake256_Context { - if ctx.is224 { - ctx.h[0] = 0xc1059ed8 - ctx.h[1] = 0x367cd507 - ctx.h[2] = 0x3070dd17 - ctx.h[3] = 0xf70e5939 - ctx.h[4] = 0xffc00b31 - ctx.h[5] = 0x68581511 - ctx.h[6] = 0x64f98fa7 - ctx.h[7] = 0xbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667 - ctx.h[1] = 0xbb67ae85 - ctx.h[2] = 0x3c6ef372 - ctx.h[3] = 0xa54ff53a - ctx.h[4] = 0x510e527f - ctx.h[5] = 0x9b05688c - ctx.h[6] = 0x1f83d9ab - ctx.h[7] = 0x5be0cd19 - } - } else when T == Blake512_Context { - if ctx.is384 { - ctx.h[0] = 0xcbbb9d5dc1059ed8 - ctx.h[1] = 0x629a292a367cd507 - ctx.h[2] = 0x9159015a3070dd17 - ctx.h[3] = 0x152fecd8f70e5939 - ctx.h[4] = 0x67332667ffc00b31 - ctx.h[5] = 0x8eb44a8768581511 - ctx.h[6] = 0xdb0c2e0d64f98fa7 - ctx.h[7] = 0x47b5481dbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667f3bcc908 - ctx.h[1] = 0xbb67ae8584caa73b - ctx.h[2] = 0x3c6ef372fe94f82b - ctx.h[3] = 0xa54ff53a5f1d36f1 - ctx.h[4] = 0x510e527fade682d1 - ctx.h[5] = 0x9b05688c2b3e6c1f - ctx.h[6] = 0x1f83d9abfb41bd6b - ctx.h[7] = 0x5be0cd19137e2179 - } - } -} - -update_odin :: proc(ctx: ^$T, data: []byte) { - data := data - when T == Blake256_Context { - if ctx.nx > 0 { - n := copy(ctx.x[ctx.nx:], data) - ctx.nx += n - if ctx.nx == BLOCKSIZE_256 { - block256(ctx, ctx.x[:]) - ctx.nx = 0 - } - data = data[n:] - } - if len(data) >= BLOCKSIZE_256 { - n := len(data) &~ (BLOCKSIZE_256 - 1) - block256(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.nx = copy(ctx.x[:], data) - } - } else when T == Blake512_Context { - if ctx.nx > 0 { - n := copy(ctx.x[ctx.nx:], data) - ctx.nx += n - if ctx.nx == BLOCKSIZE_512 { - block512(ctx, ctx.x[:]) - ctx.nx = 0 - } - data = data[n:] - } - if len(data) >= BLOCKSIZE_512 { - n := len(data) &~ (BLOCKSIZE_512 - 1) - block512(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.nx = copy(ctx.x[:], data) - } - } -} - -final_odin :: proc(ctx: ^$T, hash: []byte) { - when T == Blake256_Context { - tmp: [65]byte - } else when T == Blake512_Context { - tmp: [129]byte - } - nx := u64(ctx.nx) - tmp[0] = 0x80 - length := (ctx.t + nx) << 3 - - when T == Blake256_Context { - if nx == 55 { - if ctx.is224 { - write_additional(ctx, {0x80}) - } else { - write_additional(ctx, {0x81}) - } - } else { - if nx < 55 { - if nx == 0 { - ctx.nullt = true - } - write_additional(ctx, tmp[0 : 55 - nx]) - } else { - write_additional(ctx, tmp[0 : 64 - nx]) - write_additional(ctx, tmp[1:56]) - ctx.nullt = true - } - if ctx.is224 { - write_additional(ctx, {0x00}) - } else { - write_additional(ctx, {0x01}) - } - } - - for i : uint = 0; i < 8; i += 1 { - tmp[i] = byte(length >> (56 - 8 * i)) - } - write_additional(ctx, tmp[0:8]) - - h := ctx.h[:] - if ctx.is224 { - h = h[0:7] - } - for s, i in h { - hash[i * 4] = byte(s >> 24) - hash[i * 4 + 1] = byte(s >> 16) - hash[i * 4 + 2] = byte(s >> 8) - hash[i * 4 + 3] = byte(s) - } - } else when T == Blake512_Context { - if nx == 111 { - if ctx.is384 { - write_additional(ctx, {0x80}) - } else { - write_additional(ctx, {0x81}) - } - } else { - if nx < 111 { - if nx == 0 { - ctx.nullt = true - } - write_additional(ctx, tmp[0 : 111 - nx]) - } else { - write_additional(ctx, tmp[0 : 128 - nx]) - write_additional(ctx, tmp[1:112]) - ctx.nullt = true - } - if ctx.is384 { - write_additional(ctx, {0x00}) - } else { - write_additional(ctx, {0x01}) - } - } - - for i : uint = 0; i < 16; i += 1 { - tmp[i] = byte(length >> (120 - 8 * i)) - } - write_additional(ctx, tmp[0:16]) - - h := ctx.h[:] - if ctx.is384 { - h = h[0:6] - } - for s, i in h { - hash[i * 8] = byte(s >> 56) - hash[i * 8 + 1] = byte(s >> 48) - hash[i * 8 + 2] = byte(s >> 40) - hash[i * 8 + 3] = byte(s >> 32) - hash[i * 8 + 4] = byte(s >> 24) - hash[i * 8 + 5] = byte(s >> 16) - hash[i * 8 + 6] = byte(s >> 8) - hash[i * 8 + 7] = byte(s) - } - } -} - -write_additional :: proc(ctx: ^$T, data: []byte) { +write_additional :: proc "contextless" (ctx: ^$T, data: []byte) { ctx.t -= u64(len(data)) << 3 - update_odin(ctx, data) + update(ctx, data) } diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index da5e1ce24..85f9611f9 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -6,7 +6,6 @@ package blake2b List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the BLAKE2B hashing algorithm. BLAKE2B and BLAKE2B share the implementation in the _blake2 package. @@ -15,49 +14,8 @@ package blake2b import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../_blake2" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_64 = hash_bytes_odin - ctx.hash_file_64 = hash_file_odin - ctx.hash_stream_64 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_BLAKE2B) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -71,22 +29,50 @@ hash_string :: proc(data: string) -> [64]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [64]byte { - _create_blake2b_ctx() - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_blake2b_ctx() - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _blake2.update(&ctx, buf[:read]) + } + } + _blake2.final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_blake2b_ctx() - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [64]byte{}, false } hash :: proc { @@ -100,87 +86,16 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +Blake2b_Context :: _blake2.Blake2b_Context + +init :: proc(ctx: ^_blake2.Blake2b_Context) { + _blake2.init(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) { + _blake2.update(ctx, data) } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { - _blake2.init_odin(&c) - _blake2.update_odin(&c, data) - _blake2.blake2b_final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { - _blake2.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _blake2.update_odin(&c, buf[:read]) - } - } - _blake2.blake2b_final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_create_blake2b_ctx :: #force_inline proc() { - ctx: _blake2.Blake2b_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2B_SIZE - ctx.cfg = cfg - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._64 -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_blake2b_ctx() - if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { - _blake2.init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { - _blake2.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_blake2.Blake2b_Context); ok { - _blake2.blake2b_final_odin(&c, hash) - } +final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) { + _blake2.final(ctx, hash) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index b47a0bf90..72d15b227 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -6,7 +6,6 @@ package blake2s List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the BLAKE2S hashing algorithm. BLAKE2B and BLAKE2B share the implementation in the _blake2 package. @@ -15,49 +14,8 @@ package blake2s import "core:os" import "core:io" -import "../_ctx" import "../_blake2" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_32 = hash_bytes_odin - ctx.hash_file_32 = hash_file_odin - ctx.hash_stream_32 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since Blake2s is not available in Botan -@(warning="Blake2s is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -71,22 +29,50 @@ hash_string :: proc(data: string) -> [32]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [32]byte { - _create_blake2s_ctx() - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_blake2s_ctx() - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _blake2.update(&ctx, buf[:read]) + } + } + _blake2.final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_blake2s_ctx() - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [32]byte{}, false } hash :: proc { @@ -100,87 +86,16 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +Blake2s_Context :: _blake2.Blake2b_Context + +init :: proc(ctx: ^_blake2.Blake2s_Context) { + _blake2.init(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) { + _blake2.update(ctx, data) } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { - _blake2.init_odin(&c) - _blake2.update_odin(&c, data) - _blake2.blake2s_final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { - _blake2.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _blake2.update_odin(&c, buf[:read]) - } - } - _blake2.blake2s_final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -@(private) -_create_blake2s_ctx :: #force_inline proc() { - ctx: _blake2.Blake2s_Context - cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2S_SIZE - ctx.cfg = cfg - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._32 -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_blake2s_ctx() - if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { - _blake2.init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { - _blake2.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_blake2.Blake2s_Context); ok { - _blake2.blake2s_final_odin(&c, hash) - } +final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) { + _blake2.final(ctx, hash) } diff --git a/core/crypto/botan/botan.lib b/core/crypto/botan/botan.lib deleted file mode 100644 index 5731855cb..000000000 Binary files a/core/crypto/botan/botan.lib and /dev/null differ diff --git a/core/crypto/botan/botan.odin b/core/crypto/botan/botan.odin deleted file mode 100644 index 17420a25f..000000000 --- a/core/crypto/botan/botan.odin +++ /dev/null @@ -1,480 +0,0 @@ -package botan - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial creation and testing of the bindings. - - Bindings for the Botan crypto library. - Created for version 2.18.1, using the provided FFI header within Botan. - - The "botan_" prefix has been stripped from the identifiers to remove redundancy, - since the package is already named botan. -*/ - -import "core:c" - -FFI_ERROR :: #type c.int -FFI_SUCCESS :: FFI_ERROR(0) -FFI_INVALID_VERIFIER :: FFI_ERROR(1) -FFI_ERROR_INVALID_INPUT :: FFI_ERROR(-1) -FFI_ERROR_BAD_MAC :: FFI_ERROR(-2) -FFI_ERROR_INSUFFICIENT_BUFFER_SPACE :: FFI_ERROR(-10) -FFI_ERROR_EXCEPTION_THROWN :: FFI_ERROR(-20) -FFI_ERROR_OUT_OF_MEMORY :: FFI_ERROR(-21) -FFI_ERROR_BAD_FLAG :: FFI_ERROR(-30) -FFI_ERROR_NULL_POINTER :: FFI_ERROR(-31) -FFI_ERROR_BAD_PARAMETER :: FFI_ERROR(-32) -FFI_ERROR_KEY_NOT_SET :: FFI_ERROR(-33) -FFI_ERROR_INVALID_KEY_LENGTH :: FFI_ERROR(-34) -FFI_ERROR_NOT_IMPLEMENTED :: FFI_ERROR(-40) -FFI_ERROR_INVALID_OBJECT :: FFI_ERROR(-50) -FFI_ERROR_UNKNOWN_ERROR :: FFI_ERROR(-100) - -FFI_HEX_LOWER_CASE :: 1 - -CIPHER_INIT_FLAG_MASK_DIRECTION :: 1 -CIPHER_INIT_FLAG_ENCRYPT :: 0 -CIPHER_INIT_FLAG_DECRYPT :: 1 - -CIPHER_UPDATE_FLAG_FINAL :: 1 << 0 - -CHECK_KEY_EXPENSIVE_TESTS :: 1 - -PRIVKEY_EXPORT_FLAG_DER :: 0 -PRIVKEY_EXPORT_FLAG_PEM :: 1 - -PUBKEY_DER_FORMAT_SIGNATURE :: 1 - -FPE_FLAG_FE1_COMPAT_MODE :: 1 - -x509_cert_key_constraints :: #type c.int -NO_CONSTRAINTS :: x509_cert_key_constraints(0) -DIGITAL_SIGNATURE :: x509_cert_key_constraints(32768) -NON_REPUDIATION :: x509_cert_key_constraints(16384) -KEY_ENCIPHERMENT :: x509_cert_key_constraints(8192) -DATA_ENCIPHERMENT :: x509_cert_key_constraints(4096) -KEY_AGREEMENT :: x509_cert_key_constraints(2048) -KEY_CERT_SIGN :: x509_cert_key_constraints(1024) -CRL_SIGN :: x509_cert_key_constraints(512) -ENCIPHER_ONLY :: x509_cert_key_constraints(256) -DECIPHER_ONLY :: x509_cert_key_constraints(128) - -HASH_SHA1 :: "SHA1" -HASH_SHA_224 :: "SHA-224" -HASH_SHA_256 :: "SHA-256" -HASH_SHA_384 :: "SHA-384" -HASH_SHA_512 :: "SHA-512" -HASH_SHA3_224 :: "SHA-3(224)" -HASH_SHA3_256 :: "SHA-3(256)" -HASH_SHA3_384 :: "SHA-3(384)" -HASH_SHA3_512 :: "SHA-3(512)" -HASH_SHAKE_128 :: "SHAKE-128" -HASH_SHAKE_256 :: "SHAKE-256" -HASH_KECCAK_224 :: "KECCAK(224)" -HASH_KECCAK_256 :: "KECCAK(256)" -HASH_KECCAK_384 :: "KECCAK(384)" -HASH_KECCAK_512 :: "KECCAK(512)" -HASH_RIPEMD_160 :: "RIPEMD-160" -HASH_WHIRLPOOL :: "Whirlpool" -HASH_BLAKE2B :: "BLAKE2b" -HASH_MD4 :: "MD4" -HASH_MD5 :: "MD5" -HASH_TIGER_128 :: "Tiger(16,3)" -HASH_TIGER_160 :: "Tiger(20,3)" -HASH_TIGER_192 :: "Tiger(24,3)" -HASH_GOST :: "GOST-34.11" -HASH_STREEBOG_256 :: "Streebog-256" -HASH_STREEBOG_512 :: "Streebog-512" -HASH_SM3 :: "SM3" -HASH_SKEIN_512_256 :: "Skein-512(256)" -HASH_SKEIN_512_512 :: "Skein-512(512)" -HASH_SKEIN_512_1024 :: "Skein-512(1024)" - -// Not real values from Botan, only used for context setup within the crypto lib -HASH_SHA2 :: "SHA2" -HASH_SHA3 :: "SHA3" -HASH_SHAKE :: "SHAKE" -HASH_KECCAK :: "KECCAK" -HASH_STREEBOG :: "STREEBOG" -HASH_TIGER :: "TIGER" -HASH_SKEIN_512 :: "SKEIN_512" - -MAC_HMAC_SHA1 :: "HMAC(SHA1)" -MAC_HMAC_SHA_224 :: "HMAC(SHA-224)" -MAC_HMAC_SHA_256 :: "HMAC(SHA-256)" -MAC_HMAC_SHA_384 :: "HMAC(SHA-384)" -MAC_HMAC_SHA_512 :: "HMAC(SHA-512)" -MAC_HMAC_MD5 :: "HMAC(MD5)" - -hash_struct :: struct{} -hash_t :: ^hash_struct -rng_struct :: struct{} -rng_t :: ^rng_struct -mac_struct :: struct{} -mac_t :: ^mac_struct -cipher_struct :: struct{} -cipher_t :: ^cipher_struct -block_cipher_struct :: struct{} -block_cipher_t :: ^block_cipher_struct -mp_struct :: struct{} -mp_t :: ^mp_struct -privkey_struct :: struct{} -privkey_t :: ^privkey_struct -pubkey_struct :: struct{} -pubkey_t :: ^pubkey_struct -pk_op_encrypt_struct :: struct{} -pk_op_encrypt_t :: ^pk_op_encrypt_struct -pk_op_decrypt_struct :: struct{} -pk_op_decrypt_t :: ^pk_op_decrypt_struct -pk_op_sign_struct :: struct{} -pk_op_sign_t :: ^pk_op_sign_struct -pk_op_verify_struct :: struct{} -pk_op_verify_t :: ^pk_op_verify_struct -pk_op_ka_struct :: struct{} -pk_op_ka_t :: ^pk_op_ka_struct -x509_cert_struct :: struct{} -x509_cert_t :: ^x509_cert_struct -x509_crl_struct :: struct{} -x509_crl_t :: ^x509_crl_struct -hotp_struct :: struct{} -hotp_t :: ^hotp_struct -totp_struct :: struct{} -totp_t :: ^totp_struct -fpe_struct :: struct{} -fpe_t :: ^fpe_struct - -when ODIN_OS == "windows" { - foreign import botan_lib "botan.lib" -} else when ODIN_OS == "linux" { - foreign import botan_lib "system:botan-2" -} else when ODIN_OS == "darwin" { - foreign import botan_lib "system:botan-2" -} - -@(default_calling_convention="c") -@(link_prefix="botan_") -foreign botan_lib { - error_description :: proc(err: c.int) -> cstring --- - ffi_api_version :: proc() -> c.int --- - ffi_supports_api :: proc(api_version: c.int) -> c.int --- - version_string :: proc() -> cstring --- - version_major :: proc() -> c.int --- - version_minor :: proc() -> c.int --- - version_patch :: proc() -> c.int --- - version_datestamp :: proc() -> c.int --- - - constant_time_compare :: proc(x, y: ^c.char, length: c.size_t) -> c.int --- - same_mem :: proc(x, y: ^c.char, length: c.size_t) -> c.int --- - scrub_mem :: proc(mem: rawptr, bytes: c.size_t) -> c.int --- - - hex_encode :: proc(x: ^c.char, length: c.size_t, out: ^c.char, flags: c.uint) -> c.int --- - hex_decode :: proc(hex_str: cstring, in_len: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- - - base64_encode :: proc(x: ^c.char, length: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- - base64_decode :: proc(base64_str: cstring, in_len: c.size_t, out: ^c.char, out_len: c.size_t) -> c.int --- - - rng_init :: proc(rng: ^rng_t, rng_type: cstring) -> c.int --- - rng_init_custom :: proc(rng_out: ^rng_t, rng_name: cstring, ctx: rawptr, - get_cb: proc(ctx: rawptr, out: ^c.char, out_len: c.size_t) -> ^c.int, - add_entropy_cb: proc(ctx: rawptr, input: ^c.char, length: c.size_t) -> ^c.int, - destroy_cb: proc(ctx: rawptr) -> rawptr) -> c.int --- - rng_get :: proc(rng: rng_t, out: ^c.char, out_len: c.size_t) -> c.int --- - rng_reseed :: proc(rng: rng_t, bits: c.size_t) -> c.int --- - rng_reseed_from_rng :: proc(rng, source_rng: rng_t, bits: c.size_t) -> c.int --- - rng_add_entropy :: proc(rng: rng_t, entropy: ^c.char, entropy_len: c.size_t) -> c.int --- - rng_destroy :: proc(rng: rng_t) -> c.int --- - - hash_init :: proc(hash: ^hash_t, hash_name: cstring, flags: c.uint) -> c.int --- - hash_copy_state :: proc(dest: ^hash_t, source: hash_t) -> c.int --- - hash_output_length :: proc(hash: hash_t, output_length: ^c.size_t) -> c.int --- - hash_block_size :: proc(hash: hash_t, block_size: ^c.size_t) -> c.int --- - hash_update :: proc(hash: hash_t, input: ^c.char, input_len: c.size_t) -> c.int --- - hash_final :: proc(hash: hash_t, out: ^c.char) -> c.int --- - hash_clear :: proc(hash: hash_t) -> c.int --- - hash_destroy :: proc(hash: hash_t) -> c.int --- - hash_name :: proc(hash: hash_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- - - mac_init :: proc(mac: ^mac_t, hash_name: cstring, flags: c.uint) -> c.int --- - mac_output_length :: proc(mac: mac_t, output_length: ^c.size_t) -> c.int --- - mac_set_key :: proc(mac: mac_t, key: ^c.char, key_len: c.size_t) -> c.int --- - mac_update :: proc(mac: mac_t, buf: ^c.char, length: c.size_t) -> c.int --- - mac_final :: proc(mac: mac_t, out: ^c.char) -> c.int --- - mac_clear :: proc(mac: mac_t) -> c.int --- - mac_name :: proc(mac: mac_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- - mac_get_keyspec :: proc(mac: mac_t, out_minimum_keylength, out_maximum_keylength, out_keylength_modulo: ^c.size_t) -> c.int --- - mac_destroy :: proc(mac: mac_t) -> c.int --- - - cipher_init :: proc(cipher: ^cipher_t, name: cstring, flags: c.uint) -> c.int --- - cipher_name :: proc(cipher: cipher_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- - cipher_output_length :: proc(cipher: cipher_t, output_length: ^c.size_t) -> c.int --- - cipher_valid_nonce_length :: proc(cipher: cipher_t, nl: c.size_t) -> c.int --- - cipher_get_tag_length :: proc(cipher: cipher_t, tag_size: ^c.size_t) -> c.int --- - cipher_get_default_nonce_length :: proc(cipher: cipher_t, nl: ^c.size_t) -> c.int --- - cipher_get_update_granularity :: proc(cipher: cipher_t, ug: ^c.size_t) -> c.int --- - cipher_query_keylen :: proc(cipher: cipher_t, out_minimum_keylength, out_maximum_keylength: ^c.size_t) -> c.int --- - cipher_get_keyspec :: proc(cipher: cipher_t, min_keylen, max_keylen, mod_keylen: ^c.size_t) -> c.int --- - cipher_set_key :: proc(cipher: cipher_t, key: ^c.char, key_len: c.size_t) -> c.int --- - cipher_reset :: proc(cipher: cipher_t) -> c.int --- - cipher_set_associated_data :: proc(cipher: cipher_t, ad: ^c.char, ad_len: c.size_t) -> c.int --- - cipher_start :: proc(cipher: cipher_t, nonce: ^c.char, nonce_len: c.size_t) -> c.int --- - cipher_update :: proc(cipher: cipher_t, flags: c.uint, output: ^c.char, output_size: c.size_t, output_written: ^c.size_t, - input_bytes: ^c.char, input_size: c.size_t, input_consumed: ^c.size_t) -> c.int --- - cipher_clear :: proc(hash: cipher_t) -> c.int --- - cipher_destroy :: proc(cipher: cipher_t) -> c.int --- - - @(deprecated="Use botan.pwdhash") - pbkdf :: proc(pbkdf_algo: cstring, out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, - salt_len, iterations: c.size_t) -> c.int --- - @(deprecated="Use botan.pwdhash_timed") - pbkdf_timed :: proc(pbkdf_algo: cstring, out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, - salt_len, milliseconds_to_run: c.size_t, out_iterations_used: ^c.size_t) -> c.int --- - pwdhash :: proc(algo: cstring, param1, param2, param3: c.size_t, out: ^c.char, out_len: c.size_t, passphrase: cstring, - passphrase_len: c.size_t, salt: ^c.char, salt_len: c.size_t) -> c.int --- - pwdhash_timed :: proc(algo: cstring, msec: c.uint, param1, param2, param3: c.size_t, out: ^c.char, out_len: c.size_t, - passphrase: cstring, passphrase_len: c.size_t, salt: ^c.char, salt_len: c.size_t) -> c.int --- - @(deprecated="Use botan.pwdhash") - scrypt :: proc(out: ^c.char, out_len: c.size_t, passphrase: cstring, salt: ^c.char, salt_len, N, r, p: c.size_t) -> c.int --- - kdf :: proc(kdf_algo: cstring, out: ^c.char, out_len: c.size_t, secret: ^c.char, secret_lent: c.size_t, salt: ^c.char, - salt_len: c.size_t, label: ^c.char, label_len: c.size_t) -> c.int --- - - block_cipher_init :: proc(bc: ^block_cipher_t, name: cstring) -> c.int --- - block_cipher_destroy :: proc(bc: block_cipher_t) -> c.int --- - block_cipher_clear :: proc(bc: block_cipher_t) -> c.int --- - block_cipher_set_key :: proc(bc: block_cipher_t, key: ^c.char, key_len: c.size_t) -> c.int --- - block_cipher_block_size :: proc(bc: block_cipher_t) -> c.int --- - block_cipher_encrypt_blocks :: proc(bc: block_cipher_t, input, out: ^c.char, blocks: c.size_t) -> c.int --- - block_cipher_decrypt_blocks :: proc(bc: block_cipher_t, input, out: ^c.char, blocks: c.size_t) -> c.int --- - block_cipher_name :: proc(bc: block_cipher_t, name: ^c.char, name_len: ^c.size_t) -> c.int --- - block_cipher_get_keyspec :: proc(bc: block_cipher_t, out_minimum_keylength, out_maximum_keylength, out_keylength_modulo: ^c.size_t) -> c.int --- - - mp_init :: proc(mp: ^mp_t) -> c.int --- - mp_destroy :: proc(mp: mp_t) -> c.int --- - mp_to_hex :: proc(mp: mp_t, out: ^c.char) -> c.int --- - mp_to_str :: proc(mp: mp_t, base: c.char, out: ^c.char, out_len: ^c.size_t) -> c.int --- - mp_clear :: proc(mp: mp_t) -> c.int --- - mp_set_from_int :: proc(mp: mp_t, initial_value: c.int) -> c.int --- - mp_set_from_mp :: proc(dest, source: mp_t) -> c.int --- - mp_set_from_str :: proc(dest: mp_t, str: cstring) -> c.int --- - mp_set_from_radix_str :: proc(mp: mp_t, str: cstring, radix: c.size_t) -> c.int --- - mp_num_bits :: proc(n: mp_t, bits: ^c.size_t) -> c.int --- - mp_num_bytes :: proc(n: mp_t, bytes: ^c.size_t) -> c.int --- - mp_to_bin :: proc(mp: mp_t, vec: ^c.char) -> c.int --- - mp_from_bin :: proc(mp: mp_t, vec: ^c.char, vec_len: c.size_t) -> c.int --- - mp_to_uint32 :: proc(mp: mp_t, val: ^c.uint) -> c.int --- - mp_is_positive :: proc(mp: mp_t) -> c.int --- - mp_is_negative :: proc(mp: mp_t) -> c.int --- - mp_flip_sign :: proc(mp: mp_t) -> c.int --- - mp_is_zero :: proc(mp: mp_t) -> c.int --- - @(deprecated="Use botan.mp_get_bit(0)") - mp_is_odd :: proc(mp: mp_t) -> c.int --- - @(deprecated="Use botan.mp_get_bit(0)") - mp_is_even :: proc(mp: mp_t) -> c.int --- - mp_add_u32 :: proc(result, x: mp_t, y: c.uint) -> c.int --- - mp_sub_u32 :: proc(result, x: mp_t, y: c.uint) -> c.int --- - mp_add :: proc(result, x, y: mp_t) -> c.int --- - mp_sub :: proc(result, x, y: mp_t) -> c.int --- - mp_mul :: proc(result, x, y: mp_t) -> c.int --- - mp_div :: proc(quotient, remainder, x, y: mp_t) -> c.int --- - mp_mod_mul :: proc(result, x, y, mod: mp_t) -> c.int --- - mp_equal :: proc(x, y: mp_t) -> c.int --- - mp_cmp :: proc(result: ^c.int, x, y: mp_t) -> c.int --- - mp_swap :: proc(x, y: mp_t) -> c.int --- - mp_powmod :: proc(out, base, exponent, modulus: mp_t) -> c.int --- - mp_lshift :: proc(out, input: mp_t, shift: c.size_t) -> c.int --- - mp_rshift :: proc(out, input: mp_t, shift: c.size_t) -> c.int --- - mp_mod_inverse :: proc(out, input, modulus: mp_t) -> c.int --- - mp_rand_bits :: proc(rand_out: mp_t, rng: rng_t, bits: c.size_t) -> c.int --- - mp_rand_range :: proc(rand_out: mp_t, rng: rng_t, lower_bound, upper_bound: mp_t) -> c.int --- - mp_gcd :: proc(out, x, y: mp_t) -> c.int --- - mp_is_prime :: proc(n: mp_t, rng: rng_t, test_prob: c.size_t) -> c.int --- - mp_get_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- - mp_set_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- - mp_clear_bit :: proc(n: mp_t, bit: c.size_t) -> c.int --- - - bcrypt_generate :: proc(out: ^c.char, out_len: ^c.size_t, password: cstring, rng: rng_t, work_factor: c.size_t, flags: c.uint) -> c.int --- - bcrypt_is_valid :: proc(pass, hash: cstring) -> c.int --- - - privkey_create :: proc(key: ^privkey_t, algo_name, algo_params: cstring, rng: rng_t) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_check_key :: proc(key: privkey_t, rng: rng_t, flags: c.uint) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_create_rsa :: proc(key: ^privkey_t, rng: rng_t, bits: c.size_t) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_create_ecdsa :: proc(key: ^privkey_t, rng: rng_t, params: cstring) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_create_ecdh :: proc(key: ^privkey_t, rng: rng_t, params: cstring) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_create_mceliece :: proc(key: ^privkey_t, rng: rng_t, n, t: c.size_t) -> c.int --- - @(deprecated="Use botan.privkey_create") - privkey_create_dh :: proc(key: ^privkey_t, rng: rng_t, param: cstring) -> c.int --- - privkey_create_dsa :: proc(key: ^privkey_t, rng: rng_t, pbits, qbits: c.size_t) -> c.int --- - privkey_create_elgamal :: proc(key: ^privkey_t, rng: rng_t, pbits, qbits: c.size_t) -> c.int --- - privkey_load :: proc(key: ^privkey_t, rng: rng_t, bits: ^c.char, length: c.size_t, password: cstring) -> c.int --- - privkey_destroy :: proc(key: privkey_t) -> c.int --- - privkey_export :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- - privkey_algo_name :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - @(deprecated="Use botan.privkey_export_encrypted_pbkdf_{msec,iter}") - privkey_export_encrypted :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase, encryption_algo: cstring, flags: c.uint) -> c.int --- - privkey_export_encrypted_pbkdf_msec :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase: cstring, pbkdf_msec_runtime: c.uint, - pbkdf_iterations_out: ^c.size_t, cipher_algo, pbkdf_algo: cstring, flags: c.uint) -> c.int --- - privkey_export_encrypted_pbkdf_iter :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t, rng: rng_t, passphrase: cstring, pbkdf_iterations: c.size_t, - cipher_algo, pbkdf_algo: cstring, flags: c.uint) -> c.int --- - pubkey_load :: proc(key: ^pubkey_t, bits: ^c.char, length: c.size_t) -> c.int --- - privkey_export_pubkey :: proc(out: ^pubkey_t, input: privkey_t) -> c.int --- - pubkey_export :: proc(key: pubkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- - pubkey_algo_name :: proc(key: pubkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - pubkey_check_key :: proc(key: pubkey_t, rng: rng_t, flags: c.uint) -> c.int --- - pubkey_estimated_strength :: proc(key: pubkey_t, estimate: ^c.size_t) -> c.int --- - pubkey_fingerprint :: proc(key: pubkey_t, hash: cstring, out: ^c.char, out_len: ^c.size_t) -> c.int --- - pubkey_destroy :: proc(key: pubkey_t) -> c.int --- - pubkey_get_field :: proc(output: mp_t, key: pubkey_t, field_name: cstring) -> c.int --- - privkey_get_field :: proc(output: mp_t, key: privkey_t, field_name: cstring) -> c.int --- - - privkey_load_rsa :: proc(key: ^privkey_t, p, q, e: mp_t) -> c.int --- - privkey_load_rsa_pkcs1 :: proc(key: ^privkey_t, bits: ^c.char, length: c.size_t) -> c.int --- - @(deprecated="Use botan.privkey_get_field") - privkey_rsa_get_p :: proc(p: mp_t, rsa_key: privkey_t) -> c.int --- - @(deprecated="Use botan.privkey_get_field") - privkey_rsa_get_q :: proc(q: mp_t, rsa_key: privkey_t) -> c.int --- - @(deprecated="Use botan.privkey_get_field") - privkey_rsa_get_d :: proc(d: mp_t, rsa_key: privkey_t) -> c.int --- - @(deprecated="Use botan.privkey_get_field") - privkey_rsa_get_n :: proc(n: mp_t, rsa_key: privkey_t) -> c.int --- - @(deprecated="Use botan.privkey_get_field") - privkey_rsa_get_e :: proc(e: mp_t, rsa_key: privkey_t) -> c.int --- - privkey_rsa_get_privkey :: proc(rsa_key: privkey_t, out: ^c.char, out_len: ^c.size_t, flags: c.uint) -> c.int --- - pubkey_load_rsa :: proc(key: ^pubkey_t, n, e: mp_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_rsa_get_e :: proc(e: mp_t, rsa_key: pubkey_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_rsa_get_n :: proc(n: mp_t, rsa_key: pubkey_t) -> c.int --- - - privkey_load_dsa :: proc(key: ^privkey_t, p, q, g, x: mp_t) -> c.int --- - pubkey_load_dsa :: proc(key: ^pubkey_t, p, q, g, y: mp_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - privkey_dsa_get_x :: proc(n: mp_t, key: privkey_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_dsa_get_p :: proc(p: mp_t, key: pubkey_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_dsa_get_q :: proc(q: mp_t, key: pubkey_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_dsa_get_g :: proc(d: mp_t, key: pubkey_t) -> c.int --- - @(deprecated="Use botan.pubkey_get_field") - pubkey_dsa_get_y :: proc(y: mp_t, key: pubkey_t) -> c.int --- - - privkey_load_dh :: proc(key: ^privkey_t, p, g, y: mp_t) -> c.int --- - pubkey_load_dh :: proc(key: ^pubkey_t, p, g, x: mp_t) -> c.int --- - - privkey_load_elgamal :: proc(key: ^privkey_t, p, g, y: mp_t) -> c.int --- - pubkey_load_elgamal :: proc(key: ^pubkey_t, p, g, x: mp_t) -> c.int --- - - privkey_load_ed25519 :: proc(key: ^privkey_t, privkey: [32]c.char) -> c.int --- - pubkey_load_ed25519 :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- - privkey_ed25519_get_privkey :: proc(key: ^privkey_t, output: [64]c.char) -> c.int --- - pubkey_ed25519_get_pubkey :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- - - privkey_load_x25519 :: proc(key: ^privkey_t, privkey: [32]c.char) -> c.int --- - pubkey_load_x25519 :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- - privkey_x25519_get_privkey :: proc(key: ^privkey_t, output: [32]c.char) -> c.int --- - pubkey_x25519_get_pubkey :: proc(key: ^pubkey_t, pubkey: [32]c.char) -> c.int --- - - privkey_load_ecdsa :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- - pubkey_load_ecdsa :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- - pubkey_load_ecdh :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- - privkey_load_ecdh :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- - pubkey_load_sm2 :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- - privkey_load_sm2 :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- - @(deprecated="Use botan.pubkey_load_sm2") - pubkey_load_sm2_enc :: proc(key: ^pubkey_t, public_x, public_y: mp_t, curve_name: cstring) -> c.int --- - @(deprecated="Use botan.privkey_load_sm2") - privkey_load_sm2_enc :: proc(key: ^privkey_t, scalar: mp_t, curve_name: cstring) -> c.int --- - pubkey_sm2_compute_za :: proc(out: ^c.char, out_len: ^c.size_t, ident, hash_algo: cstring, key: pubkey_t) -> c.int --- - - pk_op_encrypt_create :: proc(op: ^pk_op_encrypt_t, key: pubkey_t, padding: cstring, flags: c.uint) -> c.int --- - pk_op_encrypt_destroy :: proc(op: pk_op_encrypt_t) -> c.int --- - pk_op_encrypt_output_length :: proc(op: pk_op_encrypt_t, ptext_len: c.size_t, ctext_len: ^c.size_t) -> c.int --- - pk_op_encrypt :: proc(op: pk_op_encrypt_t, rng: rng_t, out: ^c.char, out_len: ^c.size_t, plaintext: cstring, plaintext_len: c.size_t) -> c.int --- - - pk_op_decrypt_create :: proc(op: ^pk_op_decrypt_t, key: privkey_t, padding: cstring, flags: c.uint) -> c.int --- - pk_op_decrypt_destroy :: proc(op: pk_op_decrypt_t) -> c.int --- - pk_op_decrypt_output_length :: proc(op: pk_op_decrypt_t, ptext_len: c.size_t, ctext_len: ^c.size_t) -> c.int --- - pk_op_decrypt :: proc(op: pk_op_decrypt_t, rng: rng_t, out: ^c.char, out_len: ^c.size_t, ciphertext: cstring, ciphertext_len: c.size_t) -> c.int --- - - pk_op_sign_create :: proc(op: ^pk_op_sign_t, key: privkey_t, hash_and_padding: cstring, flags: c.uint) -> c.int --- - pk_op_sign_destroy :: proc(op: pk_op_sign_t) -> c.int --- - pk_op_sign_output_length :: proc(op: pk_op_sign_t, olen: ^c.size_t) -> c.int --- - pk_op_sign_update :: proc(op: pk_op_sign_t, input: ^c.char, input_len: c.size_t) -> c.int --- - pk_op_sign_finish :: proc(op: pk_op_sign_t, rng: rng_t, sig: ^c.char, sig_len: ^c.size_t) -> c.int --- - - pk_op_verify_create :: proc(op: ^pk_op_verify_t, hash_and_padding: cstring, flags: c.uint) -> c.int --- - pk_op_verify_destroy :: proc(op: pk_op_verify_t) -> c.int --- - pk_op_verify_update :: proc(op: pk_op_verify_t, input: ^c.char, input_len: c.size_t) -> c.int --- - pk_op_verify_finish :: proc(op: pk_op_verify_t, sig: ^c.char, sig_len: c.size_t) -> c.int --- - - pk_op_key_agreement_create :: proc(op: ^pk_op_ka_t, kdf: cstring, flags: c.uint) -> c.int --- - pk_op_key_agreement_destroy :: proc(op: pk_op_ka_t) -> c.int --- - pk_op_key_agreement_export_public :: proc(key: privkey_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - pk_op_key_agreement_size :: proc(op: pk_op_ka_t, out_len: ^c.size_t) -> c.int --- - pk_op_key_agreement :: proc(op: pk_op_ka_t, out: ^c.char, out_len: ^c.size_t, other_key: ^c.char, other_key_len: c.size_t, salt: ^c.char, - salt_len: c.size_t) -> c.int --- - - pkcs_hash_id :: proc(hash_name: cstring, pkcs_id: ^c.char, pkcs_id_len: ^c.size_t) -> c.int --- - - @(deprecated="Poorly specified, avoid in new code") - mceies_encrypt :: proc(mce_key: pubkey_t, rng: rng_t, aead: cstring, pt: ^c.char, pt_len: c.size_t, ad: ^c.char, ad_len: c.size_t, - ct: ^c.char, ct_len: ^c.size_t) -> c.int --- - @(deprecated="Poorly specified, avoid in new code") - mceies_decrypt :: proc(mce_key: privkey_t, aead: cstring, ct: ^c.char, ct_len: c.size_t, ad: ^c.char, ad_len: c.size_t, pt: ^c.char, - pt_len: ^c.size_t) -> c.int --- - - x509_cert_load :: proc(cert_obj: ^x509_cert_t, cert: ^c.char, cert_len: c.size_t) -> c.int --- - x509_cert_load_file :: proc(cert_obj: ^x509_cert_t, filename: cstring) -> c.int --- - x509_cert_destroy :: proc(cert: x509_cert_t) -> c.int --- - x509_cert_dup :: proc(new_cert: ^x509_cert_t, cert: x509_cert_t) -> c.int --- - x509_cert_get_time_starts :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_time_expires :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_not_before :: proc(cert: x509_cert_t, time_since_epoch: ^c.ulonglong) -> c.int --- - x509_cert_not_after :: proc(cert: x509_cert_t, time_since_epoch: ^c.ulonglong) -> c.int --- - x509_cert_get_fingerprint :: proc(cert: x509_cert_t, hash: cstring, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_serial_number :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_authority_key_id :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_subject_key_id :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_public_key_bits :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_public_key :: proc(cert: x509_cert_t, key: ^pubkey_t) -> c.int --- - x509_cert_get_issuer_dn :: proc(cert: x509_cert_t, key: ^c.char, index: c.size_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_get_subject_dn :: proc(cert: x509_cert_t, key: ^c.char, index: c.size_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_to_string :: proc(cert: x509_cert_t, out: ^c.char, out_len: ^c.size_t) -> c.int --- - x509_cert_allowed_usage :: proc(cert: x509_cert_t, key_usage: c.uint) -> c.int --- - x509_cert_hostname_match :: proc(cert: x509_cert_t, hostname: cstring) -> c.int --- - x509_cert_verify :: proc(validation_result: ^c.int, cert: x509_cert_t, intermediates: ^x509_cert_t, intermediates_len: c.size_t, trusted: ^x509_cert_t, - trusted_len: c.size_t, trusted_path: cstring, required_strength: c.size_t, hostname: cstring, reference_time: c.ulonglong) -> c.int --- - x509_cert_validation_status :: proc(code: c.int) -> cstring --- - x509_crl_load_file :: proc(crl_obj: ^x509_crl_t, crl_path: cstring) -> c.int --- - x509_crl_load :: proc(crl_obj: ^x509_crl_t, crl_bits: ^c.char, crl_bits_len: c.size_t) -> c.int --- - x509_crl_destroy :: proc(crl: x509_crl_t) -> c.int --- - x509_is_revoked :: proc(crl: x509_crl_t, cert: x509_cert_t) -> c.int --- - x509_cert_verify_with_crl :: proc(validation_result: ^c.int, cert: x509_cert_t, intermediates: ^x509_cert_t, intermediates_len: c.size_t, trusted: ^x509_cert_t, - trusted_len: c.size_t, crls: ^x509_crl_t, crls_len: c.size_t, trusted_path: cstring, required_strength: c.size_t, - hostname: cstring, reference_time: c.ulonglong) -> c.int --- - - key_wrap3394 :: proc(key: ^c.char, key_len: c.size_t, kek: ^c.char, kek_len: c.size_t, wrapped_key: ^c.char, wrapped_key_len: ^c.size_t) -> c.int --- - key_unwrap3394 :: proc(wrapped_key: ^c.char, wrapped_key_len: c.size_t, kek: ^c.char, kek_len: c.size_t, key: ^c.char, key_len: ^c.size_t) -> c.int --- - - hotp_init :: proc(hotp: ^hotp_t, key: ^c.char, key_len: c.size_t, hash_algo: cstring, digits: c.size_t) -> c.int --- - hotp_destroy :: proc(hotp: hotp_t) -> c.int --- - hotp_generate :: proc(hotp: hotp_t, hotp_code: ^c.uint, hotp_counter: c.ulonglong) -> c.int --- - hotp_check :: proc(hotp: hotp_t, next_hotp_counter: ^c.ulonglong, hotp_code: c.uint, hotp_counter: c.ulonglong, resync_range: c.size_t) -> c.int --- - - totp_init :: proc(totp: ^totp_t, key: ^c.char, key_len: c.size_t, hash_algo: cstring, digits, time_step: c.size_t) -> c.int --- - totp_destroy :: proc(totp: totp_t) -> c.int --- - totp_generate :: proc(totp: totp_t, totp_code: ^c.uint, timestamp: c.ulonglong) -> c.int --- - totp_check :: proc(totp: totp_t, totp_code: ^c.uint, timestamp: c.ulonglong, acceptable_clock_drift: c.size_t) -> c.int --- - - fpe_fe1_init :: proc(fpe: ^fpe_t, n: mp_t, key: ^c.char, key_len, rounds: c.size_t, flags: c.uint) -> c.int --- - fpe_destroy :: proc(fpe: fpe_t) -> c.int --- - fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- - fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int --- -} \ No newline at end of file diff --git a/core/crypto/botan/hash.odin b/core/crypto/botan/hash.odin deleted file mode 100644 index a06377927..000000000 --- a/core/crypto/botan/hash.odin +++ /dev/null @@ -1,498 +0,0 @@ -package botan - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog: Initial creation and testing of the bindings. - - Implementation of the context for the Botan side. -*/ - -import "core:os" -import "core:io" -import "core:fmt" -import "core:strings" - -import "../_ctx" - -hash_bytes_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._16, 16), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._20, 20), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { - hash: [24]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._24, 24), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._28, 28), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._32, 32), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._48, 48), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._64, 64), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [128]byte { - hash: [128]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._128, 128), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash -} - -hash_bytes_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - hash := make([]byte, bit_size, allocator) - c: hash_t - hash_init(&c, _check_ctx(ctx, nil, bit_size), 0) - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - hash_final(c, &hash[0]) - hash_destroy(c) - return hash[:] -} - -hash_file_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_16(ctx, buf[:]), ok - } - } - return [16]byte{}, false -} - -hash_file_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_20(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_20(ctx, buf[:]), ok - } - } - return [20]byte{}, false -} - -hash_file_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - if !load_at_once { - return hash_stream_24(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_24(ctx, buf[:]), ok - } - } - return [24]byte{}, false -} - -hash_file_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_28(ctx, buf[:]), ok - } - } - return [28]byte{}, false -} - -hash_file_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_file_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_file_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -hash_file_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([128]byte, bool) { - if !load_at_once { - return hash_stream_128(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_128(ctx, buf[:]), ok - } - } - return [128]byte{}, false -} - -hash_file_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - if !load_at_once { - return hash_stream_slice(ctx, os.stream_from_handle(hd), bit_size, allocator) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_slice(ctx, buf[:], bit_size, allocator), ok - } - } - return nil, false -} - -hash_stream_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._16, 16), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._20, 20), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._24, 24), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._28, 28), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._32, 32), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._48, 48), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._64, 64), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_128 :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream) -> ([128]byte, bool) { - hash: [128]byte - c: hash_t - hash_init(&c, _check_ctx(ctx, _ctx.Hash_Size._128, 128), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash, true -} - -hash_stream_slice :: #force_inline proc(ctx: ^_ctx.Hash_Context, s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - hash := make([]byte, bit_size, allocator) - c: hash_t - hash_init(&c, _check_ctx(ctx, nil, bit_size), 0) - buf := make([]byte, 512) - defer delete(buf) - i := 1 - for i > 0 { - i, _ = s->impl_read(buf) - if i > 0 { - hash_update(c, len(buf) == 0 ? nil : &buf[0], uint(i)) - } - } - hash_final(c, &hash[0]) - hash_destroy(c) - return hash[:], true -} - -init :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - c: hash_t - hash_init(&c, ctx.botan_hash_algo, 0) - ctx.external_ctx = c -} - -update :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.external_ctx.(hash_t); ok { - hash_update(c, len(data) == 0 ? nil : &data[0], uint(len(data))) - } -} - -final :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.external_ctx.(hash_t); ok { - hash_final(c, &hash[0]) - hash_destroy(c) - } -} - -assign_hash_vtable :: proc(ctx: ^_ctx.Hash_Context, hash_algo: cstring) { - ctx.init = init - ctx.update = update - ctx.final = final - ctx.botan_hash_algo = hash_algo - - switch hash_algo { - case HASH_MD4, HASH_MD5: - ctx.hash_bytes_16 = hash_bytes_16 - ctx.hash_file_16 = hash_file_16 - ctx.hash_stream_16 = hash_stream_16 - - case HASH_SHA1, HASH_RIPEMD_160: - ctx.hash_bytes_20 = hash_bytes_20 - ctx.hash_file_20 = hash_file_20 - ctx.hash_stream_20 = hash_stream_20 - - case HASH_SHA2, HASH_SHA3: - ctx.hash_bytes_28 = hash_bytes_28 - ctx.hash_file_28 = hash_file_28 - ctx.hash_stream_28 = hash_stream_28 - ctx.hash_bytes_32 = hash_bytes_32 - ctx.hash_file_32 = hash_file_32 - ctx.hash_stream_32 = hash_stream_32 - ctx.hash_bytes_48 = hash_bytes_48 - ctx.hash_file_48 = hash_file_48 - ctx.hash_stream_48 = hash_stream_48 - ctx.hash_bytes_64 = hash_bytes_64 - ctx.hash_file_64 = hash_file_64 - ctx.hash_stream_64 = hash_stream_64 - - case HASH_GOST, HASH_WHIRLPOOL, HASH_SM3: - ctx.hash_bytes_32 = hash_bytes_32 - ctx.hash_file_32 = hash_file_32 - ctx.hash_stream_32 = hash_stream_32 - - case HASH_STREEBOG: - ctx.hash_bytes_32 = hash_bytes_32 - ctx.hash_file_32 = hash_file_32 - ctx.hash_stream_32 = hash_stream_32 - ctx.hash_bytes_64 = hash_bytes_64 - ctx.hash_file_64 = hash_file_64 - ctx.hash_stream_64 = hash_stream_64 - - case HASH_BLAKE2B: - ctx.hash_bytes_64 = hash_bytes_64 - ctx.hash_file_64 = hash_file_64 - ctx.hash_stream_64 = hash_stream_64 - - case HASH_TIGER: - ctx.hash_bytes_16 = hash_bytes_16 - ctx.hash_file_16 = hash_file_16 - ctx.hash_stream_16 = hash_stream_16 - ctx.hash_bytes_20 = hash_bytes_20 - ctx.hash_file_20 = hash_file_20 - ctx.hash_stream_20 = hash_stream_20 - ctx.hash_bytes_24 = hash_bytes_24 - ctx.hash_file_24 = hash_file_24 - ctx.hash_stream_24 = hash_stream_24 - - case HASH_SKEIN_512: - ctx.hash_bytes_slice = hash_bytes_slice - ctx.hash_file_slice = hash_file_slice - ctx.hash_stream_slice = hash_stream_slice - } -} - -_check_ctx :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash_size: _ctx.Hash_Size, hash_size_val: int) -> cstring { - ctx.hash_size = hash_size - ctx.hash_size_val = hash_size_val - switch ctx.botan_hash_algo { - case HASH_SHA2: - #partial switch hash_size { - case ._28: return HASH_SHA_224 - case ._32: return HASH_SHA_256 - case ._48: return HASH_SHA_384 - case ._64: return HASH_SHA_512 - } - case HASH_SHA3: - #partial switch hash_size { - case ._28: return HASH_SHA3_224 - case ._32: return HASH_SHA3_256 - case ._48: return HASH_SHA3_384 - case ._64: return HASH_SHA3_512 - } - case HASH_KECCAK: - #partial switch hash_size { - case ._28: return HASH_KECCAK_224 - case ._32: return HASH_KECCAK_256 - case ._48: return HASH_KECCAK_384 - case ._64: return HASH_KECCAK_512 - } - case HASH_STREEBOG: - #partial switch hash_size { - case ._32: return HASH_STREEBOG_256 - case ._64: return HASH_STREEBOG_512 - } - case HASH_TIGER: - #partial switch hash_size { - case ._16: return HASH_TIGER_128 - case ._20: return HASH_TIGER_160 - case ._24: return HASH_TIGER_192 - } - case HASH_SKEIN_512: - return strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", hash_size_val * 8)) - case: return ctx.botan_hash_algo - } - return nil -} \ No newline at end of file diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin index 00a8fdc3d..c687e9080 100644 --- a/core/crypto/gost/gost.odin +++ b/core/crypto/gost/gost.odin @@ -6,7 +6,6 @@ package gost List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the GOST hashing algorithm, as defined in RFC 5831 */ @@ -15,42 +14,6 @@ import "core:mem" import "core:os" import "core:io" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - _assign_hash_vtable(ctx) - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_32 = hash_bytes_odin - ctx.hash_file_32 = hash_file_odin - ctx.hash_stream_32 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since MD2 is not available in Botan -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_GOST) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -64,22 +27,44 @@ hash_string :: proc(data: string) -> [32]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [32]byte { - _create_gost_ctx() - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Gost_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_gost_ctx() - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Gost_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_gost_ctx() - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [32]byte{}, false } hash :: proc { @@ -93,85 +78,77 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() -} - -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Gost_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) +init :: proc "contextless" (ctx: ^Gost_Context) { + sbox: [8][16]u32 = { + { 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 }, + { 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 }, + { 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 }, + { 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 }, + { 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 }, + { 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 }, + { 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 }, + { 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 }, } - return hash -} -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Gost_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok + i := 0 + for a := 0; a < 16; a += 1 { + ax := sbox[1][a] << 15 + bx := sbox[3][a] << 23 + cx := sbox[5][a] + cx = (cx >> 1) | (cx << 31) + dx := sbox[7][a] << 7 + for b := 0; b < 16; b, i = b + 1, i + 1 { + SBOX_1[i] = ax | (sbox[0][b] << 11) + SBOX_2[i] = bx | (sbox[2][b] << 19) + SBOX_3[i] = cx | (sbox[4][b] << 27) + SBOX_4[i] = dx | (sbox[6][b] << 3) } } - return [32]byte{}, false } -@(private) -_create_gost_ctx :: #force_inline proc() { - ctx: Gost_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._32 -} +update :: proc(ctx: ^Gost_Context, data: []byte) { + length := byte(len(data)) + j: byte -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_gost_ctx() - if c, ok := ctx.internal_ctx.(Gost_Context); ok { - init_odin(&c) + i := ctx.partial_bytes + for i < 32 && j < length { + ctx.partial[i] = data[j] + i, j = i + 1, j + 1 } -} -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Gost_Context); ok { - update_odin(&c, data) + if i < 32 { + ctx.partial_bytes = i + return } + bytes(ctx, ctx.partial[:], 256) + + for (j + 32) < length { + bytes(ctx, data[j:], 256) + j += 32 + } + + i = 0 + for j < length { + ctx.partial[i] = data[j] + i, j = i + 1, j + 1 + } + ctx.partial_bytes = i } -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Gost_Context); ok { - final_odin(&c, hash) +final :: proc(ctx: ^Gost_Context, hash: []byte) { + if ctx.partial_bytes > 0 { + mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes)) + bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3) + } + + compress(ctx.hash[:], ctx.len[:]) + compress(ctx.hash[:], ctx.sum[:]) + + for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 { + hash[j] = byte(ctx.hash[i]) + hash[j + 1] = byte(ctx.hash[i] >> 8) + hash[j + 2] = byte(ctx.hash[i] >> 16) + hash[j + 3] = byte(ctx.hash[i] >> 24) } } @@ -187,12 +164,12 @@ Gost_Context :: struct { partial_bytes: byte, } -SBOX_1 : [256]u32 -SBOX_2 : [256]u32 -SBOX_3 : [256]u32 -SBOX_4 : [256]u32 +SBOX_1: [256]u32 +SBOX_2: [256]u32 +SBOX_3: [256]u32 +SBOX_4: [256]u32 -GOST_ENCRYPT_ROUND :: #force_inline proc "contextless"(l, r, t, k1, k2: u32) -> (u32, u32, u32) { +ENCRYPT_ROUND :: #force_inline proc "contextless" (l, r, t, k1, k2: u32) -> (u32, u32, u32) { l, r, t := l, r, t t = (k1) + r l ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24] @@ -201,30 +178,30 @@ GOST_ENCRYPT_ROUND :: #force_inline proc "contextless"(l, r, t, k1, k2: u32) -> return l, r, t } -GOST_ENCRYPT :: #force_inline proc "contextless"(a, b, c: u32, key: []u32) -> (l, r, t: u32) { - l, r, t = GOST_ENCRYPT_ROUND(a, b, c, key[0], key[1]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[0], key[1]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[0], key[1]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[2], key[3]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[4], key[5]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[6], key[7]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[7], key[6]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[5], key[4]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[3], key[2]) - l, r, t = GOST_ENCRYPT_ROUND(l, r, t, key[1], key[0]) +ENCRYPT :: #force_inline proc "contextless" (a, b, c: u32, key: []u32) -> (l, r, t: u32) { + l, r, t = ENCRYPT_ROUND(a, b, c, key[0], key[1]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[7], key[6]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[5], key[4]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[3], key[2]) + l, r, t = ENCRYPT_ROUND(l, r, t, key[1], key[0]) t = r r = l l = t return } -gost_bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) { +bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) { a, c: u32 m: [8]u32 @@ -237,14 +214,14 @@ gost_bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) { c = c < a ? 1 : 0 } - gost_compress(ctx.hash[:], m[:]) + compress(ctx.hash[:], m[:]) ctx.len[0] += bits if ctx.len[0] < bits { ctx.len[1] += 1 } } -gost_compress :: proc(h, m: []u32) { +compress :: proc(h, m: []u32) { key, u, v, w, s: [8]u32 copy(u[:], h) @@ -272,7 +249,7 @@ gost_compress :: proc(h, m: []u32) { r := h[i] l := h[i + 1] t: u32 - l, r, t = GOST_ENCRYPT(l, r, 0, key[:]) + l, r, t = ENCRYPT(l, r, 0, key[:]) s[i] = r s[i + 1] = l @@ -380,78 +357,4 @@ gost_compress :: proc(h, m: []u32) { h[7] = v[0] ~ (v[0] >> 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ (v[2] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ v[4] ~ (v[5] >> 16) ~ v[5] ~ (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) ~ v[7] -} - -init_odin :: proc(ctx: ^Gost_Context) { - sbox: [8][16]u32 = { - { 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 }, - { 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 }, - { 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 }, - { 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 }, - { 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 }, - { 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 }, - { 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 }, - { 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 }, - } - - i := 0 - for a := 0; a < 16; a += 1 { - ax := sbox[1][a] << 15 - bx := sbox[3][a] << 23 - cx := sbox[5][a] - cx = (cx >> 1) | (cx << 31) - dx := sbox[7][a] << 7 - for b := 0; b < 16; b, i = b + 1, i + 1 { - SBOX_1[i] = ax | (sbox[0][b] << 11) - SBOX_2[i] = bx | (sbox[2][b] << 19) - SBOX_3[i] = cx | (sbox[4][b] << 27) - SBOX_4[i] = dx | (sbox[6][b] << 3) - } - } -} - -update_odin :: proc(ctx: ^Gost_Context, data: []byte) { - length := byte(len(data)) - j: byte - - i := ctx.partial_bytes - for i < 32 && j < length { - ctx.partial[i] = data[j] - i, j = i + 1, j + 1 - } - - if i < 32 { - ctx.partial_bytes = i - return - } - gost_bytes(ctx, ctx.partial[:], 256) - - for (j + 32) < length { - gost_bytes(ctx, data[j:], 256) - j += 32 - } - - i = 0 - for j < length { - ctx.partial[i] = data[j] - i, j = i + 1, j + 1 - } - ctx.partial_bytes = i -} - -final_odin :: proc(ctx: ^Gost_Context, hash: []byte) { - if ctx.partial_bytes > 0 { - mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes)) - gost_bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3) - } - - gost_compress(ctx.hash[:], ctx.len[:]) - gost_compress(ctx.hash[:], ctx.sum[:]) - - for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 { - hash[j] = byte(ctx.hash[i]) - hash[j + 1] = byte(ctx.hash[i] >> 8) - hash[j + 2] = byte(ctx.hash[i] >> 16) - hash[j + 3] = byte(ctx.hash[i] >> 24) - } } \ No newline at end of file diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin index d3e23dc28..0d305a1d1 100644 --- a/core/crypto/groestl/groestl.odin +++ b/core/crypto/groestl/groestl.odin @@ -6,7 +6,6 @@ package groestl List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the GROESTL hashing algorithm, as defined in */ @@ -14,70 +13,6 @@ package groestl import "core:os" import "core:io" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since GROESTL is not available in Botan -@(warning="GROESTL is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_groestl_ctx :: #force_inline proc(size: _ctx.Hash_Size) { - ctx: Groestl_Context - #partial switch size { - case ._28: ctx.hashbitlen = 224 - case ._32: ctx.hashbitlen = 256 - case ._48: ctx.hashbitlen = 384 - case ._64: ctx.hashbitlen = 512 - } - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = size -} - /* High level API */ @@ -91,22 +26,46 @@ hash_string_224 :: proc(data: string) -> [28]byte { // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_groestl_ctx(._28) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Groestl_Context + ctx.hashbitlen = 224 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_groestl_ctx(._28) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Groestl_Context + ctx.hashbitlen = 224 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_groestl_ctx(._28) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -125,22 +84,46 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_groestl_ctx(._32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Groestl_Context + ctx.hashbitlen = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_groestl_ctx(._32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Groestl_Context + ctx.hashbitlen = 256 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_groestl_ctx(._32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -159,22 +142,46 @@ hash_string_384 :: proc(data: string) -> [48]byte { // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_groestl_ctx(._48) - return _hash_impl->hash_bytes_48(data) + hash: [48]byte + ctx: Groestl_Context + ctx.hashbitlen = 384 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_groestl_ctx(._48) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: Groestl_Context + ctx.hashbitlen = 384 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_groestl_ctx(._48) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -193,22 +200,46 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_groestl_ctx(._64) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: Groestl_Context + ctx.hashbitlen = 512 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_groestl_ctx(._64) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Groestl_Context + ctx.hashbitlen = 512 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_groestl_ctx(._64) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -222,201 +253,101 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() -} - -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true +init :: proc(ctx: ^Groestl_Context) { + assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512") + if ctx.hashbitlen <= 256 { + ctx.rounds = 10 + ctx.columns = 8 + ctx.statesize = 64 } else { - return hash, false + ctx.rounds = 14 + ctx.columns = 16 + ctx.statesize = 128 + } + for i := 8 - size_of(i32); i < 8; i += 1 { + ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i)))) } } -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok +update :: proc(ctx: ^Groestl_Context, data: []byte) { + databitlen := len(data) * 8 + msglen := databitlen / 8 + rem := databitlen % 8 + + i: int + assert(ctx.bits_in_last_byte == 0) + + if ctx.buf_ptr != 0 { + for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 { + ctx.buffer[ctx.buf_ptr] = data[i] } - } - return [28]byte{}, false -} -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } + if ctx.buf_ptr < ctx.statesize { + if rem != 0 { + ctx.bits_in_last_byte = rem + ctx.buffer[ctx.buf_ptr] = data[i] + ctx.buf_ptr += 1 + } + return } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false + + ctx.buf_ptr = 0 + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + } + + transform(ctx, data[i:], u32(msglen - i)) + i += ((msglen - i) / ctx.statesize) * ctx.statesize + for i < msglen { + ctx.buffer[ctx.buf_ptr] = data[i] + i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 + } + + if rem != 0 { + ctx.bits_in_last_byte = rem + ctx.buffer[ctx.buf_ptr] = data[i] + ctx.buf_ptr += 1 } } -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) +final :: proc(ctx: ^Groestl_Context, hash: []byte) { + hashbytelen := ctx.hashbitlen / 8 + + if ctx.bits_in_last_byte != 0 { + ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte)) + ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte)) } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok + ctx.buffer[ctx.buf_ptr] = 0x80 + ctx.buf_ptr += 1 + } + + if ctx.buf_ptr > ctx.statesize - 8 { + for ctx.buf_ptr < ctx.statesize { + ctx.buffer[ctx.buf_ptr] = 0 + ctx.buf_ptr += 1 } + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + ctx.buf_ptr = 0 } - return [32]byte{}, false -} -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) + for ctx.buf_ptr < ctx.statesize - 8 { + ctx.buffer[ctx.buf_ptr] = 0 + ctx.buf_ptr += 1 } - return hash -} -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false + ctx.block_counter += 1 + ctx.buf_ptr = ctx.statesize + + for ctx.buf_ptr > ctx.statesize - 8 { + ctx.buf_ptr -= 1 + ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter) + ctx.block_counter >>= 8 } -} -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} + transform(ctx, ctx.buffer[:], u32(ctx.statesize)) + output_transformation(ctx) -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_groestl_ctx(ctx.hash_size) - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Groestl_Context); ok { - final_odin(&c, hash) + for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 { + hash[j] = ctx.chaining[i % 8][i / 8] } } @@ -631,100 +562,3 @@ add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_V } } } - -init_odin :: proc(ctx: ^Groestl_Context) { - if ctx.hashbitlen <= 256 { - ctx.rounds = 10 - ctx.columns = 8 - ctx.statesize = 64 - } else { - ctx.rounds = 14 - ctx.columns = 16 - ctx.statesize = 128 - } - for i := 8 - size_of(i32); i < 8; i += 1 { - ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i)))) - } -} - -update_odin :: proc(ctx: ^Groestl_Context, data: []byte) { - databitlen := len(data) * 8 - msglen := databitlen / 8 - rem := databitlen % 8 - - i: int - assert(ctx.bits_in_last_byte == 0) - - if ctx.buf_ptr != 0 { - for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 { - ctx.buffer[ctx.buf_ptr] = data[i] - } - - if ctx.buf_ptr < ctx.statesize { - if rem != 0 { - ctx.bits_in_last_byte = rem - ctx.buffer[ctx.buf_ptr] = data[i] - ctx.buf_ptr += 1 - } - return - } - - ctx.buf_ptr = 0 - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - } - - transform(ctx, data[i:], u32(msglen - i)) - i += ((msglen - i) / ctx.statesize) * ctx.statesize - for i < msglen { - ctx.buffer[ctx.buf_ptr] = data[i] - i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 - } - - if rem != 0 { - ctx.bits_in_last_byte = rem - ctx.buffer[ctx.buf_ptr] = data[i] - ctx.buf_ptr += 1 - } -} - -final_odin :: proc(ctx: ^Groestl_Context, hash: []byte) { - hashbytelen := ctx.hashbitlen / 8 - - if ctx.bits_in_last_byte != 0 { - ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte)) - ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte)) - } else { - ctx.buffer[ctx.buf_ptr] = 0x80 - ctx.buf_ptr += 1 - } - - if ctx.buf_ptr > ctx.statesize - 8 { - for ctx.buf_ptr < ctx.statesize { - ctx.buffer[ctx.buf_ptr] = 0 - ctx.buf_ptr += 1 - } - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - ctx.buf_ptr = 0 - } - - for ctx.buf_ptr < ctx.statesize - 8 { - ctx.buffer[ctx.buf_ptr] = 0 - ctx.buf_ptr += 1 - } - - ctx.block_counter += 1 - ctx.buf_ptr = ctx.statesize - - for ctx.buf_ptr > ctx.statesize - 8 { - ctx.buf_ptr -= 1 - ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter) - ctx.block_counter >>= 8 - } - - transform(ctx, ctx.buffer[:], u32(ctx.statesize)) - output_transformation(ctx) - - for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 { - hash[j] = ctx.chaining[i % 8][i / 8] - } -} \ No newline at end of file diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin index bea799c71..76532d4cd 100644 --- a/core/crypto/haval/haval.odin +++ b/core/crypto/haval/haval.odin @@ -6,7 +6,6 @@ package haval List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation for the HAVAL hashing algorithm as defined in */ @@ -16,74 +15,6 @@ import "core:os" import "core:io" import "../util" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin_16 - ctx.hash_file_16 = hash_file_odin_16 - ctx.hash_stream_16 = hash_stream_odin_16 - ctx.hash_bytes_20 = hash_bytes_odin_20 - ctx.hash_file_20 = hash_file_odin_20 - ctx.hash_stream_20 = hash_stream_odin_20 - ctx.hash_bytes_24 = hash_bytes_odin_24 - ctx.hash_file_24 = hash_file_odin_24 - ctx.hash_stream_24 = hash_stream_odin_24 - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since HAVAL is not available in Botan -@(warning="HAVAL is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_haval_ctx :: #force_inline proc(size: _ctx.Hash_Size, rounds: u32) { - ctx: Haval_Context - #partial switch size { - case ._16: ctx.hashbitlen = 128 - case ._20: ctx.hashbitlen = 160 - case ._24: ctx.hashbitlen = 192 - case ._28: ctx.hashbitlen = 224 - case ._32: ctx.hashbitlen = 256 - } - ctx.rounds = rounds - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = size -} /* High level API @@ -98,22 +29,50 @@ hash_string_128_3 :: proc(data: string) -> [16]byte { // hash_bytes_128_3 will hash the given input and return the // computed hash hash_bytes_128_3 :: proc(data: []byte) -> [16]byte { - _create_haval_ctx(._16, 3) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_128_3 will read the stream in chunks and compute a // hash from its contents hash_stream_128_3 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_haval_ctx(._16, 3) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 3 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_128_3 will read the file provided by the given handle // and compute a hash hash_file_128_3 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_haval_ctx(._16, 3) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128_3(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128_3(buf[:]), ok + } + } + return [16]byte{}, false } hash_128_3 :: proc { @@ -132,22 +91,50 @@ hash_string_128_4 :: proc(data: string) -> [16]byte { // hash_bytes_128_4 will hash the given input and return the // computed hash hash_bytes_128_4 :: proc(data: []byte) -> [16]byte { - _create_haval_ctx(._16, 4) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_128_4 will read the stream in chunks and compute a // hash from its contents hash_stream_128_4 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_haval_ctx(._16, 4) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 4 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_128_4 will read the file provided by the given handle // and compute a hash hash_file_128_4 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_haval_ctx(._16, 4) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128_4(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128_4(buf[:]), ok + } + } + return [16]byte{}, false } hash_128_4 :: proc { @@ -166,22 +153,50 @@ hash_string_128_5 :: proc(data: string) -> [16]byte { // hash_bytes_128_5 will hash the given input and return the // computed hash hash_bytes_128_5 :: proc(data: []byte) -> [16]byte { - _create_haval_ctx(._16, 5) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_128_5 will read the stream in chunks and compute a // hash from its contents hash_stream_128_5 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_haval_ctx(._16, 5) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 5 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_128_5 will read the file provided by the given handle // and compute a hash hash_file_128_5 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_haval_ctx(._16, 5) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128_5(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128_5(buf[:]), ok + } + } + return [16]byte{}, false } hash_128_5 :: proc { @@ -200,22 +215,50 @@ hash_string_160_3 :: proc(data: string) -> [20]byte { // hash_bytes_160_3 will hash the given input and return the // computed hash hash_bytes_160_3 :: proc(data: []byte) -> [20]byte { - _create_haval_ctx(._20, 3) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_160_3 will read the stream in chunks and compute a // hash from its contents hash_stream_160_3 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_haval_ctx(._20, 3) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 3 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_160_3 will read the file provided by the given handle // and compute a hash hash_file_160_3 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_haval_ctx(._20, 3) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160_3(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160_3(buf[:]), ok + } + } + return [20]byte{}, false } hash_160_3 :: proc { @@ -234,22 +277,50 @@ hash_string_160_4 :: proc(data: string) -> [20]byte { // hash_bytes_160_4 will hash the given input and return the // computed hash hash_bytes_160_4 :: proc(data: []byte) -> [20]byte { - _create_haval_ctx(._20, 4) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_160_4 will read the stream in chunks and compute a // hash from its contents hash_stream_160_4 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_haval_ctx(._20, 4) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 4 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_160_4 will read the file provided by the given handle // and compute a hash hash_file_160_4 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_haval_ctx(._20, 4) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160_4(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160_4(buf[:]), ok + } + } + return [20]byte{}, false } hash_160_4 :: proc { @@ -268,22 +339,50 @@ hash_string_160_5 :: proc(data: string) -> [20]byte { // hash_bytes_160_5 will hash the given input and return the // computed hash hash_bytes_160_5 :: proc(data: []byte) -> [20]byte { - _create_haval_ctx(._20, 5) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_160_5 will read the stream in chunks and compute a // hash from its contents hash_stream_160_5 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_haval_ctx(._20, 5) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 5 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_160_5 will read the file provided by the given handle // and compute a hash hash_file_160_5 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_haval_ctx(._20, 5) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160_5(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160_5(buf[:]), ok + } + } + return [20]byte{}, false } hash_160_5 :: proc { @@ -302,22 +401,50 @@ hash_string_192_3 :: proc(data: string) -> [24]byte { // hash_bytes_192_3 will hash the given input and return the // computed hash hash_bytes_192_3 :: proc(data: []byte) -> [24]byte { - _create_haval_ctx(._24, 3) - return _hash_impl->hash_bytes_24(data) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_192_3 will read the stream in chunks and compute a // hash from its contents hash_stream_192_3 :: proc(s: io.Stream) -> ([24]byte, bool) { - _create_haval_ctx(._24, 3) - return _hash_impl->hash_stream_24(s) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 3 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_192_3 will read the file provided by the given handle // and compute a hash hash_file_192_3 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - _create_haval_ctx(._24, 3) - return _hash_impl->hash_file_24(hd, load_at_once) + if !load_at_once { + return hash_stream_192_3(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_192_3(buf[:]), ok + } + } + return [24]byte{}, false } hash_192_3 :: proc { @@ -336,22 +463,50 @@ hash_string_192_4 :: proc(data: string) -> [24]byte { // hash_bytes_192_4 will hash the given input and return the // computed hash hash_bytes_192_4 :: proc(data: []byte) -> [24]byte { - _create_haval_ctx(._24, 4) - return _hash_impl->hash_bytes_24(data) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_192_4 will read the stream in chunks and compute a // hash from its contents hash_stream_192_4 :: proc(s: io.Stream) -> ([24]byte, bool) { - _create_haval_ctx(._24, 4) - return _hash_impl->hash_stream_24(s) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 4 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_192_4 will read the file provided by the given handle // and compute a hash hash_file_192_4 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - _create_haval_ctx(._24, 4) - return _hash_impl->hash_file_24(hd, load_at_once) + if !load_at_once { + return hash_stream_192_4(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_192_4(buf[:]), ok + } + } + return [24]byte{}, false } hash_192_4 :: proc { @@ -370,22 +525,50 @@ hash_string_192_5 :: proc(data: string) -> [24]byte { // hash_bytes_224_5 will hash the given input and return the // computed hash hash_bytes_192_5 :: proc(data: []byte) -> [24]byte { - _create_haval_ctx(._24, 5) - return _hash_impl->hash_bytes_24(data) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_192_5 will read the stream in chunks and compute a // hash from its contents hash_stream_192_5 :: proc(s: io.Stream) -> ([24]byte, bool) { - _create_haval_ctx(._24, 5) - return _hash_impl->hash_stream_24(s) + hash: [24]byte + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 5 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_192_5 will read the file provided by the given handle // and compute a hash hash_file_192_5 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - _create_haval_ctx(._24, 5) - return _hash_impl->hash_file_24(hd, load_at_once) + if !load_at_once { + return hash_stream_192_5(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_192_5(buf[:]), ok + } + } + return [24]byte{}, false } hash_192_5 :: proc { @@ -404,22 +587,50 @@ hash_string_224_3 :: proc(data: string) -> [28]byte { // hash_bytes_224_3 will hash the given input and return the // computed hash hash_bytes_224_3 :: proc(data: []byte) -> [28]byte { - _create_haval_ctx(._28, 3) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224_3 will read the stream in chunks and compute a // hash from its contents hash_stream_224_3 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_haval_ctx(._28, 3) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 3 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224_3 will read the file provided by the given handle // and compute a hash hash_file_224_3 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_haval_ctx(._28, 3) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224_3(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224_3(buf[:]), ok + } + } + return [28]byte{}, false } hash_224_3 :: proc { @@ -438,22 +649,50 @@ hash_string_224_4 :: proc(data: string) -> [28]byte { // hash_bytes_224_4 will hash the given input and return the // computed hash hash_bytes_224_4 :: proc(data: []byte) -> [28]byte { - _create_haval_ctx(._28, 4) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224_4 will read the stream in chunks and compute a // hash from its contents hash_stream_224_4 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_haval_ctx(._28, 4) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 4 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224_4 will read the file provided by the given handle // and compute a hash hash_file_224_4 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_haval_ctx(._28, 4) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224_4(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224_4(buf[:]), ok + } + } + return [28]byte{}, false } hash_224_4 :: proc { @@ -472,22 +711,50 @@ hash_string_224_5 :: proc(data: string) -> [28]byte { // hash_bytes_224_5 will hash the given input and return the // computed hash hash_bytes_224_5 :: proc(data: []byte) -> [28]byte { - _create_haval_ctx(._28, 5) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224_5 will read the stream in chunks and compute a // hash from its contents hash_stream_224_5 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_haval_ctx(._28, 5) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 5 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224_5 will read the file provided by the given handle // and compute a hash hash_file_224_5 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_haval_ctx(._28, 5) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224_5(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224_5(buf[:]), ok + } + } + return [28]byte{}, false } hash_224_5 :: proc { @@ -506,22 +773,50 @@ hash_string_256_3 :: proc(data: string) -> [32]byte { // hash_bytes_256_3 will hash the given input and return the // computed hash hash_bytes_256_3 :: proc(data: []byte) -> [32]byte { - _create_haval_ctx(._32, 3) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256_3 will read the stream in chunks and compute a // hash from its contents hash_stream_256_3 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_haval_ctx(._32, 3) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 3 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256_3 will read the file provided by the given handle // and compute a hash hash_file_256_3 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_haval_ctx(._32, 3) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256_3(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256_3(buf[:]), ok + } + } + return [32]byte{}, false } hash_256_3 :: proc { @@ -540,22 +835,50 @@ hash_string_256_4 :: proc(data: string) -> [32]byte { // hash_bytes_256_4 will hash the given input and return the // computed hash hash_bytes_256_4 :: proc(data: []byte) -> [32]byte { - _create_haval_ctx(._32, 4) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256_4 will read the stream in chunks and compute a // hash from its contents hash_stream_256_4 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_haval_ctx(._32, 4) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 4 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256_4 will read the file provided by the given handle // and compute a hash hash_file_256_4 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_haval_ctx(._32, 4) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256_4(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256_4(buf[:]), ok + } + } + return [32]byte{}, false } hash_256_4 :: proc { @@ -574,22 +897,50 @@ hash_string_256_5 :: proc(data: string) -> [32]byte { // hash_bytes_256_5 will hash the given input and return the // computed hash hash_bytes_256_5 :: proc(data: []byte) -> [32]byte { - _create_haval_ctx(._32, 5) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256_5 will read the stream in chunks and compute a // hash from its contents hash_stream_256_5 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_haval_ctx(._32, 5) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 5 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + ctx.str_len = u32(len(buf[:read])) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256_5 will read the file provided by the given handle // and compute a hash hash_file_256_5 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_haval_ctx(._32, 5) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256_5(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256_5(buf[:]), ok + } + } + return [32]byte{}, false } hash_256_5 :: proc { @@ -603,260 +954,93 @@ hash_256_5 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Haval_Context) { + assert(ctx.hashbitlen == 128 || ctx.hashbitlen == 160 || ctx.hashbitlen == 192 || ctx.hashbitlen == 224 || ctx.hashbitlen == 256, "hashbitlen must be set to 128, 160, 192, 224 or 256") + assert(ctx.rounds == 3 || ctx.rounds == 4 || ctx.rounds == 5, "rounds must be set to 3, 4 or 5") + ctx.fingerprint[0] = 0x243f6a88 + ctx.fingerprint[1] = 0x85a308d3 + ctx.fingerprint[2] = 0x13198a2e + ctx.fingerprint[3] = 0x03707344 + ctx.fingerprint[4] = 0xa4093822 + ctx.fingerprint[5] = 0x299f31d0 + ctx.fingerprint[6] = 0x082efa98 + ctx.fingerprint[7] = 0xec4e6c89 } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} +// @note(zh): Make sure to set ctx.str_len to the remaining buffer size before calling this proc - e.g. ctx.str_len = u32(len(data)) +update :: proc(ctx: ^Haval_Context, data: []byte) { + i: u32 + rmd_len := u32((ctx.count[0] >> 3) & 0x7f) + fill_len := 128 - rmd_len + str_len := ctx.str_len -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - c.str_len = u32(len(data)) - update_odin(&c, data) - final_odin(&c, hash[:]) + ctx.count[0] += str_len << 3 + if ctx.count[0] < (str_len << 3) { + ctx.count[1] += 1 } - return hash -} + ctx.count[1] += str_len >> 29 -hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - c.str_len = u32(len(buf[:read])) - update_odin(&c, buf[:read]) - } + when ODIN_ENDIAN == "little" { + if rmd_len + str_len >= 128 { + copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len]) + block(ctx, ctx.rounds) + for i = fill_len; i + 127 < str_len; i += 128 { + copy(util.slice_to_bytes(ctx.block[:]), data[i:128]) + block(ctx, ctx.rounds) + } + rmd_len = 0 + } else { + i = 0 } - final_odin(&c, hash[:]) - return hash, true + copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[i:]) } else { - return hash, false - } -} - -hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_16(ctx, buf[:]), ok + if rmd_len + str_len >= 128 { + copy(ctx.remainder[rmd_len:], data[:fill_len]) + CH2UINT(ctx.remainder[:], ctx.block[:]) + block(ctx, ctx.rounds) + for i = fill_len; i + 127 < str_len; i += 128 { + copy(ctx.remainder[:], data[i:128]) + CH2UINT(ctx.remainder[:], ctx.block[:]) + block(ctx, ctx.rounds) + } + rmd_len = 0 + } else { + i = 0 } + copy(ctx.remainder[rmd_len:], data[i:]) } - return [16]byte{}, false } -hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - c.str_len = u32(len(data)) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} +final :: proc(ctx: ^Haval_Context, hash: []byte) { + pad_len: u32 + tail: [10]byte -hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - c.str_len = u32(len(buf[:read])) - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true + tail[0] = byte(ctx.hashbitlen & 0x3) << 6 | byte(ctx.rounds & 0x7) << 3 | (VERSION & 0x7) + tail[1] = byte(ctx.hashbitlen >> 2) & 0xff + + UINT2CH(ctx.count[:], util.slice_to_bytes(tail[2:]), 2) + rmd_len := (ctx.count[0] >> 3) & 0x7f + if rmd_len < 118 { + pad_len = 118 - rmd_len } else { - return hash, false + pad_len = 246 - rmd_len } -} -hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_20(ctx, buf[:]), ok - } - } - return [20]byte{}, false -} + ctx.str_len = pad_len + update(ctx, PADDING[:]) + ctx.str_len = 10 + update(ctx, tail[:]) + tailor(ctx, ctx.hashbitlen) + UINT2CH(ctx.fingerprint[:], hash, ctx.hashbitlen >> 5) -hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { - hash: [24]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - c.str_len = u32(len(data)) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { - hash: [24]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - c.str_len = u32(len(buf[:read])) - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - if !load_at_once { - return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_24(ctx, buf[:]), ok - } - } - return [24]byte{}, false -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - c.str_len = u32(len(data)) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - c.str_len = u32(len(buf[:read])) - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok - } - } - return [28]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - c.str_len = u32(len(data)) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - c.str_len = u32(len(buf[:read])) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - c.str_len = u32(len(data)) - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Haval_Context); ok { - final_odin(&c, hash) - } + mem.set(ctx, 0, size_of(ctx)) } /* HAVAL implementation */ -HAVAL_VERSION :: 1 +VERSION :: 1 Haval_Context :: struct { count: [2]u32, @@ -879,23 +1063,23 @@ PADDING := [128]byte { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } -F_1 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { +F_1 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { return ((x1) & ((x0) ~ (x4)) ~ (x2) & (x5) ~ (x3) & (x6) ~ (x0)) } -F_2 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { +F_2 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { return ((x2) & ((x1) & ~(x3) ~ (x4) & (x5) ~ (x6) ~ (x0)) ~ (x4) & ((x1) ~ (x5)) ~ (x3) & (x5) ~ (x0)) } -F_3 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { +F_3 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { return ((x3) & ((x1) & (x2) ~ (x6) ~ (x0)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x0)) } -F_4 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { +F_4 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { return ((x4) & ((x5) & ~(x2) ~ (x3) & ~(x6) ~ (x1) ~ (x6) ~ (x0)) ~ (x3) & ((x1) & (x2) ~ (x5) ~ (x6)) ~ (x2) & (x6) ~ (x0)) } -F_5 :: #force_inline proc(x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { +F_5 :: #force_inline proc "contextless" (x6, x5, x4, x3, x2, x1, x0: u32) -> u32 { return ((x0) & ((x1) & (x2) & (x3) ~ ~(x5)) ~ (x1) & (x4) ~ (x2) & (x5) ~ (x3) & (x6)) } @@ -976,13 +1160,13 @@ FF_5 :: #force_inline proc(x7, x6, x5, x4, x3, x2, x1, x0, w, c, rounds: u32) -> return x8 } -HAVAL_CH2UINT :: #force_inline proc (str: []byte, word: []u32) { +CH2UINT :: #force_inline proc "contextless" (str: []byte, word: []u32) { for _, i in word[:32] { word[i] = u32(str[i*4+0]) << 0 | u32(str[i*4+1]) << 8 | u32(str[i*4+2]) << 16 | u32(str[i*4+3]) << 24 } } -HAVAL_UINT2CH :: #force_inline proc(word: []u32, str: []byte, wlen: u32) { +UINT2CH :: #force_inline proc "contextless" (word: []u32, str: []byte, wlen: u32) { for _, i in word[:wlen] { str[i*4+0] = byte(word[i] >> 0) & 0xff str[i*4+1] = byte(word[i] >> 8) & 0xff @@ -991,7 +1175,7 @@ HAVAL_UINT2CH :: #force_inline proc(word: []u32, str: []byte, wlen: u32) { } } -haval_block :: proc(ctx: ^Haval_Context, rounds: u32) { +block :: proc(ctx: ^Haval_Context, rounds: u32) { t0, t1, t2, t3 := ctx.fingerprint[0], ctx.fingerprint[1], ctx.fingerprint[2], ctx.fingerprint[3] t4, t5, t6, t7 := ctx.fingerprint[4], ctx.fingerprint[5], ctx.fingerprint[6], ctx.fingerprint[7] w := ctx.block @@ -1190,7 +1374,7 @@ haval_block :: proc(ctx: ^Haval_Context, rounds: u32) { ctx.fingerprint[7] += t7 } -haval_tailor :: proc(ctx: ^Haval_Context, size: u32) { +tailor :: proc(ctx: ^Haval_Context, size: u32) { temp: u32 switch size { case 128: @@ -1276,82 +1460,3 @@ haval_tailor :: proc(ctx: ^Haval_Context, size: u32) { ctx.fingerprint[6] += ctx.fingerprint[7] & 0x0f } } - -init_odin :: proc(ctx: ^Haval_Context) { - ctx.fingerprint[0] = 0x243f6a88 - ctx.fingerprint[1] = 0x85a308d3 - ctx.fingerprint[2] = 0x13198a2e - ctx.fingerprint[3] = 0x03707344 - ctx.fingerprint[4] = 0xa4093822 - ctx.fingerprint[5] = 0x299f31d0 - ctx.fingerprint[6] = 0x082efa98 - ctx.fingerprint[7] = 0xec4e6c89 -} - -update_odin :: proc(ctx: ^Haval_Context, data: []byte) { - i: u32 - rmd_len := u32((ctx.count[0] >> 3) & 0x7f) - fill_len := 128 - rmd_len - str_len := ctx.str_len - - ctx.count[0] += str_len << 3 - if ctx.count[0] < (str_len << 3) { - ctx.count[1] += 1 - } - ctx.count[1] += str_len >> 29 - - when ODIN_ENDIAN == "little" { - if rmd_len + str_len >= 128 { - copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len]) - haval_block(ctx, ctx.rounds) - for i = fill_len; i + 127 < str_len; i += 128 { - copy(util.slice_to_bytes(ctx.block[:]), data[i:128]) - haval_block(ctx, ctx.rounds) - } - rmd_len = 0 - } else { - i = 0 - } - copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[i:]) - } else { - if rmd_len + str_len >= 128 { - copy(ctx.remainder[rmd_len:], data[:fill_len]) - HAVAL_CH2UINT(ctx.remainder[:], ctx.block[:]) - haval_block(ctx, ctx.rounds) - for i = fill_len; i + 127 < str_len; i += 128 { - copy(ctx.remainder[:], data[i:128]) - HAVAL_CH2UINT(ctx.remainder[:], ctx.block[:]) - haval_block(ctx, ctx.rounds) - } - rmd_len = 0 - } else { - i = 0 - } - copy(ctx.remainder[rmd_len:], data[i:]) - } -} - -final_odin :: proc(ctx: ^Haval_Context, hash: []byte) { - pad_len: u32 - tail: [10]byte - - tail[0] = byte(ctx.hashbitlen & 0x3) << 6 | byte(ctx.rounds & 0x7) << 3 | (HAVAL_VERSION & 0x7) - tail[1] = byte(ctx.hashbitlen >> 2) & 0xff - - HAVAL_UINT2CH(ctx.count[:], util.slice_to_bytes(tail[2:]), 2) - rmd_len := (ctx.count[0] >> 3) & 0x7f - if rmd_len < 118 { - pad_len = 118 - rmd_len - } else { - pad_len = 246 - rmd_len - } - - ctx.str_len = pad_len - update_odin(ctx, PADDING[:]) - ctx.str_len = 10 - update_odin(ctx, tail[:]) - haval_tailor(ctx, ctx.hashbitlen) - HAVAL_UINT2CH(ctx.fingerprint[:], hash, ctx.hashbitlen >> 5) - - mem.set(ctx, 0, size_of(ctx)) -} diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin index 3c48f6666..f251424d2 100644 --- a/core/crypto/jh/jh.odin +++ b/core/crypto/jh/jh.odin @@ -6,7 +6,6 @@ package jh List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the JH hashing algorithm, as defined in */ @@ -14,70 +13,6 @@ package jh import "core:os" import "core:io" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since JH is not available in Botan -@(warning="JH is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_jh_ctx :: #force_inline proc(size: _ctx.Hash_Size) { - ctx: Jh_Context - #partial switch size { - case ._28: ctx.hashbitlen = 224 - case ._32: ctx.hashbitlen = 256 - case ._48: ctx.hashbitlen = 384 - case ._64: ctx.hashbitlen = 512 - } - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = size -} - /* High level API */ @@ -91,22 +26,46 @@ hash_string_224 :: proc(data: string) -> [28]byte { // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_jh_ctx(._28) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Jh_Context + ctx.hashbitlen = 224 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_jh_ctx(._28) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Jh_Context + ctx.hashbitlen = 224 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_jh_ctx(._28) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -125,22 +84,46 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_jh_ctx(._32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Jh_Context + ctx.hashbitlen = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_jh_ctx(._32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Jh_Context + ctx.hashbitlen = 256 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_jh_ctx(._32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -159,22 +142,46 @@ hash_string_384 :: proc(data: string) -> [48]byte { // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_jh_ctx(._48) - return _hash_impl->hash_bytes_48(data) + hash: [48]byte + ctx: Jh_Context + ctx.hashbitlen = 384 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_jh_ctx(._48) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: Jh_Context + ctx.hashbitlen = 384 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_jh_ctx(._48) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -193,22 +200,46 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_jh_ctx(._64) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: Jh_Context + ctx.hashbitlen = 512 + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_jh_ctx(._64) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Jh_Context + ctx.hashbitlen = 512 + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_jh_ctx(._64) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -222,201 +253,98 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Jh_Context) { + assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512") + ctx.H[1] = byte(ctx.hashbitlen) & 0xff + ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff + F8(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} +update :: proc(ctx: ^Jh_Context, data: []byte) { + databitlen := u64(len(data)) * 8 + ctx.databitlen += databitlen + i := u64(0) -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) + if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) { + if (databitlen & 7) == 0 { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) + } else { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1]) + } + ctx.buffer_size += databitlen + databitlen = 0 } - return hash -} -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } + if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) { + copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) + i = 64 - (ctx.buffer_size >> 3) + databitlen = databitlen - (512 - ctx.buffer_size) + F8(ctx) + ctx.buffer_size = 0 + } + + for databitlen >= 512 { + copy(ctx.buffer[:], data[i:i + 64]) + F8(ctx) + i += 64 + databitlen -= 512 + } + + if databitlen > 0 { + if (databitlen & 7) == 0 { + copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)]) + } else { + copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1]) } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false + ctx.buffer_size = databitlen } } -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok +final :: proc(ctx: ^Jh_Context, hash: []byte) { + if ctx.databitlen & 0x1ff == 0 { + for i := 0; i < 64; i += 1 { + ctx.buffer[i] = 0 } - } - return [28]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true + ctx.buffer[0] = 0x80 + ctx.buffer[63] = byte(ctx.databitlen) & 0xff + ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff + ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff + ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff + ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff + ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff + ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff + ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff + F8(ctx) } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok + if ctx.buffer_size & 7 == 0 { + for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 { + ctx.buffer[i] = 0 + } + } else { + for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 { + ctx.buffer[i] = 0 + } } - } - return [32]byte{}, false -} - -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } + ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7)) + F8(ctx) + for i := 0; i < 64; i += 1 { + ctx.buffer[i] = 0 } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false + ctx.buffer[63] = byte(ctx.databitlen) & 0xff + ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff + ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff + ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff + ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff + ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff + ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff + ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff + F8(ctx) } -} - -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_jh_ctx(ctx.hash_size) - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Jh_Context); ok { - final_odin(&c, hash) + switch ctx.hashbitlen { + case 224: copy(hash[:], ctx.H[100:128]) + case 256: copy(hash[:], ctx.H[96:128]) + case 384: copy(hash[:], ctx.H[80:128]) + case 512: copy(hash[:], ctx.H[64:128]) } } @@ -424,7 +352,7 @@ _final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { JH implementation */ -JH_ROUNDCONSTANT_ZERO := [64]byte { +ROUNDCONSTANT_ZERO := [64]byte { 0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7, 0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8, 0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6, @@ -435,7 +363,7 @@ JH_ROUNDCONSTANT_ZERO := [64]byte { 0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa, } -JH_S := [2][16]byte { +SBOX := [2][16]byte { {9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14}, {3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8}, } @@ -450,7 +378,7 @@ Jh_Context :: struct { buffer: [64]byte, } -JH_E8_finaldegroup :: proc(ctx: ^Jh_Context) { +E8_finaldegroup :: proc(ctx: ^Jh_Context) { t0,t1,t2,t3: byte tem: [256]byte for i := 0; i < 128; i += 1 { @@ -473,11 +401,11 @@ JH_E8_finaldegroup :: proc(ctx: ^Jh_Context) { } } -jh_update_roundconstant :: proc(ctx: ^Jh_Context) { +update_roundconstant :: proc(ctx: ^Jh_Context) { tem: [64]byte t: byte for i := 0; i < 64; i += 1 { - tem[i] = JH_S[0][ctx.roundconstant[i]] + tem[i] = SBOX[0][ctx.roundconstant[i]] } for i := 0; i < 64; i += 2 { tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf @@ -499,14 +427,14 @@ jh_update_roundconstant :: proc(ctx: ^Jh_Context) { } } -JH_R8 :: proc(ctx: ^Jh_Context) { +R8 :: proc(ctx: ^Jh_Context) { t: byte tem, roundconstant_expanded: [256]byte for i := u32(0); i < 256; i += 1 { roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1 } for i := 0; i < 256; i += 1 { - tem[i] = JH_S[roundconstant_expanded[i]][ctx.A[i]] + tem[i] = SBOX[roundconstant_expanded[i]][ctx.A[i]] } for i := 0; i < 256; i += 2 { tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf @@ -528,7 +456,7 @@ JH_R8 :: proc(ctx: ^Jh_Context) { } } -JH_E8_initialgroup :: proc(ctx: ^Jh_Context) { +E8_initialgroup :: proc(ctx: ^Jh_Context) { t0, t1, t2, t3: byte tem: [256]byte for i := u32(0); i < 256; i += 1 { @@ -544,118 +472,24 @@ JH_E8_initialgroup :: proc(ctx: ^Jh_Context) { } } -JH_E8 :: proc(ctx: ^Jh_Context) { +E8 :: proc(ctx: ^Jh_Context) { for i := 0; i < 64; i += 1 { - ctx.roundconstant[i] = JH_ROUNDCONSTANT_ZERO[i] + ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i] } - JH_E8_initialgroup(ctx) + E8_initialgroup(ctx) for i := 0; i < 42; i += 1 { - JH_R8(ctx) - jh_update_roundconstant(ctx) + R8(ctx) + update_roundconstant(ctx) } - JH_E8_finaldegroup(ctx) + E8_finaldegroup(ctx) } -JH_F8 :: proc(ctx: ^Jh_Context) { +F8 :: proc(ctx: ^Jh_Context) { for i := 0; i < 64; i += 1 { ctx.H[i] ~= ctx.buffer[i] } - JH_E8(ctx) + E8(ctx) for i := 0; i < 64; i += 1 { ctx.H[i + 64] ~= ctx.buffer[i] } } - -init_odin :: proc(ctx: ^Jh_Context) { - ctx.H[1] = byte(ctx.hashbitlen) & 0xff - ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff - JH_F8(ctx) -} - -update_odin :: proc(ctx: ^Jh_Context, data: []byte) { - databitlen := u64(len(data)) * 8 - ctx.databitlen += databitlen - i := u64(0) - - if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) { - if (databitlen & 7) == 0 { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) - } else { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1]) - } - ctx.buffer_size += databitlen - databitlen = 0 - } - - if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) { - copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)]) - i = 64 - (ctx.buffer_size >> 3) - databitlen = databitlen - (512 - ctx.buffer_size) - JH_F8(ctx) - ctx.buffer_size = 0 - } - - for databitlen >= 512 { - copy(ctx.buffer[:], data[i:i + 64]) - JH_F8(ctx) - i += 64 - databitlen -= 512 - } - - if databitlen > 0 { - if (databitlen & 7) == 0 { - copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)]) - } else { - copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1]) - } - ctx.buffer_size = databitlen - } -} - -final_odin :: proc(ctx: ^Jh_Context, hash: []byte) { - if ctx.databitlen & 0x1ff == 0 { - for i := 0; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - ctx.buffer[0] = 0x80 - ctx.buffer[63] = byte(ctx.databitlen) & 0xff - ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff - ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff - ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff - ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff - ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff - ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff - ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff - JH_F8(ctx) - } else { - if ctx.buffer_size & 7 == 0 { - for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - } else { - for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - } - ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7)) - JH_F8(ctx) - for i := 0; i < 64; i += 1 { - ctx.buffer[i] = 0 - } - ctx.buffer[63] = byte(ctx.databitlen) & 0xff - ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff - ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff - ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff - ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff - ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff - ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff - ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff - JH_F8(ctx) - } - switch ctx.hashbitlen { - case 224: copy(hash[:], ctx.H[100:128]) - case 256: copy(hash[:], ctx.H[96:128]) - case 384: copy(hash[:], ctx.H[80:128]) - case 512: copy(hash[:], ctx.H[64:128]) - } -} diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index 4b3f9a5a2..19c4c7dda 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -6,7 +6,6 @@ package keccak List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the Keccak hashing algorithm. This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output. @@ -15,57 +14,8 @@ package keccak import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../_sha3" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_KECCAK) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} /* High level API @@ -80,22 +30,48 @@ hash_string_224 :: proc(data: string) -> [28]byte { // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_keccak_ctx(28) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 28 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_keccak_ctx(28) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 28 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_keccak_ctx(28) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -114,22 +90,48 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_keccak_ctx(32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_keccak_ctx(32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_keccak_ctx(32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -148,22 +150,48 @@ hash_string_384 :: proc(data: string) -> [48]byte { // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_keccak_ctx(48) - return _hash_impl->hash_bytes_48(data) + hash: [48]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 48 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_keccak_ctx(48) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 48 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_keccak_ctx(48) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -182,22 +210,48 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_keccak_ctx(64) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 64 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_keccak_ctx(64) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 64 + ctx.is_keccak = true + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_keccak_ctx(64) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -211,219 +265,17 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +Sha3_Context :: _sha3.Sha3_Context + +init :: proc(ctx: ^_sha3.Sha3_Context) { + ctx.is_keccak = true + _sha3.init(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { + _sha3.update(ctx, data) } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok - } - } - return [28]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_create_keccak_ctx :: #force_inline proc(mdlen: int) { - ctx: _sha3.Sha3_Context - ctx.mdlen = mdlen - ctx.is_keccak = true - _hash_impl.internal_ctx = ctx - switch mdlen { - case 28: _hash_impl.hash_size = ._28 - case 32: _hash_impl.hash_size = ._32 - case 48: _hash_impl.hash_size = ._48 - case 64: _hash_impl.hash_size = ._64 - } -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._28: _create_keccak_ctx(28) - case ._32: _create_keccak_ctx(32) - case ._48: _create_keccak_ctx(48) - case ._64: _create_keccak_ctx(64) - } - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.final_odin(&c, hash) - } +final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { + _sha3.final(ctx, hash) } diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin index ceca0f58b..5e027c13c 100644 --- a/core/crypto/md2/md2.odin +++ b/core/crypto/md2/md2.odin @@ -6,7 +6,6 @@ package md2 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the MD2 hashing algorithm, as defined in RFC 1319 */ @@ -14,48 +13,6 @@ package md2 import "core:os" import "core:io" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin - ctx.hash_file_16 = hash_file_odin - ctx.hash_stream_16 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since MD2 is not available in Botan -@(warning="MD2 is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -69,22 +26,44 @@ hash_string :: proc(data: string) -> [16]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [16]byte { - _create_md2_ctx() - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Md2_Context + // init(&ctx) No-op + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_md2_ctx() - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Md2_Context + // init(&ctx) No-op + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_md2_ctx() - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [16]byte{}, false } hash :: proc { @@ -98,85 +77,32 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +@(warning="Init is a no-op for MD2") +init :: proc(ctx: ^Md2_Context) { + // No action needed here } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc(ctx: ^Md2_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if (ctx.datalen == 16) { + transform(ctx, ctx.data[:]) + ctx.datalen = 0 + } + } } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md2_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) +final :: proc(ctx: ^Md2_Context, hash: []byte) { + to_pad := byte(16 - ctx.datalen) + for ctx.datalen < 16 { + ctx.data[ctx.datalen] = to_pad + ctx.datalen += 1 } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md2_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok - } - } - return [16]byte{}, false -} - -@(private) -_create_md2_ctx :: #force_inline proc() { - ctx: Md2_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._16 -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_md2_ctx() - if c, ok := ctx.internal_ctx.(Md2_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Md2_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Md2_Context); ok { - final_odin(&c, hash) + transform(ctx, ctx.data[:]) + transform(ctx, ctx.checksum[:]) + for i := 0; i < 16; i += 1 { + hash[i] = ctx.state[i] } } @@ -232,31 +158,3 @@ transform :: proc(ctx: ^Md2_Context, data: []byte) { t = ctx.checksum[j] } } - -init_odin :: proc(ctx: ^Md2_Context) { - // No action needed here -} - -update_odin :: proc(ctx: ^Md2_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if (ctx.datalen == 16) { - transform(ctx, ctx.data[:]) - ctx.datalen = 0 - } - } -} - -final_odin :: proc(ctx: ^Md2_Context, hash: []byte) { - to_pad := byte(16 - ctx.datalen) - for ctx.datalen < 16 { - ctx.data[ctx.datalen] = to_pad - ctx.datalen += 1 - } - transform(ctx, ctx.data[:]) - transform(ctx, ctx.checksum[:]) - for i := 0; i < 16; i += 1 { - hash[i] = ctx.state[i] - } -} \ No newline at end of file diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin index bc012caea..813db578a 100644 --- a/core/crypto/md4/md4.odin +++ b/core/crypto/md4/md4.odin @@ -16,47 +16,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin - ctx.hash_file_16 = hash_file_odin - ctx.hash_stream_16 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_MD4) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} /* High level API @@ -71,22 +30,44 @@ hash_string :: proc(data: string) -> [16]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [16]byte { - _create_md4_ctx() - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Md4_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_md4_ctx() - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Md4_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_md4_ctx() - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [16]byte{}, false } hash :: proc { @@ -100,85 +81,61 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Md4_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md4_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md4_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok +update :: proc(ctx: ^Md4_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if(ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 } } - return [16]byte{}, false } -@(private) -_create_md4_ctx :: #force_inline proc() { - ctx: Md4_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._16 -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_md4_ctx() - if c, ok := ctx.internal_ctx.(Md4_Context); ok { - init_odin(&c) +final :: proc(ctx: ^Md4_Context, hash: []byte) { + i := ctx.datalen + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else if ctx.datalen >= 56 { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) } -} -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Md4_Context); ok { - update_odin(&c, data) - } -} + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[56] = byte(ctx.bitlen) + ctx.data[57] = byte(ctx.bitlen >> 8) + ctx.data[58] = byte(ctx.bitlen >> 16) + ctx.data[59] = byte(ctx.bitlen >> 24) + ctx.data[60] = byte(ctx.bitlen >> 32) + ctx.data[61] = byte(ctx.bitlen >> 40) + ctx.data[62] = byte(ctx.bitlen >> 48) + ctx.data[63] = byte(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Md4_Context); ok { - final_odin(&c, hash) + for i = 0; i < 4; i += 1 { + hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff + hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff + hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff + hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff } } @@ -282,61 +239,3 @@ transform :: proc(ctx: ^Md4_Context, data: []byte) { ctx.state[2] += c ctx.state[3] += d } - -init_odin :: proc(ctx: ^Md4_Context) { - ctx.state[0] = 0x67452301 - ctx.state[1] = 0xefcdab89 - ctx.state[2] = 0x98badcfe - ctx.state[3] = 0x10325476 -} - -update_odin :: proc(ctx: ^Md4_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if(ctx.datalen == BLOCK_SIZE) { - transform(ctx, ctx.data[:]) - ctx.bitlen += 512 - ctx.datalen = 0 - } - } -} - -final_odin :: proc(ctx: ^Md4_Context, hash: []byte) { - i := ctx.datalen - if ctx.datalen < 56 { - ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } else if ctx.datalen >= 56 { - ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } - transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) - } - - ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[56] = byte(ctx.bitlen) - ctx.data[57] = byte(ctx.bitlen >> 8) - ctx.data[58] = byte(ctx.bitlen >> 16) - ctx.data[59] = byte(ctx.bitlen >> 24) - ctx.data[60] = byte(ctx.bitlen >> 32) - ctx.data[61] = byte(ctx.bitlen >> 40) - ctx.data[62] = byte(ctx.bitlen >> 48) - ctx.data[63] = byte(ctx.bitlen >> 56) - transform(ctx, ctx.data[:]) - - for i = 0; i < 4; i += 1 { - hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff - hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff - hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff - hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff - } -} diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 78da3fe33..a41ed16f8 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -6,7 +6,6 @@ package md5 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the MD5 hashing algorithm, as defined in RFC 1321 */ @@ -16,47 +15,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin - ctx.hash_file_16 = hash_file_odin - ctx.hash_stream_16 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_MD5) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} /* High level API @@ -71,22 +29,44 @@ hash_string :: proc(data: string) -> [16]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [16]byte { - _create_md5_ctx() - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Md5_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_md5_ctx() - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Md5_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_md5_ctx() - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [16]byte{}, false } hash :: proc { @@ -100,85 +80,63 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Md5_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md5_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Md5_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok +update :: proc(ctx: ^Md5_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if(ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 } } - return [16]byte{}, false } -@(private) -_create_md5_ctx :: #force_inline proc() { - ctx: Md5_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._16 -} +final :: proc(ctx: ^Md5_Context, hash: []byte){ + i : u32 + i = ctx.datalen -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_md5_ctx() - if c, ok := ctx.internal_ctx.(Md5_Context); ok { - init_odin(&c) + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 + } + } else if ctx.datalen >= 56 { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) } -} -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Md5_Context); ok { - update_odin(&c, data) - } -} + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[56] = byte(ctx.bitlen) + ctx.data[57] = byte(ctx.bitlen >> 8) + ctx.data[58] = byte(ctx.bitlen >> 16) + ctx.data[59] = byte(ctx.bitlen >> 24) + ctx.data[60] = byte(ctx.bitlen >> 32) + ctx.data[61] = byte(ctx.bitlen >> 40) + ctx.data[62] = byte(ctx.bitlen >> 48) + ctx.data[63] = byte(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Md5_Context); ok { - final_odin(&c, hash) + for i = 0; i < 4; i += 1 { + hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff + hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff + hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff + hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff } } @@ -303,63 +261,3 @@ transform :: proc(ctx: ^Md5_Context, data: []byte) { ctx.state[2] += c ctx.state[3] += d } - -init_odin :: proc(ctx: ^Md5_Context) { - ctx.state[0] = 0x67452301 - ctx.state[1] = 0xefcdab89 - ctx.state[2] = 0x98badcfe - ctx.state[3] = 0x10325476 -} - -update_odin :: proc(ctx: ^Md5_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if(ctx.datalen == BLOCK_SIZE) { - transform(ctx, ctx.data[:]) - ctx.bitlen += 512 - ctx.datalen = 0 - } - } -} - -final_odin :: proc(ctx: ^Md5_Context, hash: []byte){ - i : u32 - i = ctx.datalen - - if ctx.datalen < 56 { - ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } else if ctx.datalen >= 56 { - ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } - transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) - } - - ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[56] = byte(ctx.bitlen) - ctx.data[57] = byte(ctx.bitlen >> 8) - ctx.data[58] = byte(ctx.bitlen >> 16) - ctx.data[59] = byte(ctx.bitlen >> 24) - ctx.data[60] = byte(ctx.bitlen >> 32) - ctx.data[61] = byte(ctx.bitlen >> 40) - ctx.data[62] = byte(ctx.bitlen >> 48) - ctx.data[63] = byte(ctx.bitlen >> 56) - transform(ctx, ctx.data[:]) - - for i = 0; i < 4; i += 1 { - hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff - hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff - hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff - hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff - } -} \ No newline at end of file diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin index fe480e5a9..a9a5d1126 100644 --- a/core/crypto/ripemd/ripemd.odin +++ b/core/crypto/ripemd/ripemd.odin @@ -6,7 +6,6 @@ package ripemd List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation for the RIPEMD hashing algorithm as defined in */ @@ -15,56 +14,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin_16 - ctx.hash_file_16 = hash_file_odin_16 - ctx.hash_stream_16 = hash_stream_odin_16 - ctx.hash_bytes_20 = hash_bytes_odin_20 - ctx.hash_file_20 = hash_file_odin_20 - ctx.hash_stream_20 = hash_stream_odin_20 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_40 = hash_bytes_odin_40 - ctx.hash_file_40 = hash_file_odin_40 - ctx.hash_stream_40 = hash_stream_odin_40 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_RIPEMD_160) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} /* High level API @@ -79,22 +28,44 @@ hash_string_128 :: proc(data: string) -> [16]byte { // hash_bytes_128 will hash the given input and return the // computed hash hash_bytes_128 :: proc(data: []byte) -> [16]byte { - _create_ripemd_ctx(16) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: Ripemd128_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_ripemd_ctx(16) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: Ripemd128_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle // and compute a hash hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_ripemd_ctx(16) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128(buf[:]), ok + } + } + return [16]byte{}, false } hash_128 :: proc { @@ -113,22 +84,44 @@ hash_string_160 :: proc(data: string) -> [20]byte { // hash_bytes_160 will hash the given input and return the // computed hash hash_bytes_160 :: proc(data: []byte) -> [20]byte { - _create_ripemd_ctx(20) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: Ripemd160_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_160 will read the stream in chunks and compute a // hash from its contents hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_ripemd_ctx(20) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: Ripemd160_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_160 will read the file provided by the given handle // and compute a hash hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_ripemd_ctx(20) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160(buf[:]), ok + } + } + return [20]byte{}, false } hash_160 :: proc { @@ -147,22 +140,44 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_ripemd_ctx(32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Ripemd256_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_ripemd_ctx(32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Ripemd256_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_ripemd_ctx(32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -181,22 +196,44 @@ hash_string_320 :: proc(data: string) -> [40]byte { // hash_bytes_320 will hash the given input and return the // computed hash hash_bytes_320 :: proc(data: []byte) -> [40]byte { - _create_ripemd_ctx(40) - return _hash_impl->hash_bytes_40(data) + hash: [40]byte + ctx: Ripemd320_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_320 will read the stream in chunks and compute a // hash from its contents hash_stream_320 :: proc(s: io.Stream) -> ([40]byte, bool) { - _create_ripemd_ctx(40) - return _hash_impl->hash_stream_40(s) + hash: [40]byte + ctx: Ripemd320_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_320 will read the file provided by the given handle // and compute a hash hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([40]byte, bool) { - _create_ripemd_ctx(40) - return _hash_impl->hash_file_40(hd, load_at_once) + if !load_at_once { + return hash_stream_320(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_320(buf[:]), ok + } + } + return [40]byte{}, false } hash_320 :: proc { @@ -206,261 +243,122 @@ hash_320 :: proc { hash_string_320, } -hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) +/* + Low level API +*/ + +init :: proc(ctx: ^$T) { + when T == Ripemd128_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 + } else when T == Ripemd160_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 + } else when T == Ripemd256_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 + ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] = S5, S6, S7, S8 + } else when T == Ripemd320_Context { + ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 + ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] = S5, S6, S7, S8, S9 } - return hash } -hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } +update :: proc(ctx: ^$T, data: []byte) { + ctx.tc += u64(len(data)) + data := data + if ctx.nx > 0 { + n := len(data) + + when T == Ripemd128_Context { + if n > RIPEMD_128_BLOCK_SIZE - ctx.nx { + n = RIPEMD_128_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd160_Context { + if n > RIPEMD_160_BLOCK_SIZE - ctx.nx { + n = RIPEMD_160_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd256_Context{ + if n > RIPEMD_256_BLOCK_SIZE - ctx.nx { + n = RIPEMD_256_BLOCK_SIZE - ctx.nx + } + } else when T == Ripemd320_Context{ + if n > RIPEMD_320_BLOCK_SIZE - ctx.nx { + n = RIPEMD_320_BLOCK_SIZE - ctx.nx + } } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} -hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_16(ctx, buf[:]), ok + for i := 0; i < n; i += 1 { + ctx.x[ctx.nx + i] = data[i] } - } - return [16]byte{}, false -} -hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } + ctx.nx += n + when T == Ripemd128_Context { + if ctx.nx == RIPEMD_128_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd160_Context { + if ctx.nx == RIPEMD_160_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd256_Context{ + if ctx.nx == RIPEMD_256_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } + } else when T == Ripemd320_Context{ + if ctx.nx == RIPEMD_320_BLOCK_SIZE { + block(ctx, ctx.x[0:]) + ctx.nx = 0 + } } - final_odin(&c, hash[:]) - return hash, true + data = data[n:] + } + n := block(ctx, data) + data = data[n:] + if len(data) > 0 { + ctx.nx = copy(ctx.x[:], data) + } +} + +final :: proc(ctx: ^$T, hash: []byte) { + d := ctx + tc := d.tc + tmp: [64]byte + tmp[0] = 0x80 + + if tc % 64 < 56 { + update(d, tmp[0:56 - tc % 64]) } else { - return hash, false + update(d, tmp[0:64 + 56 - tc % 64]) } + + tc <<= 3 + for i : u32 = 0; i < 8; i += 1 { + tmp[i] = byte(tc >> (8 * i)) + } + + update(d, tmp[0:8]) + + when T == Ripemd128_Context { + size :: RIPEMD_128_SIZE + } else when T == Ripemd160_Context { + size :: RIPEMD_160_SIZE + } else when T == Ripemd256_Context{ + size :: RIPEMD_256_SIZE + } else when T == Ripemd320_Context{ + size :: RIPEMD_320_SIZE + } + + digest: [size]byte + for s, i in d.s { + digest[i * 4] = byte(s) + digest[i * 4 + 1] = byte(s >> 8) + digest[i * 4 + 2] = byte(s >> 16) + digest[i * 4 + 3] = byte(s >> 24) + } + copy(hash[:], digest[:]) } -hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_20(ctx, buf[:]), ok - } - } - return [20]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_bytes_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [40]byte { - hash: [40]byte - if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([40]byte, bool) { - hash: [40]byte - if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_40 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([40]byte, bool) { - if !load_at_once { - return hash_stream_odin_40(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_40(ctx, buf[:]), ok - } - } - return [40]byte{}, false -} - -@(private) -_create_ripemd_ctx :: #force_inline proc(hash_size: int) { - switch hash_size { - case 16: - ctx: Ripemd128_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._16 - case 20: - ctx: Ripemd160_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._20 - case 32: - ctx: Ripemd256_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._32 - case 40: - ctx: Ripemd320_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._40 - } -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._16: - _create_ripemd_ctx(16) - if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { - init_odin(&c) - } - case ._20: - _create_ripemd_ctx(20) - if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { - init_odin(&c) - } - case ._32: - _create_ripemd_ctx(32) - if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { - init_odin(&c) - } - case ._40: - _create_ripemd_ctx(40) - if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { - init_odin(&c) - } - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - #partial switch ctx.hash_size { - case ._16: - if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { - update_odin(&c, data) - } - case ._20: - if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { - update_odin(&c, data) - } - case ._32: - if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { - update_odin(&c, data) - } - case ._40: - if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { - update_odin(&c, data) - } - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - #partial switch ctx.hash_size { - case ._16: - if c, ok := ctx.internal_ctx.(Ripemd128_Context); ok { - final_odin(&c, hash) - } - case ._20: - if c, ok := ctx.internal_ctx.(Ripemd160_Context); ok { - final_odin(&c, hash) - } - case ._32: - if c, ok := ctx.internal_ctx.(Ripemd256_Context); ok { - final_odin(&c, hash) - } - case ._40: - if c, ok := ctx.internal_ctx.(Ripemd320_Context); ok { - final_odin(&c, hash) - } - } -} /* RIPEMD implementation @@ -574,20 +472,6 @@ RIPEMD_160_R1 := [80]uint { 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11, } -init_odin :: proc(ctx: ^$T) { - when T == Ripemd128_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 - } else when T == Ripemd160_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 - } else when T == Ripemd256_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3] = S0, S1, S2, S3 - ctx.s[4], ctx.s[5], ctx.s[6], ctx.s[7] = S5, S6, S7, S8 - } else when T == Ripemd320_Context { - ctx.s[0], ctx.s[1], ctx.s[2], ctx.s[3], ctx.s[4] = S0, S1, S2, S3, S4 - ctx.s[5], ctx.s[6], ctx.s[7], ctx.s[8], ctx.s[9] = S5, S6, S7, S8, S9 - } -} - block :: #force_inline proc (ctx: ^$T, p: []byte) -> int { when T == Ripemd128_Context { return ripemd_128_block(ctx, p) @@ -948,101 +832,3 @@ ripemd_320_block :: proc(ctx: ^$T, p: []byte) -> int { } return n } - -update_odin :: proc(ctx: ^$T, p: []byte) { - ctx.tc += u64(len(p)) - p := p - if ctx.nx > 0 { - n := len(p) - - when T == Ripemd128_Context { - if n > RIPEMD_128_BLOCK_SIZE - ctx.nx { - n = RIPEMD_128_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd160_Context { - if n > RIPEMD_160_BLOCK_SIZE - ctx.nx { - n = RIPEMD_160_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd256_Context{ - if n > RIPEMD_256_BLOCK_SIZE - ctx.nx { - n = RIPEMD_256_BLOCK_SIZE - ctx.nx - } - } else when T == Ripemd320_Context{ - if n > RIPEMD_320_BLOCK_SIZE - ctx.nx { - n = RIPEMD_320_BLOCK_SIZE - ctx.nx - } - } - - for i := 0; i < n; i += 1 { - ctx.x[ctx.nx + i] = p[i] - } - - ctx.nx += n - when T == Ripemd128_Context { - if ctx.nx == RIPEMD_128_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd160_Context { - if ctx.nx == RIPEMD_160_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd256_Context{ - if ctx.nx == RIPEMD_256_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } else when T == Ripemd320_Context{ - if ctx.nx == RIPEMD_320_BLOCK_SIZE { - block(ctx, ctx.x[0:]) - ctx.nx = 0 - } - } - p = p[n:] - } - n := block(ctx, p) - p = p[n:] - if len(p) > 0 { - ctx.nx = copy(ctx.x[:], p) - } -} - -final_odin :: proc(ctx: ^$T, hash: []byte) { - d := ctx - tc := d.tc - tmp: [64]byte - tmp[0] = 0x80 - - if tc % 64 < 56 { - update_odin(d, tmp[0:56 - tc % 64]) - } else { - update_odin(d, tmp[0:64 + 56 - tc % 64]) - } - - tc <<= 3 - for i : u32 = 0; i < 8; i += 1 { - tmp[i] = byte(tc >> (8 * i)) - } - - update_odin(d, tmp[0:8]) - - when T == Ripemd128_Context { - size :: RIPEMD_128_SIZE - } else when T == Ripemd160_Context { - size :: RIPEMD_160_SIZE - } else when T == Ripemd256_Context{ - size :: RIPEMD_256_SIZE - } else when T == Ripemd320_Context{ - size :: RIPEMD_320_SIZE - } - - digest: [size]byte - for s, i in d.s { - digest[i * 4] = byte(s) - digest[i * 4 + 1] = byte(s >> 8) - digest[i * 4 + 2] = byte(s >> 16) - digest[i * 4 + 3] = byte(s >> 24) - } - copy(hash[:], digest[:]) -} diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index 022859309..736b207a3 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -6,7 +6,6 @@ package sha1 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 */ @@ -16,52 +15,10 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_20 = hash_bytes_odin - ctx.hash_file_20 = hash_file_odin - ctx.hash_stream_20 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA1) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} /* High level API */ - // hash_string will hash the given input and return the // computed hash hash_string :: proc(data: string) -> [20]byte { @@ -71,22 +28,44 @@ hash_string :: proc(data: string) -> [20]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [20]byte { - _create_sha1_ctx() - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: Sha1_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_sha1_ctx() - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: Sha1_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_sha1_ctx() - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [20]byte{}, false } hash :: proc { @@ -100,86 +79,70 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Sha1_Context) { + ctx.state[0] = 0x67452301 + ctx.state[1] = 0xefcdab89 + ctx.state[2] = 0x98badcfe + ctx.state[3] = 0x10325476 + ctx.state[4] = 0xc3d2e1f0 + ctx.k[0] = 0x5a827999 + ctx.k[1] = 0x6ed9eba1 + ctx.k[2] = 0x8f1bbcdc + ctx.k[3] = 0xca62c1d6 } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc(ctx: ^Sha1_Context, data: []byte) { + for i := 0; i < len(data); i += 1 { + ctx.data[ctx.datalen] = data[i] + ctx.datalen += 1 + if (ctx.datalen == BLOCK_SIZE) { + transform(ctx, ctx.data[:]) + ctx.bitlen += 512 + ctx.datalen = 0 + } + } } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} +final :: proc(ctx: ^Sha1_Context, hash: []byte) { + i := ctx.datalen -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Sha1_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - if c, ok := ctx.internal_ctx.(Sha1_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok + if ctx.datalen < 56 { + ctx.data[i] = 0x80 + i += 1 + for i < 56 { + ctx.data[i] = 0x00 + i += 1 } - } - return [20]byte{}, false -} + } + else { + ctx.data[i] = 0x80 + i += 1 + for i < BLOCK_SIZE { + ctx.data[i] = 0x00 + i += 1 + } + transform(ctx, ctx.data[:]) + mem.set(&ctx.data, 0, 56) + } -@(private) -_create_sha1_ctx :: #force_inline proc() { - ctx: Sha1_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._20 -} + ctx.bitlen += u64(ctx.datalen * 8) + ctx.data[63] = u8(ctx.bitlen) + ctx.data[62] = u8(ctx.bitlen >> 8) + ctx.data[61] = u8(ctx.bitlen >> 16) + ctx.data[60] = u8(ctx.bitlen >> 24) + ctx.data[59] = u8(ctx.bitlen >> 32) + ctx.data[58] = u8(ctx.bitlen >> 40) + ctx.data[57] = u8(ctx.bitlen >> 48) + ctx.data[56] = u8(ctx.bitlen >> 56) + transform(ctx, ctx.data[:]) -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_sha1_ctx() - if c, ok := ctx.internal_ctx.(Sha1_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Sha1_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Sha1_Context); ok { - final_odin(&c, hash) - } + for j: u32 = 0; j < 4; j += 1 { + hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff + hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff + hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff + hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff + hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff + } } /* @@ -258,69 +221,3 @@ transform :: proc(ctx: ^Sha1_Context, data: []byte) { ctx.state[3] += d ctx.state[4] += e } - -init_odin :: proc(ctx: ^Sha1_Context) { - ctx.state[0] = 0x67452301 - ctx.state[1] = 0xefcdab89 - ctx.state[2] = 0x98badcfe - ctx.state[3] = 0x10325476 - ctx.state[4] = 0xc3d2e1f0 - ctx.k[0] = 0x5a827999 - ctx.k[1] = 0x6ed9eba1 - ctx.k[2] = 0x8f1bbcdc - ctx.k[3] = 0xca62c1d6 -} - -update_odin :: proc(ctx: ^Sha1_Context, data: []byte) { - for i := 0; i < len(data); i += 1 { - ctx.data[ctx.datalen] = data[i] - ctx.datalen += 1 - if (ctx.datalen == BLOCK_SIZE) { - transform(ctx, ctx.data[:]) - ctx.bitlen += 512 - ctx.datalen = 0 - } - } -} - -final_odin :: proc(ctx: ^Sha1_Context, hash: []byte) { - i := ctx.datalen - - if ctx.datalen < 56 { - ctx.data[i] = 0x80 - i += 1 - for i < 56 { - ctx.data[i] = 0x00 - i += 1 - } - } - else { - ctx.data[i] = 0x80 - i += 1 - for i < BLOCK_SIZE { - ctx.data[i] = 0x00 - i += 1 - } - transform(ctx, ctx.data[:]) - mem.set(&ctx.data, 0, 56) - } - - ctx.bitlen += u64(ctx.datalen * 8) - ctx.data[63] = u8(ctx.bitlen) - ctx.data[62] = u8(ctx.bitlen >> 8) - ctx.data[61] = u8(ctx.bitlen >> 16) - ctx.data[60] = u8(ctx.bitlen >> 24) - ctx.data[59] = u8(ctx.bitlen >> 32) - ctx.data[58] = u8(ctx.bitlen >> 40) - ctx.data[57] = u8(ctx.bitlen >> 48) - ctx.data[56] = u8(ctx.bitlen >> 56) - transform(ctx, ctx.data[:]) - - for j: u32 = 0; j < 4; j += 1 { - hash[j] = u8(ctx.state[0] >> (24 - j * 8)) & 0x000000ff - hash[j + 4] = u8(ctx.state[1] >> (24 - j * 8)) & 0x000000ff - hash[j + 8] = u8(ctx.state[2] >> (24 - j * 8)) & 0x000000ff - hash[j + 12] = u8(ctx.state[3] >> (24 - j * 8)) & 0x000000ff - hash[j + 16] = u8(ctx.state[4] >> (24 - j * 8)) & 0x000000ff - } -} \ No newline at end of file diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 2ddbcf27a..8b7ccf38a 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -6,7 +6,6 @@ package sha2 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the SHA2 hashing algorithm, as defined in and in RFC 3874 @@ -17,72 +16,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA2) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_sha256_ctx :: #force_inline proc(is224: bool) { - ctx: Sha256_Context - ctx.is224 = is224 - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = is224 ? ._28 : ._32 -} - -@(private) -_create_sha512_ctx :: #force_inline proc(is384: bool) { - ctx: Sha512_Context - ctx.is384 = is384 - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = is384 ? ._48 : ._64 -} /* High level API @@ -97,22 +30,46 @@ hash_string_224 :: proc(data: string) -> [28]byte { // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_sha256_ctx(true) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: Sha256_Context + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_sha256_ctx(true) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_sha256_ctx(true) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -131,22 +88,46 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_sha256_ctx(false) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Sha256_Context + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_sha256_ctx(false) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_sha256_ctx(false) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -165,22 +146,46 @@ hash_string_384 :: proc(data: string) -> [48]byte { // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_sha512_ctx(true) - return _hash_impl->hash_bytes_48(data) + hash: [48]byte + ctx: Sha512_Context + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_sha512_ctx(true) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: Sha512_Context + ctx.is384 = true + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_sha512_ctx(true) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -199,22 +204,46 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_sha512_ctx(false) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_sha512_ctx(false) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_sha512_ctx(false) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -228,225 +257,121 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() -} - -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } +init :: proc(ctx: ^$T) { + when T == Sha256_Context { + if ctx.is224 { + ctx.h[0] = 0xc1059ed8 + ctx.h[1] = 0x367cd507 + ctx.h[2] = 0x3070dd17 + ctx.h[3] = 0xf70e5939 + ctx.h[4] = 0xffc00b31 + ctx.h[5] = 0x68581511 + ctx.h[6] = 0x64f98fa7 + ctx.h[7] = 0xbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667 + ctx.h[1] = 0xbb67ae85 + ctx.h[2] = 0x3c6ef372 + ctx.h[3] = 0xa54ff53a + ctx.h[4] = 0x510e527f + ctx.h[5] = 0x9b05688c + ctx.h[6] = 0x1f83d9ab + ctx.h[7] = 0x5be0cd19 } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok + } else when T == Sha512_Context { + if ctx.is384 { + ctx.h[0] = 0xcbbb9d5dc1059ed8 + ctx.h[1] = 0x629a292a367cd507 + ctx.h[2] = 0x9159015a3070dd17 + ctx.h[3] = 0x152fecd8f70e5939 + ctx.h[4] = 0x67332667ffc00b31 + ctx.h[5] = 0x8eb44a8768581511 + ctx.h[6] = 0xdb0c2e0d64f98fa7 + ctx.h[7] = 0x47b5481dbefa4fa4 + } else { + ctx.h[0] = 0x6a09e667f3bcc908 + ctx.h[1] = 0xbb67ae8584caa73b + ctx.h[2] = 0x3c6ef372fe94f82b + ctx.h[3] = 0xa54ff53a5f1d36f1 + ctx.h[4] = 0x510e527fade682d1 + ctx.h[5] = 0x9b05688c2b3e6c1f + ctx.h[6] = 0x1f83d9abfb41bd6b + ctx.h[7] = 0x5be0cd19137e2179 } } - return [28]byte{}, false } -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) +update :: proc(ctx: ^$T, data: []byte) { + length := uint(len(data)) + block_nb: uint + new_len, rem_len, tmp_len: uint + shifted_message := make([]byte, length) + + when T == Sha256_Context { + CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE + } else when T == Sha512_Context { + CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE } - return hash -} -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} + tmp_len = CURR_BLOCK_SIZE - ctx.length + rem_len = length < tmp_len ? length : tmp_len + copy(ctx.block[ctx.length:], data[:rem_len]) -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - if ctx.hash_size == ._28 || ctx.hash_size == ._32 { - _create_sha256_ctx(ctx.hash_size == ._28) - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - init_odin(&c) - } + if ctx.length + length < CURR_BLOCK_SIZE { + ctx.length += length return } - if ctx.hash_size == ._48 || ctx.hash_size == ._64 { - _create_sha512_ctx(ctx.hash_size == ._48) - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - init_odin(&c) - } - } + + new_len = length - rem_len + block_nb = new_len / CURR_BLOCK_SIZE + shifted_message = data[rem_len:] + + sha2_transf(ctx, ctx.block[:], 1) + sha2_transf(ctx, shifted_message, block_nb) + + rem_len = new_len % CURR_BLOCK_SIZE + when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} + else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} + + ctx.length = rem_len + when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} + else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} } -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - #partial switch ctx.hash_size { - case ._28, ._32: - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - update_odin(&c, data) - } - case ._48, ._64: - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - update_odin(&c, data) - } - } -} +final :: proc(ctx: ^$T, hash: []byte) { + block_nb, pm_len, len_b: u32 + i: i32 -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - #partial switch ctx.hash_size { - case ._28, ._32: - if c, ok := ctx.internal_ctx.(Sha256_Context); ok { - final_odin(&c, hash) - } - case ._48, ._64: - if c, ok := ctx.internal_ctx.(Sha512_Context); ok { - final_odin(&c, hash) - } - } + when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} + else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} + + when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} + + len_b = u32(ctx.tot_len + ctx.length) << 3 + when T == Sha256_Context {pm_len = block_nb << 6} + else when T == Sha512_Context {pm_len = block_nb << 7} + + mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) + ctx.block[ctx.length] = 0x80 + + util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) + + sha2_transf(ctx, ctx.block[:], uint(block_nb)) + + when T == Sha256_Context { + if ctx.is224 { + for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} + } + } else when T == Sha512_Context { + if ctx.is384 { + for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } else { + for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} + } + } } /* @@ -590,50 +515,6 @@ PACK64 :: #force_inline proc "contextless"(b: []byte, x: ^u64) { x^ = u64(b[7]) | u64(b[6]) << 8 | u64(b[5]) << 16 | u64(b[4]) << 24 | u64(b[3]) << 32 | u64(b[2]) << 40 | u64(b[1]) << 48 | u64(b[0]) << 56 } -init_odin :: proc(ctx: ^$T) { - when T == Sha256_Context { - if ctx.is224 { - ctx.h[0] = 0xc1059ed8 - ctx.h[1] = 0x367cd507 - ctx.h[2] = 0x3070dd17 - ctx.h[3] = 0xf70e5939 - ctx.h[4] = 0xffc00b31 - ctx.h[5] = 0x68581511 - ctx.h[6] = 0x64f98fa7 - ctx.h[7] = 0xbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667 - ctx.h[1] = 0xbb67ae85 - ctx.h[2] = 0x3c6ef372 - ctx.h[3] = 0xa54ff53a - ctx.h[4] = 0x510e527f - ctx.h[5] = 0x9b05688c - ctx.h[6] = 0x1f83d9ab - ctx.h[7] = 0x5be0cd19 - } - } else when T == Sha512_Context { - if ctx.is384 { - ctx.h[0] = 0xcbbb9d5dc1059ed8 - ctx.h[1] = 0x629a292a367cd507 - ctx.h[2] = 0x9159015a3070dd17 - ctx.h[3] = 0x152fecd8f70e5939 - ctx.h[4] = 0x67332667ffc00b31 - ctx.h[5] = 0x8eb44a8768581511 - ctx.h[6] = 0xdb0c2e0d64f98fa7 - ctx.h[7] = 0x47b5481dbefa4fa4 - } else { - ctx.h[0] = 0x6a09e667f3bcc908 - ctx.h[1] = 0xbb67ae8584caa73b - ctx.h[2] = 0x3c6ef372fe94f82b - ctx.h[3] = 0xa54ff53a5f1d36f1 - ctx.h[4] = 0x510e527fade682d1 - ctx.h[5] = 0x9b05688c2b3e6c1f - ctx.h[6] = 0x1f83d9abfb41bd6b - ctx.h[7] = 0x5be0cd19137e2179 - } - } -} - sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { when T == Sha256_Context { w: [64]u32 @@ -710,76 +591,3 @@ sha2_transf :: proc(ctx: ^$T, data: []byte, block_nb: uint) { } } } - -update_odin :: proc(ctx: ^$T, data: []byte) { - length := uint(len(data)) - block_nb: uint - new_len, rem_len, tmp_len: uint - shifted_message := make([]byte, length) - - when T == Sha256_Context { - CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE - } else when T == Sha512_Context { - CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE - } - - tmp_len = CURR_BLOCK_SIZE - ctx.length - rem_len = length < tmp_len ? length : tmp_len - copy(ctx.block[ctx.length:], data[:rem_len]) - - if ctx.length + length < CURR_BLOCK_SIZE { - ctx.length += length - return - } - - new_len = length - rem_len - block_nb = new_len / CURR_BLOCK_SIZE - shifted_message = data[rem_len:] - - sha2_transf(ctx, ctx.block[:], 1) - sha2_transf(ctx, shifted_message, block_nb) - - rem_len = new_len % CURR_BLOCK_SIZE - when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])} - else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])} - - ctx.length = rem_len - when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6} - else when T == Sha512_Context {ctx.tot_len += (block_nb + 1) << 7} -} - -final_odin :: proc(ctx: ^$T, hash: []byte) { - block_nb, pm_len, len_b: u32 - i: i32 - - when T == Sha256_Context {CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE} - else when T == Sha512_Context {CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE} - - when T == Sha256_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 9) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} - else when T == Sha512_Context {block_nb = 1 + ((CURR_BLOCK_SIZE - 17) < (ctx.length % CURR_BLOCK_SIZE) ? 1 : 0)} - - len_b = u32(ctx.tot_len + ctx.length) << 3 - when T == Sha256_Context {pm_len = block_nb << 6} - else when T == Sha512_Context {pm_len = block_nb << 7} - - mem.set(rawptr(&(ctx.block[ctx.length:])[0]), 0, int(uint(pm_len) - ctx.length)) - ctx.block[ctx.length] = 0x80 - - util.PUT_U32_BE(ctx.block[pm_len - 4:], len_b) - - sha2_transf(ctx, ctx.block[:], uint(block_nb)) - - when T == Sha256_Context { - if ctx.is224 { - for i = 0; i < 7; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {util.PUT_U32_BE(hash[i << 2:], ctx.h[i])} - } - } else when T == Sha512_Context { - if ctx.is384 { - for i = 0; i < 6; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} - } else { - for i = 0; i < 8; i += 1 {util.PUT_U64_BE(hash[i << 3:], ctx.h[i])} - } - } -} \ No newline at end of file diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index c37e369c9..1becf7640 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -6,7 +6,6 @@ package sha3 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the SHA3 hashing algorithm. The SHAKE functionality can be found in package shake. If you wish to compute a Keccak hash, you can use the keccak package, it will use the original padding. @@ -15,58 +14,8 @@ package sha3 import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../_sha3" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_28 = hash_bytes_odin_28 - ctx.hash_file_28 = hash_file_odin_28 - ctx.hash_stream_28 = hash_stream_odin_28 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_48 = hash_bytes_odin_48 - ctx.hash_file_48 = hash_file_odin_48 - ctx.hash_stream_48 = hash_stream_odin_48 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_SHA3) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -80,22 +29,46 @@ hash_string_224 :: proc(data: string) -> [28]byte { // hash_bytes_224 will hash the given input and return the // computed hash hash_bytes_224 :: proc(data: []byte) -> [28]byte { - _create_sha3_ctx(28) - return _hash_impl->hash_bytes_28(data) + hash: [28]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 28 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_224 will read the stream in chunks and compute a // hash from its contents hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - _create_sha3_ctx(28) - return _hash_impl->hash_stream_28(s) + hash: [28]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 28 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_224 will read the file provided by the given handle // and compute a hash hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - _create_sha3_ctx(28) - return _hash_impl->hash_file_28(hd, load_at_once) + if !load_at_once { + return hash_stream_224(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_224(buf[:]), ok + } + } + return [28]byte{}, false } hash_224 :: proc { @@ -114,22 +87,46 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_sha3_ctx(32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_sha3_ctx(32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_sha3_ctx(32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -148,22 +145,46 @@ hash_string_384 :: proc(data: string) -> [48]byte { // hash_bytes_384 will hash the given input and return the // computed hash hash_bytes_384 :: proc(data: []byte) -> [48]byte { - _create_sha3_ctx(48) - return _hash_impl->hash_bytes_48(data) + hash: [48]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 48 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_384 will read the stream in chunks and compute a // hash from its contents hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - _create_sha3_ctx(48) - return _hash_impl->hash_stream_48(s) + hash: [48]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 48 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_384 will read the file provided by the given handle // and compute a hash hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - _create_sha3_ctx(48) - return _hash_impl->hash_file_48(hd, load_at_once) + if !load_at_once { + return hash_stream_384(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_384(buf[:]), ok + } + } + return [48]byte{}, false } hash_384 :: proc { @@ -182,22 +203,46 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_sha3_ctx(64) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 64 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_sha3_ctx(64) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 64 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_sha3_ctx(64) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -211,218 +256,16 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +Sha3_Context :: _sha3.Sha3_Context + +init :: proc(ctx: ^_sha3.Sha3_Context) { + _sha3.init(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { + _sha3.update(ctx, data) } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [28]byte { - hash: [28]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([28]byte, bool) { - hash: [28]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_28 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { - if !load_at_once { - return hash_stream_odin_28(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_28(ctx, buf[:]), ok - } - } - return [28]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -hash_bytes_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [48]byte { - hash: [48]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([48]byte, bool) { - hash: [48]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_48 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { - if !load_at_once { - return hash_stream_odin_48(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_48(ctx, buf[:]), ok - } - } - return [48]byte{}, false -} - -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_create_sha3_ctx :: #force_inline proc(mdlen: int) { - ctx: _sha3.Sha3_Context - ctx.mdlen = mdlen - _hash_impl.internal_ctx = ctx - switch mdlen { - case 28: _hash_impl.hash_size = ._28 - case 32: _hash_impl.hash_size = ._32 - case 48: _hash_impl.hash_size = ._48 - case 64: _hash_impl.hash_size = ._64 - } -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._28: _create_sha3_ctx(28) - case ._32: _create_sha3_ctx(32) - case ._48: _create_sha3_ctx(48) - case ._64: _create_sha3_ctx(64) - } - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.final_odin(&c, hash) - } +final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { + _sha3.final(ctx, hash) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 2822dace2..ff477b1a9 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -6,7 +6,6 @@ package shake List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the SHAKE hashing algorithm. The SHA3 functionality can be found in package sha3. @@ -15,52 +14,8 @@ package shake import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../_sha3" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin_16 - ctx.hash_file_16 = hash_file_odin_16 - ctx.hash_stream_16 = hash_stream_odin_16 - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_SHAKE) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -74,22 +29,48 @@ hash_string_128 :: proc(data: string) -> [16]byte { // hash_bytes_128 will hash the given input and return the // computed hash hash_bytes_128 :: proc(data: []byte) -> [16]byte { - _create_shake_ctx(16) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 16 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_shake_ctx(16) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 16 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle // and compute a hash hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_shake_ctx(16) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128(buf[:]), ok + } + } + return [16]byte{}, false } hash_128 :: proc { @@ -108,22 +89,48 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_shake_ctx(32) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_shake_ctx(32) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: _sha3.Sha3_Context + ctx.mdlen = 32 + _sha3.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _sha3.update(&ctx, buf[:read]) + } + } + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_shake_ctx(32) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -137,137 +144,17 @@ hash_256 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +Sha3_Context :: _sha3.Sha3_Context + +init :: proc(ctx: ^_sha3.Sha3_Context) { + _sha3.init(ctx) } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) { + _sha3.update(ctx, data) } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.shake_xof_odin(&c) - _sha3.shake_out_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.shake_xof_odin(&c) - _sha3.shake_out_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_16(ctx, buf[:]), ok - } - } - return [16]byte{}, false -} - -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - _sha3.update_odin(&c, data) - _sha3.shake_xof_odin(&c) - _sha3.shake_out_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _sha3.update_odin(&c, buf[:read]) - } - } - _sha3.shake_xof_odin(&c) - _sha3.shake_out_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} - -@(private) -_create_shake_ctx :: #force_inline proc(mdlen: int) { - ctx: _sha3.Sha3_Context - ctx.mdlen = mdlen - _hash_impl.internal_ctx = ctx - switch mdlen { - case 16: _hash_impl.hash_size = ._16 - case 32: _hash_impl.hash_size = ._32 - } -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._16: _create_shake_ctx(16) - case ._32: _create_shake_ctx(32) - } - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_sha3.Sha3_Context); ok { - _sha3.shake_xof_odin(&c) - _sha3.shake_out_odin(&c, hash[:]) - } +final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) { + _sha3.shake_xof(ctx) + _sha3.shake_out(ctx, hash[:]) } diff --git a/core/crypto/skein/skein.odin b/core/crypto/skein/skein.odin deleted file mode 100644 index 45623d480..000000000 --- a/core/crypto/skein/skein.odin +++ /dev/null @@ -1,487 +0,0 @@ -package skein - -/* - Copyright 2021 zhibog - Made available under the BSD-3 license. - - List of contributors: - zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. - - Implementation of the SKEIN hashing algorithm, as defined in - - This package offers the internal state sizes of 256, 512 and 1024 bits and arbitrary output size. -*/ - -import "core:os" -import "core:io" - -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - ctx.is_using_odin = false - } else { - _assign_hash_vtable(ctx) - ctx.is_using_odin = true - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - // @note(zh): Default to SKEIN-512 - ctx.hash_bytes_slice = hash_bytes_skein512_odin - ctx.hash_file_slice = hash_file_skein512_odin - ctx.hash_stream_slice = hash_stream_skein512_odin - ctx.init = _init_skein512_odin - ctx.update = _update_skein512_odin - ctx.final = _final_skein512_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - _hash_impl.is_using_odin = false - // @note(zh): Botan only supports SKEIN-512. - botan.assign_hash_vtable(_hash_impl, botan.HASH_SKEIN_512) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -@(warning="SKEIN is not yet implemented in Odin. Botan bindings will be used") -use_odin :: #force_inline proc() { - // _hash_impl.is_using_odin = true - // _assign_hash_vtable(_hash_impl) - use_botan() -} - -@(private) -_create_skein256_ctx :: #force_inline proc(size: int) { - _hash_impl.hash_size_val = size - if _hash_impl.is_using_odin { - ctx: Skein256_Context - ctx.h.bit_length = u64(size) - _hash_impl.internal_ctx = ctx - _hash_impl.hash_bytes_slice = hash_bytes_skein256_odin - _hash_impl.hash_file_slice = hash_file_skein256_odin - _hash_impl.hash_stream_slice = hash_stream_skein256_odin - _hash_impl.init = _init_skein256_odin - _hash_impl.update = _update_skein256_odin - _hash_impl.final = _final_skein256_odin - } -} - -@(private) -_create_skein512_ctx :: #force_inline proc(size: int) { - _hash_impl.hash_size_val = size - if _hash_impl.is_using_odin { - ctx: Skein512_Context - ctx.h.bit_length = u64(size) - _hash_impl.internal_ctx = ctx - _hash_impl.hash_bytes_slice = hash_bytes_skein512_odin - _hash_impl.hash_file_slice = hash_file_skein512_odin - _hash_impl.hash_stream_slice = hash_stream_skein512_odin - _hash_impl.init = _init_skein512_odin - _hash_impl.update = _update_skein512_odin - _hash_impl.final = _final_skein512_odin - } -} - -@(private) -_create_skein1024_ctx :: #force_inline proc(size: int) { - _hash_impl.hash_size_val = size - if _hash_impl.is_using_odin { - ctx: Skein1024_Context - ctx.h.bit_length = u64(size) - _hash_impl.internal_ctx = ctx - _hash_impl.hash_bytes_slice = hash_bytes_skein1024_odin - _hash_impl.hash_file_slice = hash_file_skein1024_odin - _hash_impl.hash_stream_slice = hash_stream_skein1024_odin - _hash_impl.init = _init_skein1024_odin - _hash_impl.update = _update_skein1024_odin - _hash_impl.final = _final_skein1024_odin - } -} - -/* - High level API -*/ - -// hash_skein256_string will hash the given input and return the -// computed hash -hash_skein256_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { - return hash_skein256_bytes(transmute([]byte)(data), bit_size, allocator) -} - -// hash_skein256_bytes will hash the given input and return the -// computed hash -hash_skein256_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - _create_skein256_ctx(bit_size) - return _hash_impl->hash_bytes_slice(data, bit_size, allocator) -} - -// hash_skein256_stream will read the stream in chunks and compute a -// hash from its contents -hash_skein256_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - _create_skein256_ctx(bit_size) - return _hash_impl->hash_stream_slice(s, bit_size, allocator) -} - -// hash_skein256_file will read the file provided by the given handle -// and compute a hash -hash_skein256_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - _create_skein256_ctx(bit_size) - return _hash_impl->hash_file_slice(hd, bit_size, load_at_once, allocator) -} - -hash_skein256 :: proc { - hash_skein256_stream, - hash_skein256_file, - hash_skein256_bytes, - hash_skein256_string, -} - -// hash_skein512_string will hash the given input and return the -// computed hash -hash_skein512_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { - return hash_skein512_bytes(transmute([]byte)(data), bit_size, allocator) -} - -// hash_skein512_bytes will hash the given input and return the -// computed hash -hash_skein512_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - _create_skein512_ctx(bit_size) - return _hash_impl->hash_bytes_slice(data, bit_size, allocator) -} - -// hash_skein512_stream will read the stream in chunks and compute a -// hash from its contents -hash_skein512_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - _create_skein512_ctx(bit_size) - return _hash_impl->hash_stream_slice(s, bit_size, allocator) -} - -// hash_skein512_file will read the file provided by the given handle -// and compute a hash -hash_skein512_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - _create_skein512_ctx(bit_size) - return _hash_impl->hash_file_slice(hd, bit_size, load_at_once, allocator) -} - -hash_skein512 :: proc { - hash_skein512_stream, - hash_skein512_file, - hash_skein512_bytes, - hash_skein512_string, -} - -// hash_skein1024_string will hash the given input and return the -// computed hash -hash_skein1024_string :: proc(data: string, bit_size: int, allocator := context.allocator) -> []byte { - return hash_skein1024_bytes(transmute([]byte)(data), bit_size, allocator) -} - -// hash_skein1024_bytes will hash the given input and return the -// computed hash -hash_skein1024_bytes :: proc(data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - _create_skein1024_ctx(bit_size) - return _hash_impl->hash_bytes_slice(data, bit_size, allocator) -} - -// hash_skein1024_stream will read the stream in chunks and compute a -// hash from its contents -hash_skein1024_stream :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - _create_skein1024_ctx(bit_size) - return _hash_impl->hash_stream_slice(s, bit_size, allocator) -} - -// hash_skein1024_file will read the file provided by the given handle -// and compute a hash -hash_skein1024_file :: proc(hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - _create_skein1024_ctx(bit_size) - return _hash_impl->hash_file_slice(hd, bit_size, load_at_once, allocator) -} - -hash_skein1024 :: proc { - hash_skein1024_stream, - hash_skein1024_file, - hash_skein1024_bytes, - hash_skein1024_string, -} - -/* - Low level API -*/ - -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() -} - -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} - -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein256_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - return hash - } else { - delete(hash) - return nil - } -} - -hash_stream_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein256_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - delete(hash) - return nil, false - } -} - -hash_file_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - if !load_at_once { - return hash_stream_skein256_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_skein256_odin(ctx, buf[:], bit_size, allocator), ok - } - } - return nil, false -} - -hash_bytes_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein512_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - return hash - } else { - delete(hash) - return nil - } -} - -hash_stream_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein512_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - delete(hash) - return nil, false - } -} - -hash_file_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - if !load_at_once { - return hash_stream_skein512_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_skein512_odin(ctx, buf[:], bit_size, allocator), ok - } - } - return nil, false -} - -hash_bytes_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte, bit_size: int, allocator := context.allocator) -> []byte { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - return hash - } else { - delete(hash) - return nil - } -} - -hash_stream_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { - hash := make([]byte, bit_size, allocator) - if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - delete(hash) - return nil, false - } -} - -hash_file_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, bit_size: int, load_at_once := false, allocator := context.allocator) -> ([]byte, bool) { - if !load_at_once { - return hash_stream_skein512_odin(ctx, os.stream_from_handle(hd), bit_size, allocator) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_skein512_odin(ctx, buf[:], bit_size, allocator), ok - } - } - return nil, false -} - -@(private) -_init_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_skein256_ctx(ctx.hash_size_val) - if c, ok := ctx.internal_ctx.(Skein256_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Skein256_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_skein256_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Skein256_Context); ok { - final_odin(&c, hash) - } -} - -@(private) -_init_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_skein512_ctx(ctx.hash_size_val) - if c, ok := ctx.internal_ctx.(Skein512_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Skein512_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_skein512_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Skein512_Context); ok { - final_odin(&c, hash) - } -} - -@(private) -_init_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_skein1024_ctx(ctx.hash_size_val) - if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_skein1024_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Skein1024_Context); ok { - final_odin(&c, hash) - } -} - -/* - SKEIN implementation -*/ - -STATE_WORDS_256 :: 4 -STATE_WORDS_512 :: 8 -STATE_WORDS_1024 :: 16 - -STATE_BYTES_256 :: 32 -STATE_BYTES_512 :: 64 -STATE_BYTES_1024 :: 128 - -Skein_Header :: struct { - bit_length: u64, - bcnt: u64, - t: [2]u64, -} - -Skein256_Context :: struct { - h: Skein_Header, - x: [STATE_WORDS_256]u64, - b: [STATE_BYTES_256]byte, -} - -Skein512_Context :: struct { - h: Skein_Header, - x: [STATE_WORDS_512]u64, - b: [STATE_BYTES_512]byte, -} - -Skein1024_Context :: struct { - h: Skein_Header, - x: [STATE_WORDS_1024]u64, - b: [STATE_BYTES_1024]byte, -} - - -init_odin :: proc(ctx: ^$T) { - -} - -update_odin :: proc(ctx: ^$T, data: []byte) { - -} - -final_odin :: proc(ctx: ^$T, hash: []byte) { - -} \ No newline at end of file diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index bd1f6f98a..c72bd4f15 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -6,7 +6,6 @@ package sm3 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the SM3 hashing algorithm, as defined in */ @@ -15,51 +14,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_32 = hash_bytes_odin - ctx.hash_file_32 = hash_file_odin - ctx.hash_stream_32 = hash_stream_odin - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_SM3) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -/* - High level API -*/ // hash_string will hash the given input and return the // computed hash @@ -70,22 +24,44 @@ hash_string :: proc(data: string) -> [32]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [32]byte { - _create_sm3_ctx() - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Sm3_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_sm3_ctx() - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Sm3_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_sm3_ctx() - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [32]byte{}, false } hash :: proc { @@ -99,86 +75,64 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Sm3_Context) { + ctx.state[0] = IV[0] + ctx.state[1] = IV[1] + ctx.state[2] = IV[2] + ctx.state[3] = IV[3] + ctx.state[4] = IV[4] + ctx.state[5] = IV[5] + ctx.state[6] = IV[6] + ctx.state[7] = IV[7] } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) -} +update :: proc(ctx: ^Sm3_Context, data: []byte) { + data := data + ctx.length += u64(len(data)) -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} - -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Sm3_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Sm3_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } + if ctx.bitlength > 0 { + n := copy(ctx.x[ctx.bitlength:], data[:]) + ctx.bitlength += u64(n) + if ctx.bitlength == 64 { + block(ctx, ctx.x[:]) + ctx.bitlength = 0 } - final_odin(&c, hash[:]) - return hash, true + data = data[n:] + } + if len(data) >= 64 { + n := len(data) &~ (64 - 1) + block(ctx, data[:n]) + data = data[n:] + } + if len(data) > 0 { + ctx.bitlength = u64(copy(ctx.x[:], data[:])) + } +} + +final :: proc(ctx: ^Sm3_Context, hash: []byte) { + length := ctx.length + + pad: [64]byte + pad[0] = 0x80 + if length % 64 < 56 { + update(ctx, pad[0: 56 - length % 64]) } else { - return hash, false + update(ctx, pad[0: 64 + 56 - length % 64]) } -} -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} + length <<= 3 + util.PUT_U64_BE(pad[:], length) + update(ctx, pad[0: 8]) + assert(ctx.bitlength == 0) -@(private) -_create_sm3_ctx :: #force_inline proc() { - ctx: Sm3_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._32 -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_sm3_ctx() - if c, ok := ctx.internal_ctx.(Sm3_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Sm3_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Sm3_Context); ok { - final_odin(&c, hash) - } + util.PUT_U32_BE(hash[0:], ctx.state[0]) + util.PUT_U32_BE(hash[4:], ctx.state[1]) + util.PUT_U32_BE(hash[8:], ctx.state[2]) + util.PUT_U32_BE(hash[12:], ctx.state[3]) + util.PUT_U32_BE(hash[16:], ctx.state[4]) + util.PUT_U32_BE(hash[20:], ctx.state[5]) + util.PUT_U32_BE(hash[24:], ctx.state[6]) + util.PUT_U32_BE(hash[28:], ctx.state[7]) } /* @@ -200,17 +154,6 @@ IV := [8]u32 { 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, } -init_odin :: proc(ctx: ^Sm3_Context) { - ctx.state[0] = IV[0] - ctx.state[1] = IV[1] - ctx.state[2] = IV[2] - ctx.state[3] = IV[3] - ctx.state[4] = IV[4] - ctx.state[5] = IV[5] - ctx.state[6] = IV[6] - ctx.state[7] = IV[7] -} - block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { buf := buf @@ -282,52 +225,3 @@ block :: proc "contextless" (ctx: ^Sm3_Context, buf: []byte) { ctx.state[0], ctx.state[1], ctx.state[2], ctx.state[3] = state0, state1, state2, state3 ctx.state[4], ctx.state[5], ctx.state[6], ctx.state[7] = state4, state5, state6, state7 } - -update_odin :: proc(ctx: ^Sm3_Context, data: []byte) { - data := data - ctx.length += u64(len(data)) - - if ctx.bitlength > 0 { - n := copy(ctx.x[ctx.bitlength:], data[:]) - ctx.bitlength += u64(n) - if ctx.bitlength == 64 { - block(ctx, ctx.x[:]) - ctx.bitlength = 0 - } - data = data[n:] - } - if len(data) >= 64 { - n := len(data) &~ (64 - 1) - block(ctx, data[:n]) - data = data[n:] - } - if len(data) > 0 { - ctx.bitlength = u64(copy(ctx.x[:], data[:])) - } -} - -final_odin :: proc(ctx: ^Sm3_Context, hash: []byte) { - length := ctx.length - - pad: [64]byte - pad[0] = 0x80 - if length % 64 < 56 { - update_odin(ctx, pad[0: 56 - length % 64]) - } else { - update_odin(ctx, pad[0: 64 + 56 - length % 64]) - } - - length <<= 3 - util.PUT_U64_BE(pad[:], length) - update_odin(ctx, pad[0: 8]) - assert(ctx.bitlength == 0) - - util.PUT_U32_BE(hash[0:], ctx.state[0]) - util.PUT_U32_BE(hash[4:], ctx.state[1]) - util.PUT_U32_BE(hash[8:], ctx.state[2]) - util.PUT_U32_BE(hash[12:], ctx.state[3]) - util.PUT_U32_BE(hash[16:], ctx.state[4]) - util.PUT_U32_BE(hash[20:], ctx.state[5]) - util.PUT_U32_BE(hash[24:], ctx.state[6]) - util.PUT_U32_BE(hash[28:], ctx.state[7]) -} diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin index 385fbdc44..b90ef8e86 100644 --- a/core/crypto/streebog/streebog.odin +++ b/core/crypto/streebog/streebog.odin @@ -6,7 +6,6 @@ package streebog List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the Streebog hashing algorithm, standardized as GOST R 34.11-2012 in RFC 6986 */ @@ -15,58 +14,6 @@ import "core:os" import "core:io" import "../util" -import "../botan" -import "../_ctx" - -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_32 = hash_bytes_odin_32 - ctx.hash_file_32 = hash_file_odin_32 - ctx.hash_stream_32 = hash_stream_odin_32 - ctx.hash_bytes_64 = hash_bytes_odin_64 - ctx.hash_file_64 = hash_file_odin_64 - ctx.hash_stream_64 = hash_stream_odin_64 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_STREEBOG) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - -@(private) -_create_streebog_ctx :: #force_inline proc(is256: bool) { - ctx: Streebog_Context - ctx.is256 = is256 - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = is256 ? ._32 : ._64 -} /* High level API @@ -81,22 +28,46 @@ hash_string_256 :: proc(data: string) -> [32]byte { // hash_bytes_256 will hash the given input and return the // computed hash hash_bytes_256 :: proc(data: []byte) -> [32]byte { - _create_streebog_ctx(true) - return _hash_impl->hash_bytes_32(data) + hash: [32]byte + ctx: Streebog_Context + ctx.is256 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_256 will read the stream in chunks and compute a // hash from its contents hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - _create_streebog_ctx(true) - return _hash_impl->hash_stream_32(s) + hash: [32]byte + ctx: Streebog_Context + ctx.is256 = true + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_256 will read the file provided by the given handle // and compute a hash hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - _create_streebog_ctx(true) - return _hash_impl->hash_file_32(hd, load_at_once) + if !load_at_once { + return hash_stream_256(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_256(buf[:]), ok + } + } + return [32]byte{}, false } hash_256 :: proc { @@ -115,22 +86,44 @@ hash_string_512 :: proc(data: string) -> [64]byte { // hash_bytes_512 will hash the given input and return the // computed hash hash_bytes_512 :: proc(data: []byte) -> [64]byte { - _create_streebog_ctx(false) - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: Streebog_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream_512 will read the stream in chunks and compute a // hash from its contents hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_streebog_ctx(false) - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Streebog_Context + init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file_512 will read the file provided by the given handle // and compute a hash hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_streebog_ctx(false) - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream_512(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_512(buf[:]), ok + } + } + return [64]byte{}, false } hash_512 :: proc { @@ -144,120 +137,64 @@ hash_512 :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +init :: proc(ctx: ^Streebog_Context) { + if ctx.is256 { + ctx.hash_size = 256 + for _, i in ctx.h { + ctx.h[i] = 0x01 + } + } else { + ctx.hash_size = 512 + } + ctx.v_512[1] = 0x02 } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc(ctx: ^Streebog_Context, data: []byte) { + length := u64(len(data)) + chk_size: u64 + data := data + for (length > 63) && (ctx.buf_size == 0) { + stage2(ctx, data) + data = data[64:] + length -= 64 + } + + for length != 0 { + chk_size = 64 - ctx.buf_size + if chk_size > length { + chk_size = length + } + copy(ctx.buffer[ctx.buf_size:], data[:chk_size]) + ctx.buf_size += chk_size + length -= chk_size + data = data[chk_size:] + if ctx.buf_size == 64 { + stage2(ctx, ctx.buffer[:]) + ctx.buf_size = 0 + } + } } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} +final :: proc(ctx: ^Streebog_Context, hash: []byte) { + t: [64]byte + t[1] = byte((ctx.buf_size * 8) >> 8) & 0xff + t[0] = byte((ctx.buf_size) * 8) & 0xff -hash_bytes_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [32]byte { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} + padding(ctx) -hash_stream_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([32]byte, bool) { - hash: [32]byte - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} + G(ctx.h[:], ctx.n[:], ctx.buffer[:]) -hash_file_odin_32 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { - if !load_at_once { - return hash_stream_odin_32(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_32(ctx, buf[:]), ok - } - } - return [32]byte{}, false -} + add_mod_512(ctx.n[:], t[:], ctx.n[:]) + add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:]) -hash_bytes_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - init_odin(&c) - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} + G(ctx.h[:], ctx.v_0[:], ctx.n[:]) + G(ctx.h[:], ctx.v_0[:], ctx.sigma[:]) -hash_stream_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_64 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin_64(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_64(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} - -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - _create_streebog_ctx(ctx.hash_size == ._32) - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - init_odin(&c) - } -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Streebog_Context); ok { - final_odin(&c, hash) - } + if ctx.is256 { + copy(hash[:], ctx.h[32:]) + } else { + copy(hash[:], ctx.h[:]) + } } /* @@ -534,63 +471,3 @@ padding :: proc(ctx: ^Streebog_Context) { copy(ctx.buffer[:], t[:]) } } - -init_odin :: proc(ctx: ^Streebog_Context) { - if ctx.is256 { - ctx.hash_size = 256 - for _, i in ctx.h { - ctx.h[i] = 0x01 - } - } else { - ctx.hash_size = 512 - } - ctx.v_512[1] = 0x02 -} - -update_odin :: proc(ctx: ^Streebog_Context, data: []byte) { - length := u64(len(data)) - chk_size: u64 - data := data - for (length > 63) && (ctx.buf_size == 0) { - stage2(ctx, data) - data = data[64:] - length -= 64 - } - - for length != 0 { - chk_size = 64 - ctx.buf_size - if chk_size > length { - chk_size = length - } - copy(ctx.buffer[ctx.buf_size:], data[:chk_size]) - ctx.buf_size += chk_size - length -= chk_size - data = data[chk_size:] - if ctx.buf_size == 64 { - stage2(ctx, ctx.buffer[:]) - ctx.buf_size = 0 - } - } -} - -final_odin :: proc(ctx: ^Streebog_Context, hash: []byte) { - t: [64]byte - t[1] = byte((ctx.buf_size * 8) >> 8) & 0xff - t[0] = byte((ctx.buf_size) * 8) & 0xff - - padding(ctx) - - G(ctx.h[:], ctx.n[:], ctx.buffer[:]) - - add_mod_512(ctx.n[:], t[:], ctx.n[:]) - add_mod_512(ctx.sigma[:], ctx.buffer[:], ctx.sigma[:]) - - G(ctx.h[:], ctx.v_0[:], ctx.n[:]) - G(ctx.h[:], ctx.v_0[:], ctx.sigma[:]) - - if ctx.is256 { - copy(hash[:], ctx.h[32:]) - } else { - copy(hash[:], ctx.h[:]) - } -} \ No newline at end of file diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin index 240375b90..ecd7f5583 100644 --- a/core/crypto/tiger/tiger.odin +++ b/core/crypto/tiger/tiger.odin @@ -6,7 +6,6 @@ package tiger List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the Tiger1 variant of the Tiger hashing algorithm as defined in */ @@ -14,55 +13,8 @@ package tiger import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../_tiger" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin_16 - ctx.hash_file_16 = hash_file_odin_16 - ctx.hash_stream_16 = hash_stream_odin_16 - ctx.hash_bytes_20 = hash_bytes_odin_20 - ctx.hash_file_20 = hash_file_odin_20 - ctx.hash_stream_20 = hash_stream_odin_20 - ctx.hash_bytes_24 = hash_bytes_odin_24 - ctx.hash_file_24 = hash_file_odin_24 - ctx.hash_stream_24 = hash_stream_odin_24 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_TIGER) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -76,22 +28,46 @@ hash_string_128 :: proc(data: string) -> [16]byte { // hash_bytes_128 will hash the given input and return the // computed hash hash_bytes_128 :: proc(data: []byte) -> [16]byte { - _create_tiger_ctx(16) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_tiger_ctx(16) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle // and compute a hash hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_tiger_ctx(16) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128(buf[:]), ok + } + } + return [16]byte{}, false } hash_128 :: proc { @@ -110,22 +86,46 @@ hash_string_160 :: proc(data: string) -> [20]byte { // hash_bytes_160 will hash the given input and return the // computed hash hash_bytes_160 :: proc(data: []byte) -> [20]byte { - _create_tiger_ctx(20) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_160 will read the stream in chunks and compute a // hash from its contents hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_tiger_ctx(20) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_160 will read the file provided by the given handle // and compute a hash hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_tiger_ctx(20) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160(buf[:]), ok + } + } + return [20]byte{}, false } hash_160 :: proc { @@ -144,22 +144,46 @@ hash_string_192 :: proc(data: string) -> [24]byte { // hash_bytes_192 will hash the given input and return the // computed hash hash_bytes_192 :: proc(data: []byte) -> [24]byte { - _create_tiger_ctx(24) - return _hash_impl->hash_bytes_24(data) + hash: [24]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_192 will read the stream in chunks and compute a // hash from its contents hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { - _create_tiger_ctx(24) - return _hash_impl->hash_stream_24(s) + hash: [24]byte + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_192 will read the file provided by the given handle // and compute a hash hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - _create_tiger_ctx(24) - return _hash_impl->hash_file_24(hd, load_at_once) + if !load_at_once { + return hash_stream_192(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_192(buf[:]), ok + } + } + return [24]byte{}, false } hash_192 :: proc { @@ -169,163 +193,21 @@ hash_192 :: proc { hash_string_192, } -hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} +/* + Low level API +*/ -hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} +Tiger_Context :: _tiger.Tiger_Context -hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_16(ctx, buf[:]), ok - } - } - return [16]byte{}, false -} - -hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_20(ctx, buf[:]), ok - } - } - return [20]byte{}, false -} - -hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { - hash: [24]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { - hash: [24]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - if !load_at_once { - return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_24(ctx, buf[:]), ok - } - } - return [24]byte{}, false -} - -@(private) -_create_tiger_ctx :: #force_inline proc(hash_size: int) { - ctx: _tiger.Tiger_Context +init :: proc(ctx: ^_tiger.Tiger_Context) { ctx.ver = 1 - _hash_impl.internal_ctx = ctx - switch hash_size { - case 16: _hash_impl.hash_size = ._16 - case 20: _hash_impl.hash_size = ._20 - case 24: _hash_impl.hash_size = ._24 - } + _tiger.init(ctx) } -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._16: _create_tiger_ctx(16) - case ._20: _create_tiger_ctx(20) - case ._24: _create_tiger_ctx(24) - } - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - } +update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) { + _tiger.update(ctx, data) } -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.final_odin(&c, hash) - } -} +final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) { + _tiger.final(ctx, hash) +} \ No newline at end of file diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin index a61d271ad..a93e19319 100644 --- a/core/crypto/tiger2/tiger2.odin +++ b/core/crypto/tiger2/tiger2.odin @@ -6,7 +6,6 @@ package tiger2 List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Interface for the Tiger2 variant of the Tiger hashing algorithm as defined in */ @@ -14,55 +13,8 @@ package tiger2 import "core:os" import "core:io" -import "../_ctx" import "../_tiger" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_16 = hash_bytes_odin_16 - ctx.hash_file_16 = hash_file_odin_16 - ctx.hash_stream_16 = hash_stream_odin_16 - ctx.hash_bytes_20 = hash_bytes_odin_20 - ctx.hash_file_20 = hash_file_odin_20 - ctx.hash_stream_20 = hash_stream_odin_20 - ctx.hash_bytes_24 = hash_bytes_odin_24 - ctx.hash_file_24 = hash_file_odin_24 - ctx.hash_stream_24 = hash_stream_odin_24 - ctx.init = _init_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan does nothing, since Tiger2 is not available in Botan -@(warning="Tiger2 is not provided by the Botan API. Odin implementation will be used") -use_botan :: #force_inline proc() { - use_odin() -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -76,22 +28,46 @@ hash_string_128 :: proc(data: string) -> [16]byte { // hash_bytes_128 will hash the given input and return the // computed hash hash_bytes_128 :: proc(data: []byte) -> [16]byte { - _create_tiger2_ctx(16) - return _hash_impl->hash_bytes_16(data) + hash: [16]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_128 will read the stream in chunks and compute a // hash from its contents hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - _create_tiger2_ctx(16) - return _hash_impl->hash_stream_16(s) + hash: [16]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_128 will read the file provided by the given handle // and compute a hash hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - _create_tiger2_ctx(16) - return _hash_impl->hash_file_16(hd, load_at_once) + if !load_at_once { + return hash_stream_128(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_128(buf[:]), ok + } + } + return [16]byte{}, false } hash_128 :: proc { @@ -110,22 +86,46 @@ hash_string_160 :: proc(data: string) -> [20]byte { // hash_bytes_160 will hash the given input and return the // computed hash hash_bytes_160 :: proc(data: []byte) -> [20]byte { - _create_tiger2_ctx(20) - return _hash_impl->hash_bytes_20(data) + hash: [20]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_160 will read the stream in chunks and compute a // hash from its contents hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - _create_tiger2_ctx(20) - return _hash_impl->hash_stream_20(s) + hash: [20]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_160 will read the file provided by the given handle // and compute a hash hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - _create_tiger2_ctx(20) - return _hash_impl->hash_file_20(hd, load_at_once) + if !load_at_once { + return hash_stream_160(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_160(buf[:]), ok + } + } + return [20]byte{}, false } hash_160 :: proc { @@ -144,22 +144,46 @@ hash_string_192 :: proc(data: string) -> [24]byte { // hash_bytes_192 will hash the given input and return the // computed hash hash_bytes_192 :: proc(data: []byte) -> [24]byte { - _create_tiger2_ctx(24) - return _hash_impl->hash_bytes_24(data) + hash: [24]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash[:]) + return hash } // hash_stream_192 will read the stream in chunks and compute a // hash from its contents hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { - _create_tiger2_ctx(24) - return _hash_impl->hash_stream_24(s) + hash: [24]byte + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + _tiger.update(&ctx, buf[:read]) + } + } + _tiger.final(&ctx, hash[:]) + return hash, true } // hash_file_192 will read the file provided by the given handle // and compute a hash hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - _create_tiger2_ctx(24) - return _hash_impl->hash_file_24(hd, load_at_once) + if !load_at_once { + return hash_stream_192(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes_192(buf[:]), ok + } + } + return [24]byte{}, false } hash_192 :: proc { @@ -169,163 +193,21 @@ hash_192 :: proc { hash_string_192, } -hash_bytes_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [16]byte { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} +/* + Low level API +*/ -hash_stream_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([16]byte, bool) { - hash: [16]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} +Tiger_Context :: _tiger.Tiger_Context -hash_file_odin_16 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { - if !load_at_once { - return hash_stream_odin_16(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_16(ctx, buf[:]), ok - } - } - return [16]byte{}, false -} - -hash_bytes_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [20]byte { - hash: [20]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([20]byte, bool) { - hash: [20]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_20 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { - if !load_at_once { - return hash_stream_odin_20(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_20(ctx, buf[:]), ok - } - } - return [20]byte{}, false -} - -hash_bytes_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [24]byte { - hash: [24]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - _tiger.update_odin(&c, data) - _tiger.final_odin(&c, hash[:]) - } - return hash -} - -hash_stream_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([24]byte, bool) { - hash: [24]byte - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - _tiger.update_odin(&c, buf[:read]) - } - } - _tiger.final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} - -hash_file_odin_24 :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { - if !load_at_once { - return hash_stream_odin_24(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin_24(ctx, buf[:]), ok - } - } - return [24]byte{}, false -} - -@(private) -_create_tiger2_ctx :: #force_inline proc(hash_size: int) { - ctx: _tiger.Tiger_Context +init :: proc(ctx: ^_tiger.Tiger_Context) { ctx.ver = 2 - _hash_impl.internal_ctx = ctx - switch hash_size { - case 16: _hash_impl.hash_size = ._16 - case 20: _hash_impl.hash_size = ._20 - case 24: _hash_impl.hash_size = ._24 - } + _tiger.init(ctx) } -@(private) -_init_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - #partial switch ctx.hash_size { - case ._16: _create_tiger2_ctx(16) - case ._20: _create_tiger2_ctx(20) - case ._24: _create_tiger2_ctx(24) - } - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.init_odin(&c) - } +update :: proc(ctx: ^_tiger.Tiger_Context, data: []byte) { + _tiger.update(ctx, data) } -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(_tiger.Tiger_Context); ok { - _tiger.final_odin(&c, hash) - } +final :: proc(ctx: ^_tiger.Tiger_Context, hash: []byte) { + _tiger.final(ctx, hash) } \ No newline at end of file diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin index ce0123318..43ad2a0a5 100644 --- a/core/crypto/whirlpool/whirlpool.odin +++ b/core/crypto/whirlpool/whirlpool.odin @@ -6,7 +6,6 @@ package whirlpool List of contributors: zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings. Implementation of the Whirlpool hashing algorithm, as defined in */ @@ -14,48 +13,8 @@ package whirlpool import "core:os" import "core:io" -import "../botan" -import "../_ctx" import "../util" -/* - Context initialization and switching between the Odin implementation and the bindings -*/ - -USE_BOTAN_LIB :: bool(#config(USE_BOTAN_LIB, false)) - -@(private) -_init_vtable :: #force_inline proc() -> ^_ctx.Hash_Context { - ctx := _ctx._init_vtable() - when USE_BOTAN_LIB { - use_botan() - } else { - _assign_hash_vtable(ctx) - } - return ctx -} - -@(private) -_assign_hash_vtable :: #force_inline proc(ctx: ^_ctx.Hash_Context) { - ctx.hash_bytes_64 = hash_bytes_odin - ctx.hash_file_64 = hash_file_odin - ctx.hash_stream_64 = hash_stream_odin - ctx.update = _update_odin - ctx.final = _final_odin -} - -_hash_impl := _init_vtable() - -// use_botan assigns the internal vtable of the hash context to use the Botan bindings -use_botan :: #force_inline proc() { - botan.assign_hash_vtable(_hash_impl, botan.HASH_WHIRLPOOL) -} - -// use_odin assigns the internal vtable of the hash context to use the Odin implementation -use_odin :: #force_inline proc() { - _assign_hash_vtable(_hash_impl) -} - /* High level API */ @@ -69,22 +28,44 @@ hash_string :: proc(data: string) -> [64]byte { // hash_bytes will hash the given input and return the // computed hash hash_bytes :: proc(data: []byte) -> [64]byte { - _create_whirlpool_ctx() - return _hash_impl->hash_bytes_64(data) + hash: [64]byte + ctx: Whirlpool_Context + // init(&ctx) No-op + update(&ctx, data) + final(&ctx, hash[:]) + return hash } // hash_stream will read the stream in chunks and compute a // hash from its contents hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - _create_whirlpool_ctx() - return _hash_impl->hash_stream_64(s) + hash: [64]byte + ctx: Whirlpool_Context + // init(&ctx) No-op + buf := make([]byte, 512) + defer delete(buf) + read := 1 + for read > 0 { + read, _ = s->impl_read(buf) + if read > 0 { + update(&ctx, buf[:read]) + } + } + final(&ctx, hash[:]) + return hash, true } // hash_file will read the file provided by the given handle // and compute a hash hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - _create_whirlpool_ctx() - return _hash_impl->hash_file_64(hd, load_at_once) + if !load_at_once { + return hash_stream(os.stream_from_handle(hd)) + } else { + if buf, ok := os.read_entire_file(hd); ok { + return hash_bytes(buf[:]), ok + } + } + return [64]byte{}, false } hash :: proc { @@ -98,76 +79,103 @@ hash :: proc { Low level API */ -init :: proc(ctx: ^_ctx.Hash_Context) { - _hash_impl->init() +@(warning="Init is a no-op for Whirlpool") +init :: proc(ctx: ^Whirlpool_Context) { + // No action needed here } -update :: proc(ctx: ^_ctx.Hash_Context, data: []byte) { - _hash_impl->update(data) +update :: proc(ctx: ^Whirlpool_Context, source: []byte) { + source_pos: int + nn := len(source) + source_bits := u64(nn * 8) + source_gap := u32((8 - (int(source_bits & 7))) & 7) + buffer_rem := uint(ctx.buffer_bits & 7) + b: u32 + + for i, carry, value := 31, u32(0), u32(source_bits); i >= 0 && (carry != 0 || value != 0); i -= 1 { + carry += u32(ctx.bitlength[i]) + (u32(value & 0xff)) + ctx.bitlength[i] = byte(carry) + carry >>= 8 + value >>= 8 + } + + for source_bits > 8 { + b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap))) + + ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem) + ctx.buffer_pos += 1 + ctx.buffer_bits += int(8 - buffer_rem) + + if ctx.buffer_bits == 512 { + transform(ctx) + ctx.buffer_bits = 0 + ctx.buffer_pos = 0 + } + ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) + ctx.buffer_bits += int(buffer_rem) + source_bits -= 8 + source_pos += 1 + } + + if source_bits > 0 { + b = u32((source[source_pos] << source_gap) & 0xff) + ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem + } else {b = 0} + + if u64(buffer_rem) + source_bits < 8 { + ctx.buffer_bits += int(source_bits) + } else { + ctx.buffer_pos += 1 + ctx.buffer_bits += 8 - int(buffer_rem) + source_bits -= u64(8 - buffer_rem) + + if ctx.buffer_bits == 512 { + transform(ctx) + ctx.buffer_bits = 0 + ctx.buffer_pos = 0 + } + ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) + ctx.buffer_bits += int(source_bits) + } } -final :: proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - _hash_impl->final(hash) -} +final :: proc(ctx: ^Whirlpool_Context, hash: []byte) { + n := ctx + n.buffer[n.buffer_pos] |= 0x80 >> (uint(n.buffer_bits) & 7) + n.buffer_pos += 1 -hash_bytes_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) -> [64]byte { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { - update_odin(&c, data) - final_odin(&c, hash[:]) - } - return hash -} + if n.buffer_pos > 64 - 32 { + if n.buffer_pos < 64 { + for i := 0; i < 64 - n.buffer_pos; i += 1 { + n.buffer[n.buffer_pos + i] = 0 + } + } + transform(ctx) + n.buffer_pos = 0 + } -hash_stream_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, fs: io.Stream) -> ([64]byte, bool) { - hash: [64]byte - if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { - buf := make([]byte, 512) - defer delete(buf) - read := 1 - for read > 0 { - read, _ = fs->impl_read(buf) - if read > 0 { - update_odin(&c, buf[:read]) - } - } - final_odin(&c, hash[:]) - return hash, true - } else { - return hash, false - } -} + if n.buffer_pos < 64 - 32 { + for i := 0; i < (64 - 32) - n.buffer_pos; i += 1 { + n.buffer[n.buffer_pos + i] = 0 + } + } + n.buffer_pos = 64 - 32 -hash_file_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { - if !load_at_once { - return hash_stream_odin(ctx, os.stream_from_handle(hd)) - } else { - if buf, ok := os.read_entire_file(hd); ok { - return hash_bytes_odin(ctx, buf[:]), ok - } - } - return [64]byte{}, false -} + for i := 0; i < 32; i += 1 { + n.buffer[n.buffer_pos + i] = n.bitlength[i] + } + transform(ctx) -@(private) -_create_whirlpool_ctx :: #force_inline proc() { - ctx: Whirlpool_Context - _hash_impl.internal_ctx = ctx - _hash_impl.hash_size = ._64 -} - -@(private) -_update_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, data: []byte) { - if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { - update_odin(&c, data) - } -} - -@(private) -_final_odin :: #force_inline proc(ctx: ^_ctx.Hash_Context, hash: []byte) { - if c, ok := ctx.internal_ctx.(Whirlpool_Context); ok { - final_odin(&c, hash) - } + for i := 0; i < 8; i += 1 { + hash[i * 8] = byte(n.hash[i] >> 56) + hash[i * 8 + 1] = byte(n.hash[i] >> 48) + hash[i * 8 + 2] = byte(n.hash[i] >> 40) + hash[i * 8 + 3] = byte(n.hash[i] >> 32) + hash[i * 8 + 4] = byte(n.hash[i] >> 24) + hash[i * 8 + 5] = byte(n.hash[i] >> 16) + hash[i * 8 + 6] = byte(n.hash[i] >> 8) + hash[i * 8 + 7] = byte(n.hash[i]) + } } /* @@ -774,97 +782,3 @@ transform :: proc (ctx: ^Whirlpool_Context) { } for i := 0; i < 8; i += 1 {ctx.hash[i] ~= state[i] ~ block[i]} } - -update_odin :: proc(ctx: ^Whirlpool_Context, source: []byte) { - source_pos: int - nn := len(source) - source_bits := u64(nn * 8) - source_gap := u32((8 - (int(source_bits & 7))) & 7) - buffer_rem := uint(ctx.buffer_bits & 7) - b: u32 - - for i, carry, value := 31, u32(0), u32(source_bits); i >= 0 && (carry != 0 || value != 0); i -= 1 { - carry += u32(ctx.bitlength[i]) + (u32(value & 0xff)) - ctx.bitlength[i] = byte(carry) - carry >>= 8 - value >>= 8 - } - - for source_bits > 8 { - b = u32(u32((source[source_pos] << source_gap) & 0xff) | u32((source[source_pos+1] & 0xff) >> (8 - source_gap))) - - ctx.buffer[ctx.buffer_pos] |= u8(b >> buffer_rem) - ctx.buffer_pos += 1 - ctx.buffer_bits += int(8 - buffer_rem) - - if ctx.buffer_bits == 512 { - transform(ctx) - ctx.buffer_bits = 0 - ctx.buffer_pos = 0 - } - ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) - ctx.buffer_bits += int(buffer_rem) - source_bits -= 8 - source_pos += 1 - } - - if source_bits > 0 { - b = u32((source[source_pos] << source_gap) & 0xff) - ctx.buffer[ctx.buffer_pos] |= byte(b) >> buffer_rem - } else {b = 0} - - if u64(buffer_rem) + source_bits < 8 { - ctx.buffer_bits += int(source_bits) - } else { - ctx.buffer_pos += 1 - ctx.buffer_bits += 8 - int(buffer_rem) - source_bits -= u64(8 - buffer_rem) - - if ctx.buffer_bits == 512 { - transform(ctx) - ctx.buffer_bits = 0 - ctx.buffer_pos = 0 - } - ctx.buffer[ctx.buffer_pos] = byte(b << (8 - buffer_rem)) - ctx.buffer_bits += int(source_bits) - } -} - -final_odin :: proc(ctx: ^Whirlpool_Context, hash: []byte) { - n := ctx - n.buffer[n.buffer_pos] |= 0x80 >> (uint(n.buffer_bits) & 7) - n.buffer_pos += 1 - - if n.buffer_pos > 64 - 32 { - if n.buffer_pos < 64 { - for i := 0; i < 64 - n.buffer_pos; i += 1 { - n.buffer[n.buffer_pos + i] = 0 - } - } - transform(ctx) - n.buffer_pos = 0 - } - - if n.buffer_pos < 64 - 32 { - for i := 0; i < (64 - 32) - n.buffer_pos; i += 1 { - n.buffer[n.buffer_pos + i] = 0 - } - } - n.buffer_pos = 64 - 32 - - for i := 0; i < 32; i += 1 { - n.buffer[n.buffer_pos + i] = n.bitlength[i] - } - transform(ctx) - - for i := 0; i < 8; i += 1 { - hash[i * 8] = byte(n.hash[i] >> 56) - hash[i * 8 + 1] = byte(n.hash[i] >> 48) - hash[i * 8 + 2] = byte(n.hash[i] >> 40) - hash[i * 8 + 3] = byte(n.hash[i] >> 32) - hash[i * 8 + 4] = byte(n.hash[i] >> 24) - hash[i * 8 + 5] = byte(n.hash[i] >> 16) - hash[i * 8 + 6] = byte(n.hash[i] >> 8) - hash[i * 8 + 7] = byte(n.hash[i]) - } -} \ No newline at end of file diff --git a/tests/core/botan.dll b/tests/core/botan.dll deleted file mode 100644 index 423231d86..000000000 Binary files a/tests/core/botan.dll and /dev/null differ diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index a50d67ddf..df9920552 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -33,7 +33,6 @@ import "core:crypto/tiger2" import "core:crypto/gost" import "core:crypto/streebog" import "core:crypto/sm3" -import "core:crypto/skein" import "core:crypto/jh" import "core:crypto/groestl" import "core:crypto/haval" @@ -102,7 +101,6 @@ main :: proc() { test_tiger2_160(&t) test_tiger2_192(&t) test_sm3(&t) - test_skein512(&t) test_jh_224(&t) test_jh_256(&t) test_jh_384(&t) @@ -171,13 +169,6 @@ test_md4 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - md4.use_botan() - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - } @(test) @@ -197,12 +188,6 @@ test_md5 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - md5.use_botan() - for v, _ in test_vectors { - computed := md5.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -225,15 +210,8 @@ test_sha1 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha1.use_botan() - for v, _ in test_vectors { - computed := sha1.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } - @(test) test_sha224 :: proc(t: ^testing.T) { // Test vectors from @@ -250,12 +228,6 @@ test_sha224 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha2.use_botan() - for v, _ in test_vectors { - computed := sha2.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -274,13 +246,6 @@ test_sha256 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha2.use_botan() - for v, _ in test_vectors { - computed := sha2.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - } @(test) @@ -299,13 +264,6 @@ test_sha384 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha2.use_botan() - for v, _ in test_vectors { - computed := sha2.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - } @(test) @@ -324,15 +282,8 @@ test_sha512 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha2.use_botan() - for v, _ in test_vectors { - computed := sha2.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } - @(test) test_sha3_224 :: proc(t: ^testing.T) { // Test vectors from @@ -353,12 +304,6 @@ test_sha3_224 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := sha3.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -381,12 +326,6 @@ test_sha3_256 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := sha3.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -409,12 +348,6 @@ test_sha3_384 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := sha3.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -437,12 +370,6 @@ test_sha3_512 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := sha3.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -457,12 +384,6 @@ test_shake_128 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := shake.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -477,12 +398,6 @@ test_shake_256 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sha3.use_botan() - for v, _ in test_vectors { - computed := shake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -499,12 +414,6 @@ test_keccak_224 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - keccak.use_botan() - for v, _ in test_vectors { - computed := keccak.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -521,12 +430,6 @@ test_keccak_256 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - keccak.use_botan() - for v, _ in test_vectors { - computed := keccak.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -543,12 +446,6 @@ test_keccak_384 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - keccak.use_botan() - for v, _ in test_vectors { - computed := keccak.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -565,12 +462,6 @@ test_keccak_512 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - keccak.use_botan() - for v, _ in test_vectors { - computed := keccak.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -597,12 +488,6 @@ test_whirlpool :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - whirlpool.use_botan() - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -623,12 +508,6 @@ test_gost :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - gost.use_botan() - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -643,12 +522,6 @@ test_streebog_256 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - streebog.use_botan() - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -663,12 +536,6 @@ test_streebog_512 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - streebog.use_botan() - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -738,12 +605,6 @@ test_blake2b :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - blake2b.use_botan() - for v, _ in test_vectors { - computed := blake2b.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -797,12 +658,6 @@ test_ripemd_160 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - ripemd.use_botan() - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -863,12 +718,6 @@ test_tiger_128 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - tiger.use_botan() - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -889,12 +738,6 @@ test_tiger_160 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - tiger.use_botan() - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -915,12 +758,6 @@ test_tiger_192 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - tiger.use_botan() - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test) @@ -979,26 +816,6 @@ test_sm3 :: proc(t: ^testing.T) { computed_str := hex_string(computed[:]) expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) } - sm3.use_botan() - for v, _ in test_vectors { - computed := sm3.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } -} - -@(test) -test_skein512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a", ""}, - TestHash{"94c2ae036dba8783d0b3f7d6cc111ff810702f5c77707999be7e1c9486ff238a7044de734293147359b4ac7e1d09cd247c351d69826b78dcddd951f0ef912713", "The quick brown fox jumps over the lazy dog"}, - } - skein.use_botan() - for v, _ in test_vectors { - computed := skein.hash_skein512(v.str, 64) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } } @(test)