core/crypto/noise: Add support for deferred patterns

This commit is contained in:
Yawning Angel
2026-04-20 00:43:28 +09:00
parent 81c89a6094
commit 81011ec361
4 changed files with 539 additions and 5 deletions

View File

@@ -459,3 +459,129 @@ cipherstates_cs :: proc(self: ^Cipher_States, seal_key: bool) -> ^Cipher_State {
}
unreachable()
}
// split_protocol_string splits a protocol string into individual components.
@(require_results)
split_protocol_string :: proc(protocol_name: string) -> (Handshake_Pattern, ecdh.Curve, aead.Algorithm, hash.Algorithm, Status) {
str := protocol_name
if len(str) > 255 {
return .Invalid, .Invalid, .Invalid, .Invalid, .Invalid_Protocol_String
}
s, ok := strings.split_by_byte_iterator(&str, '_')
if !ok || s != "Noise" {
return .Invalid, .Invalid, .Invalid, .Invalid, .Invalid_Protocol_String
}
if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok {
return .Invalid, .Invalid, .Invalid, .Invalid, .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 "NK1": pattern = .NK1
case "NX1": pattern = .NX1
case "X1N": pattern = .X1N
case "X1K": pattern = .X1K
case "XK1": pattern = .XK1
case "X1K1": pattern = .X1K1
case "X1X": pattern = .X1X
case "XX1": pattern = .XX1
case "X1X1": pattern = .X1X1
case "K1N": pattern = .K1N
case "K1K": pattern = .K1K
case "KK1": pattern = .KK1
case "K1K1": pattern = .K1K1
case "K1X": pattern = .K1X
case "KX1": pattern = .KX1
case "K1X1": pattern = .K1X1
case "I1N": pattern = .I1N
case "I1K": pattern = .I1K
case "IK1": pattern = .IK1
case "I1K1": pattern = .I1K1
case "I1X": pattern = .I1X
case "IX1": pattern = .IX1
case "I1X1": pattern = .I1X1
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: pattern = .Invalid
}
if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok {
return .Invalid, .Invalid, .Invalid, .Invalid, .Invalid_Protocol_String
}
dh: ecdh.Curve
switch s {
case "25519": dh = .X25519
case "448": dh = .X448
case: dh = .Invalid
}
if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok {
return .Invalid, .Invalid, .Invalid, .Invalid, .Invalid_Protocol_String
}
cipher: aead.Algorithm
switch s {
case "AESGCM": cipher = .AES_GCM_256
case "ChaChaPoly": cipher = .CHACHA20POLY1305
case: cipher = .Invalid
}
if s, ok = strings.split_by_byte_iterator(&str, '_'); !ok {
return .Invalid, .Invalid, .Invalid, .Invalid, .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: hash = .Invalid
}
status: Status
if len(str) != 0 {
status = .Invalid_Protocol_String
}
if pattern == .Invalid || dh == .Invalid || cipher == .Invalid || hash == .Invalid {
status = .Invalid_Protocol_String
}
return pattern, dh, cipher, hash, status
}

View File

