feat(noise): added support to Waku Payload V2

This commit is contained in:
s1fr0 2022-03-30 23:51:36 +02:00
parent d6024a8fa0
commit 7f4df9628b
No known key found for this signature in database
GPG Key ID: 2C041D60117BFF46
3 changed files with 187 additions and 5 deletions

View File

@ -2,7 +2,9 @@
import
testutils/unittests,
../../waku/v2/protocol/waku_message,
../../waku/v2/protocol/waku_noise/noise,
../../waku/v2/node/waku_payload,
../test_helpers,
std/tables
@ -79,4 +81,43 @@ procSuite "Waku Noise":
dec_pk: NoisePublicKey = decryptNoisePublicKey(cs, deserializedNoisePublicKey)
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

View File

@ -4,7 +4,11 @@ import
std/options,
eth/keys,
../../whisper/whisper_types,
../protocol/waku_message
../protocol/waku_message,
../protocol/waku_noise/noise
import libp2p/crypto/[chacha20poly1305, curve25519]
export whisper_types, keys, options
@ -12,6 +16,7 @@ type
KeyKind* = enum
Symmetric
Asymmetric
ChaChaPolyEncryption
None
KeyInfo* = object
@ -20,6 +25,8 @@ type
symKey*: SymKey
of Asymmetric:
privKey*: PrivateKey
of ChaChaPolyEncryption:
cs*: ChaChaPolyCipherState
of None:
discard
@ -56,7 +63,7 @@ proc decodePayload*(message: WakuMessage, keyInfo: KeyInfo):
return ok(decoded.get())
else:
return err("Couldn't decrypt using asymmetric key")
of None:
else:
discard
else:
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")
else:
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")

View File

@ -132,7 +132,6 @@ proc serializeNoisePublicKey*(noisePublicKey: NoisePublicKey): seq[byte] =
result.add noisePublicKey.flag
result.add noisePublicKey.pk
#TODO: strip pk_auth if pk not encrypted
proc intoNoisePublicKey*(serializedNoisePublicKey: seq[byte]): NoisePublicKey =
result.flag = serializedNoisePublicKey[0]
assert result.flag == 0 or result.flag == 1
@ -167,4 +166,113 @@ proc decryptNoisePublicKey*(cs: ChaChaPolyCipherState, noisePublicKey: NoisePubl
if noisePublicKey.flag == 0:
debug "Public key is not encrypted."
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)