mirror of
https://github.com/vacp2p/nim-libp2p.git
synced 2025-02-04 21:04:32 +00:00
Support arbitrary stream write sizes in noise
This commit is contained in:
parent
4199508f17
commit
1550bea1cc
@ -35,6 +35,8 @@ 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: ChaChaPolyKey = [0.byte, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
EmptyKey: ChaChaPolyKey = [0.byte, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
NonceMax = uint64.high - 1 # max is reserved
|
NonceMax = uint64.high - 1 # max is reserved
|
||||||
|
NoiseSize = 32
|
||||||
|
MaxPlainSize = int(uint16.high - NoiseSize - ChaChaPolyTag.len)
|
||||||
|
|
||||||
type
|
type
|
||||||
KeyPair = object
|
KeyPair = object
|
||||||
@ -282,7 +284,7 @@ proc sendHSMessage(sconn: Connection; buf: seq[byte]) {.async.} =
|
|||||||
|
|
||||||
proc packNoisePayload(payload: openarray[byte]): seq[byte] =
|
proc packNoisePayload(payload: openarray[byte]): seq[byte] =
|
||||||
let
|
let
|
||||||
noiselen = rand(2..31)
|
noiselen = rand(2..<NoiseSize)
|
||||||
plen = payload.len.uint16
|
plen = payload.len.uint16
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -427,17 +429,24 @@ method readMessage(sconn: NoiseConnection): Future[seq[byte]] {.async.} =
|
|||||||
|
|
||||||
method writeMessage(sconn: NoiseConnection, message: seq[byte]): Future[void] {.async.} =
|
method writeMessage(sconn: NoiseConnection, message: seq[byte]): Future[void] {.async.} =
|
||||||
try:
|
try:
|
||||||
let
|
|
||||||
packed = packNoisePayload(message)
|
|
||||||
cipher = sconn.writeCs.encryptWithAd([], packed)
|
|
||||||
var
|
var
|
||||||
lesize = cipher.len.uint16
|
left = message.len
|
||||||
besize = lesize.toBytesBE
|
offset = 0
|
||||||
outbuf = newSeqOfCap[byte](cipher.len + 2)
|
while left > 0:
|
||||||
trace "sendEncryptedMessage", size = lesize, peer = $sconn.peerInfo
|
let
|
||||||
outbuf &= besize
|
chunkSize = if left > MaxPlainSize: MaxPlainSize else: left
|
||||||
outbuf &= cipher
|
packed = packNoisePayload(message.toOpenArray(offset, offset + chunkSize - 1))
|
||||||
await sconn.write(outbuf)
|
cipher = sconn.writeCs.encryptWithAd([], packed)
|
||||||
|
left = left - chunkSize
|
||||||
|
offset = offset + chunkSize
|
||||||
|
var
|
||||||
|
lesize = cipher.len.uint16
|
||||||
|
besize = lesize.toBytesBE
|
||||||
|
outbuf = newSeqOfCap[byte](cipher.len + 2)
|
||||||
|
trace "sendEncryptedMessage", size = lesize, peer = $sconn.peerInfo, left, offset
|
||||||
|
outbuf &= besize
|
||||||
|
outbuf &= cipher
|
||||||
|
await sconn.write(outbuf)
|
||||||
except AsyncStreamWriteError:
|
except AsyncStreamWriteError:
|
||||||
trace "Could not write to connection"
|
trace "Could not write to connection"
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import unittest, tables
|
import unittest, tables
|
||||||
import chronos
|
import chronos
|
||||||
import chronicles
|
import chronicles
|
||||||
|
import nimcrypto/sysrand
|
||||||
import ../libp2p/crypto/crypto
|
import ../libp2p/crypto/crypto
|
||||||
import ../libp2p/[switch,
|
import ../libp2p/[switch,
|
||||||
multistream,
|
multistream,
|
||||||
@ -134,6 +135,47 @@ suite "Noise":
|
|||||||
check:
|
check:
|
||||||
waitFor(testListenerDialer()) == true
|
waitFor(testListenerDialer()) == true
|
||||||
|
|
||||||
|
test "e2e: handle read + noise fragmented":
|
||||||
|
proc testListenerDialer(): Future[bool] {.async.} =
|
||||||
|
let
|
||||||
|
server: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
|
||||||
|
serverInfo = PeerInfo.init(PrivateKey.random(RSA), [server])
|
||||||
|
serverNoise = newNoise(serverInfo.privateKey, outgoing = false)
|
||||||
|
readTask = newFuture[void]()
|
||||||
|
|
||||||
|
var hugePayload = newSeq[byte](0xFFFFF)
|
||||||
|
check randomBytes(hugePayload) == hugePayload.len
|
||||||
|
trace "Sending huge payload", size = hugePayload.len
|
||||||
|
|
||||||
|
proc connHandler(conn: Connection) {.async, gcsafe.} =
|
||||||
|
let sconn = await serverNoise.secure(conn)
|
||||||
|
defer:
|
||||||
|
await sconn.close()
|
||||||
|
let msg = await sconn.readLp()
|
||||||
|
check msg == hugePayload
|
||||||
|
readTask.complete()
|
||||||
|
|
||||||
|
let
|
||||||
|
transport1: TcpTransport = newTransport(TcpTransport)
|
||||||
|
asyncCheck await transport1.listen(server, connHandler)
|
||||||
|
|
||||||
|
let
|
||||||
|
transport2: TcpTransport = newTransport(TcpTransport)
|
||||||
|
clientInfo = PeerInfo.init(PrivateKey.random(RSA), [transport1.ma])
|
||||||
|
clientNoise = newNoise(clientInfo.privateKey, outgoing = true)
|
||||||
|
conn = await transport2.dial(transport1.ma)
|
||||||
|
sconn = await clientNoise.secure(conn)
|
||||||
|
|
||||||
|
await sconn.writeLp(hugePayload)
|
||||||
|
await readTask
|
||||||
|
await sconn.close()
|
||||||
|
await transport1.close()
|
||||||
|
|
||||||
|
result = true
|
||||||
|
|
||||||
|
check:
|
||||||
|
waitFor(testListenerDialer()) == true
|
||||||
|
|
||||||
test "e2e use switch dial proto string":
|
test "e2e use switch dial proto string":
|
||||||
proc testSwitch(): Future[bool] {.async, gcsafe.} =
|
proc testSwitch(): Future[bool] {.async, gcsafe.} =
|
||||||
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
|
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user