deploy: cb11c192d63ac22e22b2d5348712471153a26a31

This commit is contained in:
s1fr0 2022-04-12 12:39:01 +00:00
parent 5947bc7143
commit 4af9d7af24
4 changed files with 249 additions and 17 deletions

View File

@ -4,7 +4,9 @@ import
testutils/unittests,
std/random,
stew/byteutils,
../../waku/v2/node/waku_payload,
../../waku/v2/protocol/waku_noise/noise,
../../waku/v2/protocol/waku_message,
../test_helpers
procSuite "Waku Noise":
@ -43,7 +45,7 @@ procSuite "Waku Noise":
check:
plaintext.toBytes() == decryptedCiphertext
test "Encrypt and decrypt Noise public keys":
test "Noise public keys: encrypt and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -55,7 +57,7 @@ procSuite "Waku Noise":
check:
noisePublicKey == decryptedPk
test "Decrypt unencrypted public key":
test "Noise public keys: decrypt an unencrypted public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -66,7 +68,7 @@ procSuite "Waku Noise":
check:
noisePublicKey == decryptedPk
test "Encrypt encrypted public key":
test "Noise public keys: encrypt an encrypted public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -78,7 +80,7 @@ procSuite "Waku Noise":
check:
encryptedPk == encryptedPk2
test "Encrypt, decrypt and decrypt public key":
test "Noise public keys: encrypt, decrypt and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -91,7 +93,7 @@ procSuite "Waku Noise":
check:
decryptedPk == decryptedPk2
test "Serialize and deserialize unencrypted public key":
test "Noise public keys: serialize and deserialize an unencrypted public key":
let
noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -101,7 +103,7 @@ procSuite "Waku Noise":
check:
noisePublicKey == deserializedNoisePublicKey
test "Encrypt, serialize, deserialize and decrypt public key":
test "Noise public keys: encrypt, serialize, deserialize and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
@ -113,4 +115,46 @@ procSuite "Waku Noise":
decryptedPk: NoisePublicKey = decryptNoisePublicKey(cs, deserializedNoisePublicKey)
check:
noisePublicKey == decryptedPk
noisePublicKey == decryptedPk
test "PayloadV2: serialize/deserialize PayloadV2 to byte sequence":
let
payload2: PayloadV2 = randomPayloadV2(rng[])
serializedPayload = serializePayloadV2(payload2)
check:
serializedPayload.isOk()
let deserializedPayload = deserializePayloadV2(serializedPayload.get())
check:
deserializedPayload.isOk()
payload2 == deserializedPayload.get()
test "PayloadV2: Encode/Decode a Waku Message (version 2) to a PayloadV2":
# We encode to a WakuMessage a random PayloadV2
let
payload2 = randomPayloadV2(rng[])
msg = encodePayloadV2(payload2)
check:
msg.isOk()
# We create ProtoBuffer from WakuMessage
let pb = msg.get().encode()
# We decode the WakuMessage from the ProtoBuffer
let msgFromPb = WakuMessage.init(pb.buffer)
check:
msgFromPb.isOk()
let decoded = decodePayloadV2(msgFromPb.get())
check:
decoded.isOk()
payload2 == decoded.get()

View File

@ -2,7 +2,7 @@
# libtool - Provide generalized library-building support services.
# Generated automatically by config.status (libbacktrace) version-unused
# Libtool was configured on host fv-az129-611:
# Libtool was configured on host fv-az449-568:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
#
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,

View File

@ -4,7 +4,8 @@ import
std/options,
eth/keys,
../../whisper/whisper_types,
../protocol/waku_message
../protocol/waku_message,
../protocol/waku_noise/noise
export whisper_types, keys, options
@ -56,7 +57,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 +78,36 @@ proc encode*(payload: Payload, version: uint32, rng: var BrHmacDrbgContext):
return err("Couldn't encode the payload")
else:
return err("Unsupported WakuMessage version")
# Decodes a WakuMessage to a PayloadV2
# Currently, this is just a wrapper over deserializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
proc decodePayloadV2*(message: WakuMessage): WakuResult[PayloadV2]
{.raises: [Defect, NoiseMalformedHandshake, NoisePublicKeyError].} =
# We check message version (only 2 is supported in this proc)
case message.version
of 2:
# We attempt to decode the WakuMessage payload
let deserializedPayload2 = deserializePayloadV2(message.payload)
if deserializedPayload2.isOk():
return ok(deserializedPayload2.get())
else:
return err("Failed to decode WakuMessage")
else:
return err("Wrong message version while decoding payload")
# Encodes a PayloadV2 to a WakuMessage
# Currently, this is just a wrapper over serializePayloadV2 and encryption/decryption is done on top (no KeyInfo)
proc encodePayloadV2*(payload2: PayloadV2): WakuResult[WakuMessage]
{.raises: [Defect, NoiseMalformedHandshake, NoisePublicKeyError].} =
# We attempt to encode the PayloadV2
let serializedPayload2 = serializePayloadV2(payload2)
if not serializedPayload2.isOk():
return err("Failed to encode PayloadV2")
# If successful, we create and return a WakuMessage
let msg = WakuMessage(payload: serializedPayload2.get(), version: 2)
return ok(msg)

