mirror of
https://github.com/waku-org/nwaku.git
synced 2025-01-09 14:26:27 +00:00
feat(noise): added support to Waku Payload V2
This commit is contained in:
parent
d6024a8fa0
commit
7f4df9628b
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
testutils/unittests,
|
testutils/unittests,
|
||||||
|
../../waku/v2/protocol/waku_message,
|
||||||
../../waku/v2/protocol/waku_noise/noise,
|
../../waku/v2/protocol/waku_noise/noise,
|
||||||
|
../../waku/v2/node/waku_payload,
|
||||||
../test_helpers,
|
../test_helpers,
|
||||||
std/tables
|
std/tables
|
||||||
|
|
||||||
@ -80,3 +82,42 @@ procSuite "Waku Noise":
|
|||||||
|
|
||||||
check:
|
check:
|
||||||
noisePublicKey == dec_pk
|
noisePublicKey == dec_pk
|
||||||
|
|
||||||
|
test "Encode/decode PayloadV2 to byte sequence":
|
||||||
|
|
||||||
|
let
|
||||||
|
payload2 = randomPayloadV2(rng[])
|
||||||
|
encoded_payload = encodeV2(payload2)
|
||||||
|
decoded_payload = decodeV2(encoded_payload.get())
|
||||||
|
|
||||||
|
check:
|
||||||
|
payload2 == decoded_payload.get()
|
||||||
|
|
||||||
|
|
||||||
|
test "Encode/Decode Waku2 payload (version 2) - ChaChaPoly Keyinfo":
|
||||||
|
# Encoding
|
||||||
|
let
|
||||||
|
version = 2'u32
|
||||||
|
payload = randomPayloadV2(rng[])
|
||||||
|
encodedPayload = encodePayloadV2(payload)
|
||||||
|
|
||||||
|
check encodedPayload.isOk()
|
||||||
|
|
||||||
|
let
|
||||||
|
msg = WakuMessage(payload: encodedPayload.get(), version: version)
|
||||||
|
pb = msg.encode()
|
||||||
|
|
||||||
|
# Decoding
|
||||||
|
let msgDecoded = WakuMessage.init(pb.buffer)
|
||||||
|
check msgDecoded.isOk()
|
||||||
|
|
||||||
|
let
|
||||||
|
cipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
keyInfo = KeyInfo(kind: ChaChaPolyEncryption, cs: cipherState)
|
||||||
|
decoded = decodePayloadV2(msgDecoded.get(), keyInfo)
|
||||||
|
|
||||||
|
check:
|
||||||
|
decoded.isOk()
|
||||||
|
decoded.get() == payload
|
||||||
|
|
||||||
|
#TODO: add encrypt payload with ChaChaPoly
|
||||||
|
@ -4,7 +4,11 @@ import
|
|||||||
std/options,
|
std/options,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
../../whisper/whisper_types,
|
../../whisper/whisper_types,
|
||||||
../protocol/waku_message
|
../protocol/waku_message,
|
||||||
|
../protocol/waku_noise/noise
|
||||||
|
|
||||||
|
import libp2p/crypto/[chacha20poly1305, curve25519]
|
||||||
|
|
||||||
|
|
||||||
export whisper_types, keys, options
|
export whisper_types, keys, options
|
||||||
|
|
||||||
@ -12,6 +16,7 @@ type
|
|||||||
KeyKind* = enum
|
KeyKind* = enum
|
||||||
Symmetric
|
Symmetric
|
||||||
Asymmetric
|
Asymmetric
|
||||||
|
ChaChaPolyEncryption
|
||||||
None
|
None
|
||||||
|
|
||||||
KeyInfo* = object
|
KeyInfo* = object
|
||||||
@ -20,6 +25,8 @@ type
|
|||||||
symKey*: SymKey
|
symKey*: SymKey
|
||||||
of Asymmetric:
|
of Asymmetric:
|
||||||
privKey*: PrivateKey
|
privKey*: PrivateKey
|
||||||
|
of ChaChaPolyEncryption:
|
||||||
|
cs*: ChaChaPolyCipherState
|
||||||
of None:
|
of None:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
@ -56,7 +63,7 @@ proc decodePayload*(message: WakuMessage, keyInfo: KeyInfo):
|
|||||||
return ok(decoded.get())
|
return ok(decoded.get())
|
||||||
else:
|
else:
|
||||||
return err("Couldn't decrypt using asymmetric key")
|
return err("Couldn't decrypt using asymmetric key")
|
||||||
of None:
|
else:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
return err("Unsupported WakuMessage version")
|
return err("Unsupported WakuMessage version")
|
||||||
@ -77,3 +84,29 @@ proc encode*(payload: Payload, version: uint32, rng: var BrHmacDrbgContext):
|
|||||||
return err("Couldn't encode the payload")
|
return err("Couldn't encode the payload")
|
||||||
else:
|
else:
|
||||||
return err("Unsupported WakuMessage version")
|
return err("Unsupported WakuMessage version")
|
||||||
|
|
||||||
|
|
||||||
|
proc decodePayloadV2*(message: WakuMessage, keyInfo: KeyInfo):
|
||||||
|
WakuResult[PayloadV2] =
|
||||||
|
case message.version
|
||||||
|
of 2:
|
||||||
|
case keyInfo.kind
|
||||||
|
of ChaChaPolyEncryption:
|
||||||
|
let decoded = decodeV2(message.payload)#, keyInfo.cs)
|
||||||
|
if decoded.isSome():
|
||||||
|
return ok(decoded.get())
|
||||||
|
else:
|
||||||
|
return err("Couldn't decrypt using ChaChaPoly Cipher State")
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
return err("Key info doesn't match v2 payloads")
|
||||||
|
|
||||||
|
|
||||||
|
proc encodePayloadV2*(payload: PayloadV2):
|
||||||
|
WakuResult[seq[byte]] =
|
||||||
|
let encoded = encodeV2(payload)
|
||||||
|
if encoded.isSome():
|
||||||
|
return ok(encoded.get())
|
||||||
|
else:
|
||||||
|
return err("Couldn't encode the payload")
|
@ -132,7 +132,6 @@ proc serializeNoisePublicKey*(noisePublicKey: NoisePublicKey): seq[byte] =
|
|||||||
result.add noisePublicKey.flag
|
result.add noisePublicKey.flag
|
||||||
result.add noisePublicKey.pk
|
result.add noisePublicKey.pk
|
||||||
|
|
||||||
#TODO: strip pk_auth if pk not encrypted
|
|
||||||
proc intoNoisePublicKey*(serializedNoisePublicKey: seq[byte]): NoisePublicKey =
|
proc intoNoisePublicKey*(serializedNoisePublicKey: seq[byte]): NoisePublicKey =
|
||||||
result.flag = serializedNoisePublicKey[0]
|
result.flag = serializedNoisePublicKey[0]
|
||||||
assert result.flag == 0 or result.flag == 1
|
assert result.flag == 0 or result.flag == 1
|
||||||
@ -168,3 +167,112 @@ proc decryptNoisePublicKey*(cs: ChaChaPolyCipherState, noisePublicKey: NoisePubl
|
|||||||
debug "Public key is not encrypted."
|
debug "Public key is not encrypted."
|
||||||
debug "Public key is left unchanged"
|
debug "Public key is left unchanged"
|
||||||
result = noisePublicKey
|
result = noisePublicKey
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Payload functions
|
||||||
|
type
|
||||||
|
PayloadV2* = object
|
||||||
|
protocol_id: uint8
|
||||||
|
handshake_message: seq[NoisePublicKey]
|
||||||
|
transport_message: seq[byte]
|
||||||
|
|
||||||
|
|
||||||
|
proc `==`(p1, p2: PayloadV2): bool =
|
||||||
|
result = (p1.protocol_id == p2.protocol_id) and
|
||||||
|
(p1.handshake_message == p2.handshake_message) and
|
||||||
|
(p1.transport_message == p2.transport_message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc randomPayloadV2*(rng: var BrHmacDrbgContext): PayloadV2 =
|
||||||
|
var protocol_id = newSeq[byte](1)
|
||||||
|
brHmacDrbgGenerate(rng, protocol_id)
|
||||||
|
result.protocol_id = protocol_id[0].uint8
|
||||||
|
result.handshake_message = @[genNoisePublicKey(rng), genNoisePublicKey(rng), genNoisePublicKey(rng)]
|
||||||
|
result.transport_message = newSeq[byte](128)
|
||||||
|
brHmacDrbgGenerate(rng, result.transport_message)
|
||||||
|
|
||||||
|
|
||||||
|
proc encodeV2*(self: PayloadV2): Option[seq[byte]] =
|
||||||
|
|
||||||
|
#We collect public keys contained in the handshake message
|
||||||
|
var
|
||||||
|
ser_handshake_message_len: int = 0
|
||||||
|
ser_handshake_message = newSeqOfCap[byte](256)
|
||||||
|
ser_pk: seq[byte]
|
||||||
|
for pk in self.handshake_message:
|
||||||
|
ser_pk = serializeNoisePublicKey(pk)
|
||||||
|
ser_handshake_message_len += ser_pk.len
|
||||||
|
ser_handshake_message.add ser_pk
|
||||||
|
|
||||||
|
|
||||||
|
#RFC: handshake-message-len is 1 byte
|
||||||
|
if ser_handshake_message_len > 256:
|
||||||
|
debug "Payload malformed: too many public keys contained in the handshake message"
|
||||||
|
return none(seq[byte])
|
||||||
|
|
||||||
|
let transport_message_len = self.transport_message.len
|
||||||
|
#let transport_message_len_len = ceil(log(transport_message_len, 8)).int
|
||||||
|
|
||||||
|
var payload = newSeqOfCap[byte](1 + #self.protocol_id.len +
|
||||||
|
1 + #ser_handshake_message_len
|
||||||
|
ser_handshake_message_len +
|
||||||
|
8 + #transport_message_len
|
||||||
|
transport_message_len #self.transport_message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
payload.add self.protocol_id.byte
|
||||||
|
payload.add ser_handshake_message_len.byte
|
||||||
|
payload.add ser_handshake_message
|
||||||
|
payload.add toBytesLE(transport_message_len.uint64)
|
||||||
|
payload.add self.transport_message
|
||||||
|
|
||||||
|
return some(payload)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Decode Noise handshake payload
|
||||||
|
proc decodeV2*(payload: seq[byte]): Option[PayloadV2] =
|
||||||
|
var res: PayloadV2
|
||||||
|
|
||||||
|
var i: uint64 = 0
|
||||||
|
res.protocol_id = payload[i].uint8
|
||||||
|
i+=1
|
||||||
|
|
||||||
|
var handshake_message_len = payload[i].uint64
|
||||||
|
i+=1
|
||||||
|
|
||||||
|
var handshake_message: seq[NoisePublicKey]
|
||||||
|
|
||||||
|
var
|
||||||
|
flag: byte
|
||||||
|
pk_len: uint64
|
||||||
|
written: uint64 = 0
|
||||||
|
|
||||||
|
while written != handshake_message_len:
|
||||||
|
#Note that flag can be used to add support to multiple Elliptic Curve arithmetics..
|
||||||
|
flag = payload[i]
|
||||||
|
if flag == 0:
|
||||||
|
pk_len = 1 + Curve25519Key.len
|
||||||
|
handshake_message.add intoNoisePublicKey(payload[i..<i+pk_len])
|
||||||
|
i += pk_len
|
||||||
|
written += pk_len
|
||||||
|
if flag == 1:
|
||||||
|
pk_len = 1 + Curve25519Key.len + ChaChaPolyTag.len
|
||||||
|
handshake_message.add intoNoisePublicKey(payload[i..<i+pk_len])
|
||||||
|
i += pk_len
|
||||||
|
written += pk_len
|
||||||
|
|
||||||
|
res.handshake_message = handshake_message
|
||||||
|
|
||||||
|
let transport_message_len = fromBytesLE(uint64, payload[i..(i+8-1)])
|
||||||
|
i+=8
|
||||||
|
|
||||||
|
res.transport_message = payload[i..i+transport_message_len-1]
|
||||||
|
i+=transport_message_len
|
||||||
|
|
||||||
|
return some(res)
|
Loading…
x
Reference in New Issue
Block a user