diff --git a/core/crypto/noise/api.odin b/core/crypto/noise/api.odin index 30387c2b4..bae58a399 100644 --- a/core/crypto/noise/api.odin +++ b/core/crypto/noise/api.odin @@ -1,7 +1,10 @@ package noise import "base:runtime" +import "core:crypto/aead" import "core:crypto/ecdh" +import "core:crypto/hash" +import "core:strings" // MAX_PACKET_SIZE is the maximum Noise message size, including TAG_SIZE // if relevant (`seal_message`, `open_message`). diff --git a/core/crypto/noise/protocol.odin b/core/crypto/noise/protocol.odin index 00d8cbb3d..883376a42 100644 --- a/core/crypto/noise/protocol.odin +++ b/core/crypto/noise/protocol.odin @@ -9,7 +9,6 @@ import "core:crypto/hash" import "core:crypto/hkdf" import "core:encoding/endian" import "core:slice" -import "core:strings" AEAD_KEY_SIZE :: 32 @@ -967,96 +966,11 @@ handshakestate_read_message :: proc(self: ^Handshake_State, message, dst: []byte @(require_results) protocol_from_string :: proc(self: ^Protocol, protocol_name: string) -> Status { - str := protocol_name self^ = Protocol{} - if len(str) > 255 { - return .Invalid_Protocol_String - } - - s, ok := strings.split_by_byte_iterator(&str, '_') - if !ok || s != "Noise" { - return .Invalid_Protocol_String - } - - if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok { - return .Invalid_Protocol_String - } - pattern: Handshake_Pattern - switch s { - case "N" : pattern = .N - case "K" : pattern = .K - case "X" : pattern = .X - case "XX": pattern = .XX - case "NK": pattern = .NK - case "NN": pattern = .NN - case "KN": pattern = .KN - case "KK": pattern = .KK - case "NX": pattern = .NX - case "KX": pattern = .KX - case "XN": pattern = .XN - case "IN": pattern = .IN - case "XK": pattern = .XK - case "IK": pattern = .IK - case "IX": pattern = .IX - case "Npsk0": pattern = .Npsk0 - case "Kpsk0": pattern = .Kpsk0 - case "Xpsk1": pattern = .Xpsk1 - case "NNpsk0": pattern = .NNpsk0 - case "NNpsk2": pattern = .NNpsk2 - case "NKpsk0": pattern = .NKpsk0 - case "NKpsk2": pattern = .NKpsk2 - case "NXpsk2": pattern = .NXpsk2 - case "XNpsk3": pattern = .XNpsk3 - case "XKpsk3": pattern = .XKpsk3 - case "XXpsk3": pattern = .XXpsk3 - case "KNpsk0": pattern = .KNpsk0 - case "KNpsk2": pattern = .KNpsk2 - case "KKpsk0": pattern = .KKpsk0 - case "KKpsk2": pattern = .KKpsk2 - case "KXpsk2": pattern = .KXpsk2 - case "INpsk1": pattern = .INpsk1 - case "INpsk2": pattern = .INpsk2 - case "IKpsk1": pattern = .IKpsk1 - case "IKpsk2": pattern = .IKpsk2 - case "IXpsk2": pattern = .IXpsk2 - case: return .Invalid_Protocol_String - } - - if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok { - return .Invalid_Protocol_String - } - dh: ecdh.Curve - switch s { - case "25519": dh = .X25519 - case "448": dh = .X448 - case: return .Invalid_Protocol_String - } - - if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok { - return .Invalid_Protocol_String - } - cipher: aead.Algorithm - switch s { - case "AESGCM": cipher = .AES_GCM_256 - case "ChaChaPoly": cipher = .CHACHA20POLY1305 - case: return .Invalid_Protocol_String - } - - if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok { - return .Invalid_Protocol_String - } - hash: hash.Algorithm - switch s { - case "SHA512": hash = .SHA512 - case "SHA256": hash = .SHA256 - case "Blake2s": hash = .BLAKE2S - case "Blake2b": hash = .BLAKE2B - case: return .Invalid_Protocol_String - } - - if len(str) != 0 { - return .Invalid_Protocol_String + pattern, dh, cipher, hash, status := split_protocol_string(protocol_name) + if status != .Ok { + return status } self.handshake_pattern = pattern diff --git a/examples/all/all_js.odin b/examples/all/all_js.odin index 3e45565e0..74cdb5fd3 100644 --- a/examples/all/all_js.odin +++ b/examples/all/all_js.odin @@ -43,6 +43,7 @@ package all @(require) import "core:crypto/legacy/keccak" @(require) import "core:crypto/legacy/md5" @(require) import "core:crypto/legacy/sha1" +@(require) import cnoise "core:crypto/noise" @(require) import "core:crypto/pbkdf2" @(require) import "core:crypto/poly1305" @(require) import "core:crypto/ristretto255" diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 65e4b917c..973ee423e 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -48,6 +48,7 @@ package all @(require) import "core:crypto/legacy/keccak" @(require) import "core:crypto/legacy/md5" @(require) import "core:crypto/legacy/sha1" +@(require) import cnoise "core:crypto/noise" @(require) import "core:crypto/pbkdf2" @(require) import "core:crypto/poly1305" @(require) import "core:crypto/ristretto255" diff --git a/core/crypto/noise/test_crypto_noise.odin b/tests/core/crypto/test_core_crypto_noise.odin similarity index 74% rename from core/crypto/noise/test_crypto_noise.odin rename to tests/core/crypto/test_core_crypto_noise.odin index 50a540f97..6371900ca 100644 --- a/core/crypto/noise/test_crypto_noise.odin +++ b/tests/core/crypto/test_core_crypto_noise.odin @@ -1,10 +1,11 @@ -package noise +package test_core_crypto import "core:bytes" import "core:crypto" import "core:crypto/aead" import "core:crypto/ecdh" import "core:crypto/hash" +import "core:crypto/noise" import "core:fmt" import "core:log" import "core:math/rand" @@ -36,7 +37,7 @@ test_supported_protocols :: proc(t: ^testing.T) { } protocol: Test_Protocol - for pattern in Handshake_Pattern { + for pattern in noise.Handshake_Pattern { if pattern == .Invalid { continue } @@ -68,13 +69,13 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat log.debugf("crypto/noise: %s", protocol_name) - is_one_way := pattern_is_one_way(protocol.handshake_pattern) + is_one_way := noise.pattern_is_one_way(protocol.handshake_pattern) initiator_s, responder_s: ecdh.Private_Key ini_s, res_s: ^ecdh.Private_Key ini_s_pub, res_s_pub: ^ecdh.Public_Key - pre, hs := pattern_requires_initiator_s(protocol.handshake_pattern) + pre, hs := noise.pattern_requires_initiator_s(protocol.handshake_pattern) if pre || hs { if !testing.expect(t, ecdh.private_key_generate(&initiator_s, protocol.dh), "failed to generate initiator s") { return false @@ -84,7 +85,7 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat ini_s_pub = &initiator_s._pub_key } } - pre, hs = pattern_requires_responder_s(protocol.handshake_pattern) + pre, hs = noise.pattern_requires_responder_s(protocol.handshake_pattern) if pre || hs { if !testing.expect(t, ecdh.private_key_generate(&responder_s, protocol.dh), "failed to generate responder s") { return false @@ -97,32 +98,32 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat psk_buf: [32]byte = --- psk: []byte - if pattern_is_psk(protocol.handshake_pattern) { + if noise.pattern_is_psk(protocol.handshake_pattern) { crypto.rand_bytes(psk_buf[:]) psk = psk_buf[:] } - ini_hs, res_hs: Handshake_State - status := handshake_init(&ini_hs, true, nil, ini_s, res_s_pub, protocol_name, psk) + ini_hs, res_hs: noise.Handshake_State + status := noise.handshake_init(&ini_hs, true, nil, ini_s, res_s_pub, protocol_name, psk) if !testing.expectf(t, status == .Ok, "failed to initialize initiator Handshake_State: %v", status) { return false } - status = handshake_init(&res_hs, false, nil, res_s, ini_s_pub, protocol_name, psk) + status = noise.handshake_init(&res_hs, false, nil, res_s, ini_s_pub, protocol_name, psk) if !testing.expectf(t, status == .Ok, "failed to initialize responder Handshake_State: %v", status) { return false } - ini_status, res_status: Status + ini_status, res_status: noise.Status ini_msg, res_msg: []byte ini_payload, res_payload: []byte - hs_msg_buf: [MAX_STEP_MSG_SIZE]byte - for i := 0; ; i += 1{ + hs_msg_buf: [noise.MAX_STEP_MSG_SIZE]byte + for i := 0; ; i += 1 { if ini_status == .Handshake_Complete && res_status == .Handshake_Complete { break } // Test the allocation path - res_msg, res_payload, ini_status = handshake_initiator_step(&ini_hs, ini_msg, allocator = allocator) + res_msg, res_payload, ini_status = noise.handshake_initiator_step(&ini_hs, ini_msg, allocator = allocator) ini_msg = nil if ini_status == .Handshake_Complete && res_status == .Handshake_Complete { @@ -137,7 +138,7 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat } // Test the non-allocation path - ini_msg, ini_payload, res_status = handshake_responder_step(&res_hs, res_msg, nil, hs_msg_buf[:]) + ini_msg, ini_payload, res_status = noise.handshake_responder_step(&res_hs, res_msg, nil, dst = hs_msg_buf[:]) delete(res_msg, allocator) res_msg = nil @@ -152,7 +153,7 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat hs_pub: ^ecdh.Public_Key if ini_s != nil { - hs_pub, status = handshake_peer_identity(&res_hs) + hs_pub, status = noise.handshake_peer_identity(&res_hs) if !testing.expect(t, status == .Ok) { return false } @@ -161,7 +162,7 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat } } if res_s != nil { - hs_pub, status = handshake_peer_identity(&ini_hs) + hs_pub, status = noise.handshake_peer_identity(&ini_hs) if !testing.expect(t, status == .Ok) { return false } @@ -171,11 +172,11 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat } h1, h2: []byte - h1, status = handshake_hash(&ini_hs) + h1, status = noise.handshake_hash(&ini_hs) if !testing.expect(t, status == .Ok) { return false } - h2, status = handshake_hash(&res_hs) + h2, status = noise.handshake_hash(&res_hs) if !testing.expect(t, status == .Ok) { return false } @@ -183,31 +184,31 @@ test_noise_one_protocol :: proc(t: ^testing.T, protocol: ^Test_Protocol, allocat return false } - ini_cs, res_cs: Cipher_States - if !testing.expectf(t, .Ok == handshake_split(&ini_hs, &ini_cs), "failed to split initiator: %v") { + ini_cs, res_cs: noise.Cipher_States + if !testing.expectf(t, .Ok == noise.handshake_split(&ini_hs, &ini_cs), "failed to split initiator: %v") { return false } - if !testing.expectf(t, .Ok == handshake_split(&res_hs, &res_cs), "failed to split responder: %v") { + if !testing.expectf(t, .Ok == noise.handshake_split(&res_hs, &res_cs), "failed to split responder: %v") { return false } - handshake_reset(&ini_hs) - handshake_reset(&res_hs) + noise.handshake_reset(&ini_hs) + noise.handshake_reset(&res_hs) if !testing.expect(t, test_messages(t, &ini_cs, &res_cs, is_one_way, allocator), "message tests failed") { return false } - cipherstates_reset(&ini_cs) - cipherstates_reset(&res_cs) + noise.cipherstates_reset(&ini_cs) + noise.cipherstates_reset(&res_cs) return true } @(private = "file") -test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^Cipher_States, is_one_way: bool, allocator := context.allocator) -> bool { +test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^noise.Cipher_States, is_one_way: bool, allocator := context.allocator) -> bool { ad_buf: [256]byte = --- - payload_buf: [MAX_PACKET_SIZE-TAG_SIZE]byte = --- + payload_buf: [noise.MAX_PACKET_SIZE-noise.TAG_SIZE]byte = --- for i in 0..<10 { ad := ad_buf[:rand.int_max(len(ad_buf))] @@ -217,14 +218,14 @@ test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^Cipher_States, is_one_way: _ = rand.read(ad) // Initiator -> Responder (allocate buffers) - tx_msg, status := seal_message(ini_cs, ad, payload, allocator = allocator) + tx_msg, status := noise.seal_message(ini_cs, ad, payload, allocator = allocator) defer delete(tx_msg, allocator) if !testing.expectf(t, status == .Ok, "i->r %d: seal failed: %v", i, status) { return false } rx_dst: []byte - rx_dst, status = open_message(res_cs, ad, tx_msg, allocator = allocator) + rx_dst, status = noise.open_message(res_cs, ad, tx_msg, allocator = allocator) defer delete(rx_dst, allocator) if !testing.expectf(t, status == .Ok, "i->r %d: open failed: %v", i, status) { return false @@ -235,11 +236,11 @@ test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^Cipher_States, is_one_way: } if i == 5 { - status = cipherstates_rekey(ini_cs, true) + status = noise.cipherstates_rekey(ini_cs, true) if !testing.expectf(t, status == .Ok, "i %d: rekey failed: %v", i, status) { return false } - status = cipherstates_rekey(res_cs, false) + status = noise.cipherstates_rekey(res_cs, false) if !testing.expectf(t, status == .Ok, "r %d: rekey failed: %v", i, status) { return false } @@ -250,12 +251,12 @@ test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^Cipher_States, is_one_way: } // Responder -> Initiator (reuse allocated buffers) - tx_msg, status = seal_message(res_cs, ad, payload, tx_msg) + tx_msg, status = noise.seal_message(res_cs, ad, payload, tx_msg) if !testing.expectf(t, status == .Ok, "r->i %d: seal failed: %v", i, status) { return false } - _, status = open_message(ini_cs, ad, tx_msg, rx_dst) + _, status = noise.open_message(ini_cs, ad, tx_msg, rx_dst) if !testing.expectf(t, status == .Ok, "r->i %d: open failed: %v", i, status) { return false } @@ -270,7 +271,7 @@ test_messages :: proc(t: ^testing.T, ini_cs, res_cs: ^Cipher_States, is_one_way: @(private = "file") Test_Protocol :: struct { - handshake_pattern: Handshake_Pattern, + handshake_pattern: noise.Handshake_Pattern, dh: ecdh.Curve, cipher: aead.Algorithm, hash: hash.Algorithm, @@ -296,8 +297,8 @@ test_protocol_string :: proc(protocol: ^Test_Protocol, allocator := context.allo #partial switch protocol.hash { case .SHA256: hash = "SHA256" case .SHA512: hash = "SHA512" - case .BLAKE2S: hash = "Blake2s" - case .BLAKE2B: hash = "Blake2b" + case .BLAKE2S: hash = "BLAKE2s" + case .BLAKE2B: hash = "BLAKE2b" case: panic("crypto/noise: unsupported hash") }