View File

@ -7,16 +7,13 @@
{.push raises: [Defect].}
import std/[oids, options]
import std/[options, tables, strutils]
import chronos
import chronicles
import bearssl
import stew/[results, endians2]
import nimcrypto/[utils, sha2, hmac]
import libp2p/stream/[connection]
import libp2p/peerid
import libp2p/peerinfo
import libp2p/protobuf/minprotobuf
import libp2p/utility
import libp2p/errors
import libp2p/crypto/[crypto, chacha20poly1305, curve25519]
@ -49,6 +46,7 @@ type
# This follows https://rfc.vac.dev/spec/35/#public-keys-serialization
# pk contains the X coordinate of the public key, if unencrypted (this implies flag = 0)
# or the encryption of the X coordinate concatenated with the authorization tag, if encrypted (this implies flag = 1)
# Note: besides encryption, flag can be used to distinguish among multiple supported Elliptic Curves
NoisePublicKey* = object
flag: uint8
pk: seq[byte]
@ -64,6 +62,15 @@ type
nonce: ChaChaPolyNonce
ad: seq[byte]
# PayloadV2 defines an object for Waku payloads with version 2 as in
# https://rfc.vac.dev/spec/35/#public-keys-serialization
# It contains a protocol ID field, the handshake message (for Noise handshakes) and
# a transport message (for Noise handshakes and ChaChaPoly encryptions)
PayloadV2* = object
protocolId: uint8
handshakeMessage: seq[NoisePublicKey]
transportMessage: seq[byte]
# Some useful error types
NoiseError* = object of LPError
NoiseHandshakeError* = object of NoiseError
@ -84,7 +91,7 @@ proc randomSeqByte*(rng: var BrHmacDrbgContext, size: int): seq[byte] =
brHmacDrbgGenerate(rng, output)
return output
# Generate random Curve25519 (public, private) key pairs
# Generate random (public, private) Elliptic Curve key pairs
proc genKeyPair*(rng: var BrHmacDrbgContext): KeyPair =
var keyPair: KeyPair
keyPair.privateKey = EllipticCurveKey.random(rng)
@ -246,4 +253,151 @@ proc decryptNoisePublicKey*(cs: ChaChaPolyCipherState, noisePublicKey: NoisePubl
# Otherwise we return the public key as it is
else:
decryptedNoisePublicKey = noisePublicKey
return decryptedNoisePublicKey
return decryptedNoisePublicKey
#################################################################
# Payload encoding/decoding procedures
# Checks equality between two PayloadsV2 objects
proc `==`(p1, p2: PayloadV2): bool =
return (p1.protocolId == p2.protocolId) and
(p1.handshakeMessage == p2.handshakeMessage) and
(p1.transportMessage == p2.transportMessage)
# Generates a random PayloadV2
proc randomPayloadV2*(rng: var BrHmacDrbgContext): PayloadV2 =
var payload2: PayloadV2
# To generate a random protocol id, we generate a random 1-byte long sequence, and we convert the first element to uint8
payload2.protocolId = randomSeqByte(rng, 1)[0].uint8
# We set the handshake message to three unencrypted random Noise Public Keys
payload2.handshakeMessage = @[genNoisePublicKey(rng), genNoisePublicKey(rng), genNoisePublicKey(rng)]
# We set the transport message to a random 128-bytes long sequence
payload2.transportMessage = randomSeqByte(rng, 128)
return payload2
# Serializes a PayloadV2 object to a byte sequences according to https://rfc.vac.dev/spec/35/.
# The output serialized payload concatenates the input PayloadV2 object fields as
# payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
# The output can be then passed to the payload field of a WakuMessage https://rfc.vac.dev/spec/14/
proc serializePayloadV2*(self: PayloadV2): Result[seq[byte], cstring] =
#We collect public keys contained in the handshake message
var
# According to https://rfc.vac.dev/spec/35/, the maximum size for the handshake message is 256 bytes, that is
# the handshake message length can be represented with 1 byte only. (its length can be stored in 1 byte)
# However, to ease public keys length addition operation, we declare it as int and later cast to uit8
serializedHandshakeMessageLen: int = 0
# This variables will store the concatenation of the serializations of all public keys in the handshake message
serializedHandshakeMessage = newSeqOfCap[byte](256)
# A variable to store the currently processed public key serialization
serializedPk: seq[byte]
# For each public key in the handshake message
for pk in self.handshakeMessage:
# We serialize the public key
serializedPk = serializeNoisePublicKey(pk)
# We sum its serialized length to the total
serializedHandshakeMessageLen += serializedPk.len
# We add its serialization to the concatenation of all serialized public keys in the handshake message
serializedHandshakeMessage.add serializedPk
# If we are processing more than 256 byte, we return an error
if serializedHandshakeMessageLen > uint8.high.int:
debug "PayloadV2 malformed: too many public keys contained in the handshake message"
return err("Too many public keys in handshake message")
# We get the transport message byte length
let transportMessageLen = self.transportMessage.len
# The output payload as in https://rfc.vac.dev/spec/35/. We concatenate all the PayloadV2 fields as
# payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
# We declare it as a byte sequence of length accordingly to the PayloadV2 information read
var payload = newSeqOfCap[byte](1 + # 1 byte for protocol ID
1 + # 1 byte for length of serializedHandshakeMessage field
serializedHandshakeMessageLen + # serializedHandshakeMessageLen bytes for serializedHandshakeMessage
8 + # 8 bytes for transportMessageLen
transportMessageLen # transportMessageLen bytes for transportMessage
)
# We concatenate all the data
# The protocol ID (1 byte) and handshake message length (1 byte) can be directly casted to byte to allow direct copy to the payload byte sequence
payload.add self.protocolId.byte
payload.add serializedHandshakeMessageLen.byte
payload.add serializedHandshakeMessage
# The transport message length is converted from uint64 to bytes in Little-Endian
payload.add toBytesLE(transportMessageLen.uint64)
payload.add self.transportMessage
return ok(payload)
# Deserializes a byte sequence to a PayloadV2 object according to https://rfc.vac.dev/spec/35/.
# The input serialized payload concatenates the output PayloadV2 object fields as
# payload = ( protocolId || serializedHandshakeMessageLen || serializedHandshakeMessage || transportMessageLen || transportMessage)
proc deserializePayloadV2*(payload: seq[byte]): Result[PayloadV2, cstring]
{.raises: [Defect, NoisePublicKeyError].} =
# The output PayloadV2
var payload2: PayloadV2
# i is the read input buffer position index
var i: uint64 = 0
# We start reading the Protocol ID
# TODO: when the list of supported protocol ID is defined, check if read protocol ID is supported
payload2.protocolId = payload[i].uint8
i += 1
# We read the Handshake Message lenght (1 byte)
var handshakeMessageLen = payload[i].uint64
if handshakeMessageLen > uint8.high.uint64:
debug "Payload malformed: too many public keys contained in the handshake message"
#raise newException(NoiseMalformedHandshake, "Too many public keys in handshake message")
return err("Too many public keys in handshake message")
i += 1
# We now read for handshakeMessageLen bytes the buffer and we deserialize each (encrypted/unencrypted) public key read
var
# In handshakeMessage we accumulate the read deserialized Noise Public keys
handshakeMessage: seq[NoisePublicKey]
flag: byte
pkLen: uint64
written: uint64 = 0
# We read the buffer until handshakeMessageLen are read
while written != handshakeMessageLen:
# We obtain the current Noise Public key encryption flag
flag = payload[i]
# If the key is unencrypted, we only read the X coordinate of the EC public key and we deserialize into a Noise Public Key
if flag == 0:
pkLen = 1 + EllipticCurveKey.len
handshake_message.add intoNoisePublicKey(payload[i..<i+pkLen])
i += pkLen
written += pkLen
# If the key is encrypted, we only read the encrypted X coordinate and the authorization tag, and we deserialize into a Noise Public Key
elif flag == 1:
pkLen = 1 + EllipticCurveKey.len + ChaChaPolyTag.len
handshakeMessage.add intoNoisePublicKey(payload[i..<i+pkLen])
i += pkLen
written += pkLen
else:
return err("Invalid flag for Noise public key")
# We save in the output PayloadV2 the read handshake message
payload2.handshakeMessage = handshakeMessage
# We read the transport message length (8 bytes) and we convert to uint64 in Little Endian
let transportMessageLen = fromBytesLE(uint64, payload[i..(i+8-1)])
i += 8
# We read the transport message (handshakeMessage bytes)
payload2.transportMessage = payload[i..i+transportMessageLen-1]
i += transportMessageLen
return ok(payload2)