mirror of
https://github.com/waku-org/nwaku.git
synced 2025-01-22 21:02:56 +00:00
feat(noise): add support to Noise public keys
This commit is contained in:
parent
2392565881
commit
d6024a8fa0
@ -2,27 +2,27 @@ import
|
|||||||
# Waku v2 tests
|
# Waku v2 tests
|
||||||
# TODO: enable this when it is altered into a proper waku relay test
|
# TODO: enable this when it is altered into a proper waku relay test
|
||||||
# ./v2/test_waku,
|
# ./v2/test_waku,
|
||||||
#./v2/test_wakunode,
|
./v2/test_wakunode,
|
||||||
#./v2/test_waku_store,
|
./v2/test_waku_store,
|
||||||
#./v2/test_waku_filter,
|
./v2/test_waku_filter,
|
||||||
#./v2/test_waku_pagination,
|
./v2/test_waku_pagination,
|
||||||
#./v2/test_waku_payload,
|
./v2/test_waku_payload,
|
||||||
#./v2/test_waku_swap,
|
./v2/test_waku_swap,
|
||||||
#./v2/test_message_store,
|
./v2/test_message_store,
|
||||||
#./v2/test_jsonrpc_waku,
|
./v2/test_jsonrpc_waku,
|
||||||
#./v2/test_peer_manager,
|
./v2/test_peer_manager,
|
||||||
#./v2/test_web3, # TODO remove it when rln-relay tests get finalized
|
./v2/test_web3, # TODO remove it when rln-relay tests get finalized
|
||||||
#./v2/test_waku_bridge,
|
./v2/test_waku_bridge,
|
||||||
#./v2/test_peer_storage,
|
./v2/test_peer_storage,
|
||||||
#./v2/test_waku_keepalive,
|
./v2/test_waku_keepalive,
|
||||||
#./v2/test_migration_utils,
|
./v2/test_migration_utils,
|
||||||
#./v2/test_namespacing_utils,
|
./v2/test_namespacing_utils,
|
||||||
#./v2/test_waku_dnsdisc,
|
./v2/test_waku_dnsdisc,
|
||||||
#./v2/test_waku_discv5,
|
./v2/test_waku_discv5,
|
||||||
#./v2/test_enr_utils,
|
./v2/test_enr_utils,
|
||||||
#./v2/test_waku_store_queue,
|
./v2/test_waku_store_queue,
|
||||||
#./v2/test_pagination_utils,
|
./v2/test_pagination_utils,
|
||||||
#./v2/test_peer_exchange
|
./v2/test_peer_exchange
|
||||||
./v2/test_waku_noise
|
./v2/test_waku_noise
|
||||||
|
|
||||||
when defined(rln):
|
when defined(rln):
|
||||||
|
@ -3,4 +3,80 @@
|
|||||||
import
|
import
|
||||||
testutils/unittests,
|
testutils/unittests,
|
||||||
../../waku/v2/protocol/waku_noise/noise,
|
../../waku/v2/protocol/waku_noise/noise,
|
||||||
../test_helpers
|
../test_helpers,
|
||||||
|
std/tables
|
||||||
|
|
||||||
|
procSuite "Waku Noise":
|
||||||
|
|
||||||
|
let rng = rng()
|
||||||
|
|
||||||
|
test "Encrypt -> decrypt public keys":
|
||||||
|
|
||||||
|
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
|
||||||
|
let
|
||||||
|
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
enc_pk: NoisePublicKey = encryptNoisePublicKey(cs, noisePublicKey)
|
||||||
|
dec_pk: NoisePublicKey = decryptNoisePublicKey(cs, enc_pk)
|
||||||
|
|
||||||
|
check:
|
||||||
|
noisePublicKey == dec_pk
|
||||||
|
|
||||||
|
test "Decrypt unencrypted public key":
|
||||||
|
|
||||||
|
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
|
||||||
|
let
|
||||||
|
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
dec_pk: NoisePublicKey = decryptNoisePublicKey(cs, noisePublicKey)
|
||||||
|
|
||||||
|
check:
|
||||||
|
noisePublicKey == dec_pk
|
||||||
|
|
||||||
|
test "Encrypt -> encrypt public keys":
|
||||||
|
|
||||||
|
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
|
||||||
|
let
|
||||||
|
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
enc_pk: NoisePublicKey = encryptNoisePublicKey(cs, noisePublicKey)
|
||||||
|
enc2_pk: NoisePublicKey = encryptNoisePublicKey(cs, enc_pk)
|
||||||
|
|
||||||
|
check enc_pk == enc2_pk
|
||||||
|
|
||||||
|
test "Encrypt -> decrypt -> decrypt public keys":
|
||||||
|
|
||||||
|
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
|
||||||
|
let
|
||||||
|
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
enc_pk: NoisePublicKey = encryptNoisePublicKey(cs, noisePublicKey)
|
||||||
|
dec_pk: NoisePublicKey = decryptNoisePublicKey(cs, enc_pk)
|
||||||
|
dec2_pk: NoisePublicKey = decryptNoisePublicKey(cs, dec_pk)
|
||||||
|
|
||||||
|
check:
|
||||||
|
dec_pk == dec2_pk
|
||||||
|
|
||||||
|
test "Serialize -> deserialize public keys (unencrypted)":
|
||||||
|
|
||||||
|
let
|
||||||
|
noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
serializedNoisePublicKey: seq[byte] = serializeNoisePublicKey(noisePublicKey)
|
||||||
|
deserializedNoisePublicKey: NoisePublicKey = intoNoisePublicKey(serializedNoisePublicKey)
|
||||||
|
|
||||||
|
check:
|
||||||
|
noisePublicKey == deserializedNoisePublicKey
|
||||||
|
|
||||||
|
test "Encrypt -> serialize -> deserialize -> decrypt public keys":
|
||||||
|
|
||||||
|
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
|
||||||
|
|
||||||
|
let
|
||||||
|
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
|
||||||
|
enc_pk: NoisePublicKey = encryptNoisePublicKey(cs, noisePublicKey)
|
||||||
|
serializedNoisePublicKey: seq[byte] = serializeNoisePublicKey(enc_pk)
|
||||||
|
deserializedNoisePublicKey: NoisePublicKey = intoNoisePublicKey(serializedNoisePublicKey)
|
||||||
|
dec_pk: NoisePublicKey = decryptNoisePublicKey(cs, deserializedNoisePublicKey)
|
||||||
|
|
||||||
|
check:
|
||||||
|
noisePublicKey == dec_pk
|
@ -9,17 +9,22 @@
|
|||||||
|
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import std/[oids, options]
|
import std/[oids, options, tables]
|
||||||
import chronos
|
import chronos
|
||||||
import chronicles
|
import chronicles
|
||||||
import bearssl
|
import bearssl
|
||||||
|
import strutils
|
||||||
|
import stew/[endians2]
|
||||||
import nimcrypto/[utils, sha2, hmac]
|
import nimcrypto/[utils, sha2, hmac]
|
||||||
|
|
||||||
import libp2p/stream/[connection]
|
import libp2p/stream/[connection]
|
||||||
|
import libp2p/peerid
|
||||||
|
import libp2p/peerinfo
|
||||||
import libp2p/protobuf/minprotobuf
|
import libp2p/protobuf/minprotobuf
|
||||||
import libp2p/utility
|
import libp2p/utility
|
||||||
import libp2p/errors
|
import libp2p/errors
|
||||||
import libp2p/crypto/[crypto, chacha20poly1305]
|
import libp2p/crypto/[crypto, chacha20poly1305, curve25519]
|
||||||
|
|
||||||
|
|
||||||
when defined(libp2p_dump):
|
when defined(libp2p_dump):
|
||||||
import libp2p/debugutils
|
import libp2p/debugutils
|
||||||
@ -30,8 +35,20 @@ logScope:
|
|||||||
const
|
const
|
||||||
# Empty is a special value which indicates k has not yet been initialized.
|
# Empty is a special value which indicates k has not yet been initialized.
|
||||||
EmptyKey = default(ChaChaPolyKey)
|
EmptyKey = default(ChaChaPolyKey)
|
||||||
|
NonceMax = uint64.high - 1 # max is reserved
|
||||||
|
NoiseSize = 32
|
||||||
|
MaxPlainSize = int(uint16.high - NoiseSize - ChaChaPolyTag.len)
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
KeyPair* = object
|
||||||
|
privateKey: Curve25519Key
|
||||||
|
publicKey: Curve25519Key
|
||||||
|
|
||||||
|
NoisePublicKey* = object
|
||||||
|
flag: uint8
|
||||||
|
pk: seq[byte]
|
||||||
|
|
||||||
ChaChaPolyCiphertext* = object
|
ChaChaPolyCiphertext* = object
|
||||||
data: seq[byte]
|
data: seq[byte]
|
||||||
tag: ChaChaPolyTag
|
tag: ChaChaPolyTag
|
||||||
@ -42,7 +59,16 @@ type
|
|||||||
ad*: seq[byte]
|
ad*: seq[byte]
|
||||||
|
|
||||||
NoiseError* = object of LPError
|
NoiseError* = object of LPError
|
||||||
|
NoiseHandshakeError* = object of NoiseError
|
||||||
NoiseDecryptTagError* = object of NoiseError
|
NoiseDecryptTagError* = object of NoiseError
|
||||||
|
NoiseNonceMaxError* = object of NoiseError # drop connection on purpose
|
||||||
|
NoisePublicKeyError* = object of NoiseError
|
||||||
|
NoiseMalformedHandshake* = object of NoiseError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
|
||||||
# ChaChaPoly encryption
|
# ChaChaPoly encryption
|
||||||
proc encrypt*(
|
proc encrypt*(
|
||||||
@ -74,3 +100,71 @@ proc randomChaChaPolyCipherState*(rng: var BrHmacDrbgContext): ChaChaPolyCipherS
|
|||||||
brHmacDrbgGenerate(rng, result.nonce)
|
brHmacDrbgGenerate(rng, result.nonce)
|
||||||
result.ad = newSeq[byte](32)
|
result.ad = newSeq[byte](32)
|
||||||
brHmacDrbgGenerate(rng, result.ad)
|
brHmacDrbgGenerate(rng, result.ad)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
|
||||||
|
# Utility
|
||||||
|
|
||||||
|
proc genKeyPair*(rng: var BrHmacDrbgContext): KeyPair =
|
||||||
|
result.privateKey = Curve25519Key.random(rng)
|
||||||
|
result.publicKey = result.privateKey.public()
|
||||||
|
|
||||||
|
|
||||||
|
# Public keys serializations/encryption
|
||||||
|
|
||||||
|
proc `==`(k1, k2: NoisePublicKey): bool =
|
||||||
|
result = (k1.flag == k2.flag) and (k1.pk == k2.pk)
|
||||||
|
|
||||||
|
|
||||||
|
proc keyPairToNoisePublicKey*(keyPair: KeyPair): NoisePublicKey =
|
||||||
|
result.flag = 0
|
||||||
|
result.pk = getBytes(keyPair.publicKey)
|
||||||
|
|
||||||
|
|
||||||
|
proc genNoisePublicKey*(rng: var BrHmacDrbgContext): NoisePublicKey =
|
||||||
|
let keyPair: KeyPair = genKeyPair(rng)
|
||||||
|
result.flag = 0
|
||||||
|
result.pk = getBytes(keyPair.publicKey)
|
||||||
|
|
||||||
|
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
|
||||||
|
result.pk = serializedNoisePublicKey[1..<serializedNoisePublicKey.len]
|
||||||
|
|
||||||
|
# Public keys encryption/decryption
|
||||||
|
|
||||||
|
proc encryptNoisePublicKey*(cs: ChaChaPolyCipherState, noisePublicKey: NoisePublicKey): NoisePublicKey
|
||||||
|
{.raises: [Defect, NoiseNonceMaxError].} =
|
||||||
|
if cs.k != EmptyKey and noisePublicKey.flag == 0:
|
||||||
|
let enc_pk = encrypt(cs, noisePublicKey.pk)
|
||||||
|
result.flag = 1
|
||||||
|
result.pk = enc_pk.data
|
||||||
|
result.pk.add enc_pk.tag
|
||||||
|
else:
|
||||||
|
result = noisePublicKey
|
||||||
|
|
||||||
|
|
||||||
|
proc decryptNoisePublicKey*(cs: ChaChaPolyCipherState, noisePublicKey: NoisePublicKey): NoisePublicKey
|
||||||
|
{.raises: [Defect, NoiseDecryptTagError].} =
|
||||||
|
if cs.k != EmptyKey and noisePublicKey.flag == 1:
|
||||||
|
#let ciphertext = ChaChaPolyCiphertext(data: noisePublicKey.pk, tag: noisePublicKey.pk_auth)
|
||||||
|
let pk_len = noisePublicKey.pk.len - ChaChaPolyTag.len
|
||||||
|
let pk = noisePublicKey.pk[0..<pk_len]
|
||||||
|
let pk_auth = intoChaChaPolyTag(noisePublicKey.pk[pk_len..<pk_len+ChaChaPolyTag.len])
|
||||||
|
let ciphertext = ChaChaPolyCiphertext(data: pk, tag: pk_auth)
|
||||||
|
result.pk = decrypt(cs, ciphertext)
|
||||||
|
result.flag = 0
|
||||||
|
else:
|
||||||
|
if cs.k == EmptyKey:
|
||||||
|
debug "No key in cipher state."
|
||||||
|
if noisePublicKey.flag == 0:
|
||||||
|
debug "Public key is not encrypted."
|
||||||
|
debug "Public key is left unchanged"
|
||||||
|
result = noisePublicKey
|
Loading…
x
Reference in New Issue
Block a user