@@ -1,7 +1,7 @@
/*
An implementation of the Noise Protocol Framework (Revision 34).
The `fallback` modifier and deferred/multi-PSK patterns are not supported
The `fallback` modifier and multi-PSK patterns are not supported
for the sake of simplicity.
See:

View File

@@ -51,6 +51,31 @@ Handshake_Pattern :: enum {
IK,
IX,
// Deferred patterns
NK1,
NX1,
X1N,
X1K,
XK1,
X1K1,
X1X,
XX1,
X1X1,
K1N,
K1K,
KK1,
K1K1,
K1X,
KX1,
K1X1,
I1N,
I1K,
IK1,
I1K1,
I1X,
IX1,
I1X1,
// Recommended PSK patterns
Npsk0,
Kpsk0,
@@ -132,6 +157,7 @@ HANDSHAKE_PATTERNS := [Handshake_Pattern]^Message_Pattern {
.N = &PATTERN_N,
.K = &PATTERN_K,
.X = &PATTERN_X,
.XX = &PATTERN_XX,
.NK = &PATTERN_NK,
.NN = &PATTERN_NN,
@@ -144,6 +170,31 @@ HANDSHAKE_PATTERNS := [Handshake_Pattern]^Message_Pattern {
.XK = &PATTERN_XK,
.IK = &PATTERN_IK,
.IX = &PATTERN_IX,
.NK1 = &PATTERN_NK1,
.NX1 = &PATTERN_NX1,
.X1N = &PATTERN_X1N,
.X1K = &PATTERN_X1K,
.XK1 = &PATTERN_XK1,
.X1K1 = &PATTERN_X1K1,
.X1X = &PATTERN_X1X,
.XX1 = &PATTERN_XX1,
.X1X1 = &PATTERN_X1X1,
.K1N = &PATTERN_K1N,
.K1K = & PATTERN_K1K,
.KK1 = &PATTERN_KK1,
.K1K1 = &PATTERN_K1K1,
.K1X = &PATTERN_K1X,
.KX1 = &PATTERN_KX1,
.K1X1 = &PATTERN_K1X1,
.I1N = &PATTERN_I1N,
.I1K = &PATTERN_I1K,
.IK1 = &PATTERN_IK1,
.I1K1 = &PATTERN_I1K1,
.I1X = &PATTERN_I1X,
.IX1 = &PATTERN_IX1,
.I1X1 = &PATTERN_I1X1,
.Npsk0 = &PATTERN_Npsk0,
.Kpsk0 = &PATTERN_Kpsk0,
.Xpsk1 = &PATTERN_Xpsk1,
@@ -378,6 +429,367 @@ PATTERN_IX : Message_Pattern = {
// ----------------------------------------------------------------------------------------
// ------------- DEFERRED PATTERNS --------------------------------------------------------
// NK1:
// <- s
// ...
// -> e
// <- e, ee, es
@(private,rodata)
PATTERN_NK1 : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e},
{.e, .ee, .es},
},
}
// NX1:
// -> e
// <- e, ee, s
// -> es
@(private,rodata)
PATTERN_NX1 : Message_Pattern = {
pre_messages = nil,
messages = {
{.e},
{.e, .ee, .s},
{.es},
},
}
// X1N:
// -> e
// <- e, ee
// -> s
// <- se
@(private,rodata)
PATTERN_X1N : Message_Pattern = {
pre_messages = nil,
messages = {
{.e},
{.e, .ee},
{.s},
{.se},
},
}
// X1K:
// <- s
// ...
// -> e, es
// <- e, ee
// -> s
// <- se
@(private,rodata)
PATTERN_X1K : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e, .es},
{.e, .ee},
{.s},
{.se},
},
}
// XK1:
// <- s
// ...
// -> e
// <- e, ee, es
// -> s, se
@(private,rodata)
PATTERN_XK1 : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e},
{.e, .ee, .es},
{.s, .se},
},
}
// X1K1:
// <- s
// ...
// -> e
// <- e, ee, es
// -> s
// <- se
@(private,rodata)
PATTERN_X1K1 : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e},
{.e, .ee, .es},
{.s},
{.se},
},
}
// X1X:
// -> e
// <- e, ee, s, es
// -> s
// <- se
@(private,rodata)
PATTERN_X1X : Message_Pattern = {
pre_messages = nil,
messages = {
{.e},
{.e, .ee, .s, .es},
{.s},
{.se},
},
}
// XX1:
// -> e
// <- e, ee, s
// -> es, s, se
@(private,rodata)
PATTERN_XX1 : Message_Pattern = {
pre_messages = nil,
messages = {
{.e},
{.e, .ee, .s},
{.es, .s, .se},
},
}
// X1X1:
// -> e
// <- e, ee, s
// -> es, s
// <- se
@(private,rodata)
PATTERN_X1X1 : Message_Pattern = {
pre_messages = nil,
messages = {
{.e},
{.e, .ee, .s},
{.es, .s},
{.se},
},
}
// K1N:
// -> s
// ...
// -> e
// <- e, ee
// -> se
@(private,rodata)
PATTERN_K1N : Message_Pattern = {
pre_messages = {.ini_s},
messages = {
{.e,},
{.e, .ee},
{.se},
},
}
// K1K:
// -> s
// <- s
// ...
// -> e, es
// <- e, ee
// -> se
@(private,rodata)
PATTERN_K1K : Message_Pattern = {
pre_messages = {.ini_s, .res_s},
messages = {
{.e, .es},
{.e, .ee},
{.se},
},
}
// KK1:
// -> s
// <- s
// ...
// -> e
// <- e, ee, se, es
@(private,rodata)
PATTERN_KK1 : Message_Pattern = {
pre_messages = {.ini_s, .res_s},
messages = {
{.e},
{.e, .ee, .se, .es},
},
}
// K1K1:
// -> s
// <- s
// ...
// -> e
// <- e, ee, es
// -> se
@(private,rodata)
PATTERN_K1K1 : Message_Pattern = {
pre_messages = {.ini_s, .res_s},
messages = {
{.e},
{.e, .ee, .es},
{.se},
},
}
// K1X:
// -> s
// ...
// -> e
// <- e, ee, s, es
// -> se
@(private,rodata)
PATTERN_K1X : Message_Pattern = {
pre_messages = {.ini_s},
messages = {
{.e},
{.e, .ee, .s, .es},
{.se},
},
}
// KX1:
// -> s
// ...
// -> e
// <- e, ee, se, s
// -> es
@(private,rodata)
PATTERN_KX1 : Message_Pattern = {
pre_messages = {.ini_s},
messages = {
{.e},
{.e, .ee, .se, .s},
{.es},
},
}
// K1X1:
// -> s
// ...
// -> e
// <- e, ee, s
// -> se, es
@(private,rodata)
PATTERN_K1X1 : Message_Pattern = {
pre_messages = {.ini_s},
messages = {
{.e},
{.e, .ee, .s},
{.se, .es},
},
}
// I1N:
// -> e, s
// <- e, ee
// -> se
@(private,rodata)
PATTERN_I1N : Message_Pattern = {
pre_messages = nil,
messages = {
{.e, .s},
{.e, .ee},
{.se},
},
}
// I1K:
// <- s
// ...
// -> e, es, s
// <- e, ee
// -> se
@(private,rodata)
PATTERN_I1K : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e, .es, .s},
{.e, .ee},
{.se},
},
}
// IK1:
// <- s
// ...
// -> e, s
// <- e, ee, se, es
@(private,rodata)
PATTERN_IK1 : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e, .s},
{.e, .ee, .se, .es},
},
}
// I1K1:
// <- s
// ...
// -> e, s
// <- e, ee, es
// -> se
@(private,rodata)
PATTERN_I1K1 : Message_Pattern = {
pre_messages = {.res_s},
messages = {
{.e, .s},
{.e, .ee, .es},
{.se},
},
}
// I1X:
// -> e, s
// <- e, ee, s, es
// -> se
@(private,rodata)
PATTERN_I1X : Message_Pattern = {
pre_messages = nil,
messages = {
{.e, .s},
{.e, .ee, .s, .es},
{.se},
},
}
// IX1:
// -> e, s
// <- e, ee, se, s
// -> es
@(private,rodata)
PATTERN_IX1 : Message_Pattern = {
pre_messages = nil,
messages = {
{.e, .s},
{.e, .ee, .se, .s},
{.es},
},
}
// I1X1:
// -> e, s
// <- e, ee, s
// -> se, es
@(private,rodata)
PATTERN_I1X1 : Message_Pattern = {
pre_messages = nil,
messages = {
{.e, .s},
{.e, .ee, .s},
{.se, .es},
},
}
// ----------------------------------------------------------------------------------------
// ------------- PSK PATTERNS -------------------------------------------------------------
// Npsk0:

View File

@@ -817,10 +817,6 @@ handshakestate_write_message :: proc(self: ^Handshake_State, payload, dst: []byt
handshakestate_read_message :: proc(self: ^Handshake_State, message, dst: []byte, allocator := context.allocator) -> ([]byte, Status) {
ensure(self.status == .Handshake_Pending, "crypto/noise: invalid state for ReadMessage")
if len(message) < MIN_DH_SIZE {
return nil, .Invalid_Handshake_Message
}
protocol := &self.symmetric_state.protocol
d_len := dh_len(&self.symmetric_state.protocol)