From d522537b19a532bc4af94fcd146f779c1f23bad0 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 7 Jul 2020 13:14:11 +0200 Subject: [PATCH] reuse single RNG instance for all crypto key generation (#249) * reuse single RNG instance for all crypto key generation * use foolproof rng * initRng -> newRng (because it's ref) * fix test * imports/exports, chat fix * fix rsa * imports and exports * work around threadvar issue * fixup * mac workaround test --- examples/directchat.nim | 11 +++-- libp2p/crypto/crypto.nim | 73 ++++++++++++++++++----------- libp2p/crypto/curve25519.nim | 20 +++----- libp2p/crypto/ecnist.nim | 15 +++--- libp2p/crypto/ed25519/ed25519.nim | 57 +++++++++++----------- libp2p/crypto/minasn1.nim | 2 - libp2p/crypto/rsa.nim | 40 ++++++---------- libp2p/crypto/secp.nim | 38 +++++++++------ libp2p/peerinfo.nim | 1 + libp2p/protocols/secure/noise.nim | 40 ++++++++-------- libp2p/protocols/secure/secio.nim | 20 ++++---- libp2p/protocols/secure/secure.nim | 4 +- libp2p/standard_setup.nim | 14 ++++-- libp2p/switch.nim | 27 +++++------ tests/helpers.nim | 20 +++++++- tests/pubsub/testfloodsub.nim | 1 - tests/pubsub/testgossipinternal.nim | 60 +++++++++++------------- tests/pubsub/testgossipsub.nim | 1 - tests/pubsub/testmcache.nim | 26 +++++----- tests/pubsub/testmessage.nim | 6 ++- tests/testcrypto.nim | 14 +++--- tests/testecnist.nim | 35 +++++++------- tests/tested25519.nim | 9 ++-- tests/testidentify.nim | 16 +++---- tests/testnoise.nim | 39 ++++++++------- tests/testpeerinfo.nim | 16 ++++--- tests/testrsa.nim | 33 +++++++------ tests/testsecp256k1.nim | 13 +++-- 28 files changed, 352 insertions(+), 299 deletions(-) diff --git a/examples/directchat.nim b/examples/directchat.nim index 22a9472f0..6843bed45 100644 --- a/examples/directchat.nim +++ b/examples/directchat.nim @@ -1,7 +1,7 @@ when not(compileOption("threads")): {.fatal: "Please, compile this program with the --threads:on option!".} -import tables, strformat, strutils +import tables, strformat, strutils, bearssl import chronos # an efficient library for async import ../libp2p/[switch, # manage transports, a single entry point for dialing and listening multistream, # tag stream with short header to identify it @@ -149,10 +149,10 @@ proc readInput(wfd: AsyncFD) {.thread.} = let line = stdin.readLine() discard waitFor transp.write(line & "\r\n") -proc processInput(rfd: AsyncFD) {.async.} = +proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} = let transp = fromPipe(rfd) - let seckey = PrivateKey.random(RSA).get() + let seckey = PrivateKey.random(RSA, rng[]).get() let peerInfo = PeerInfo.init(seckey) var localAddress = DefaultAddr while true: @@ -178,7 +178,7 @@ proc processInput(rfd: AsyncFD) {.async.} = let transports = @[Transport(TcpTransport.init())] let muxers = [(MplexCodec, mplexProvider)].toTable() let identify = newIdentify(peerInfo) - let secureManagers = [Secure(newSecio(seckey))] + let secureManagers = [Secure(newSecio(rng, seckey))] let switch = newSwitch(peerInfo, transports, identify, @@ -200,6 +200,7 @@ proc processInput(rfd: AsyncFD) {.async.} = await allFuturesThrowing(libp2pFuts) proc main() {.async.} = + let rng = newRng() # Singe random number source for the whole application let (rfd, wfd) = createAsyncPipe() if rfd == asyncInvalidPipe or wfd == asyncInvalidPipe: raise newException(ValueError, "Could not initialize pipe!") @@ -207,7 +208,7 @@ proc main() {.async.} = var thread: Thread[AsyncFD] thread.createThread(readInput, wfd) - await processInput(rfd) + await processInput(rfd, rng) when isMainModule: # isMainModule = true when the module is compiled as the main file waitFor(main()) diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index ef3807485..05c51a5fc 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -11,14 +11,14 @@ {.push raises: [Defect].} -import rsa, ecnist, ed25519/ed25519, secp +import rsa, ecnist, ed25519/ed25519, secp, bearssl import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec import nimcrypto/[rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils] import ../utility import stew/results export results -# This is workaround for Nim's `import` bug +# Export modules of types that are part of public API export rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils from strutils import split @@ -46,26 +46,26 @@ type PublicKey* = object case scheme*: PKScheme of RSA: - rsakey*: RsaPublicKey + rsakey*: rsa.RsaPublicKey of Ed25519: edkey*: EdPublicKey of Secp256k1: skkey*: SkPublicKey of ECDSA: - eckey*: EcPublicKey + eckey*: ecnist.EcPublicKey of NoSupport: discard PrivateKey* = object case scheme*: PKScheme of RSA: - rsakey*: RsaPrivateKey + rsakey*: rsa.RsaPrivateKey of Ed25519: edkey*: EdPrivateKey of Secp256k1: skkey*: SkPrivateKey of ECDSA: - eckey*: EcPrivateKey + eckey*: ecnist.EcPrivateKey of NoSupport: discard @@ -98,52 +98,68 @@ const template orError*(exp: untyped, err: untyped): untyped = (exp.mapErr do (_: auto) -> auto: err) -proc random*(t: typedesc[PrivateKey], scheme: PKScheme, - bits = DefaultKeySize): CryptoResult[PrivateKey] = +proc newRng*(): ref BrHmacDrbgContext = + # You should only create one instance of the RNG per application / library + # Ref is used so that it can be shared between components + # TODO consider moving to bearssl + var seeder = brPrngSeederSystem(nil) + if seeder == nil: + return nil + + var rng = (ref BrHmacDrbgContext)() + brHmacDrbgInit(addr rng[], addr sha256Vtable, nil, 0) + if seeder(addr rng.vtable) == 0: + return nil + rng + +proc random*( + T: typedesc[PrivateKey], scheme: PKScheme, + rng: var BrHmacDrbgContext, bits = DefaultKeySize): CryptoResult[PrivateKey] = ## Generate random private key for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in ## [512, 4096], default value is 2048 bits. case scheme of RSA: - let rsakey = ? RsaPrivateKey.random(bits).orError(KeyError) + let rsakey = ? RsaPrivateKey.random(rng, bits).orError(KeyError) ok(PrivateKey(scheme: scheme, rsakey: rsakey)) of Ed25519: - let edkey = ? EdPrivateKey.random().orError(KeyError) + let edkey = EdPrivateKey.random(rng) ok(PrivateKey(scheme: scheme, edkey: edkey)) of ECDSA: - let eckey = ? EcPrivateKey.random(Secp256r1).orError(KeyError) + let eckey = ? ecnist.EcPrivateKey.random(Secp256r1, rng).orError(KeyError) ok(PrivateKey(scheme: scheme, eckey: eckey)) of Secp256k1: - let skkey = ? SkPrivateKey.random().orError(KeyError) + let skkey = SkPrivateKey.random(rng) ok(PrivateKey(scheme: scheme, skkey: skkey)) else: err(SchemeError) -proc random*(t: typedesc[KeyPair], scheme: PKScheme, - bits = DefaultKeySize): CryptoResult[KeyPair] = +proc random*( + T: typedesc[KeyPair], scheme: PKScheme, + rng: var BrHmacDrbgContext, bits = DefaultKeySize): CryptoResult[KeyPair] = ## Generate random key pair for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in ## [512, 4096], default value is 2048 bits. case scheme of RSA: - let pair = ? RsaKeyPair.random(bits).orError(KeyError) + let pair = ? RsaKeyPair.random(rng, bits).orError(KeyError) ok(KeyPair( seckey: PrivateKey(scheme: scheme, rsakey: pair.seckey), pubkey: PublicKey(scheme: scheme, rsakey: pair.pubkey))) of Ed25519: - let pair = ? EdKeyPair.random().orError(KeyError) + let pair = EdKeyPair.random(rng) ok(KeyPair( seckey: PrivateKey(scheme: scheme, edkey: pair.seckey), pubkey: PublicKey(scheme: scheme, edkey: pair.pubkey))) of ECDSA: - let pair = ? EcKeyPair.random(Secp256r1).orError(KeyError) + let pair = ? EcKeyPair.random(Secp256r1, rng).orError(KeyError) ok(KeyPair( seckey: PrivateKey(scheme: scheme, eckey: pair.seckey), pubkey: PublicKey(scheme: scheme, eckey: pair.pubkey))) of Secp256k1: - let pair = ? SkKeyPair.random().orError(KeyError) + let pair = SkKeyPair.random(rng) ok(KeyPair( seckey: PrivateKey(scheme: scheme, skkey: pair.seckey), pubkey: PublicKey(scheme: scheme, skkey: pair.pubkey))) @@ -629,32 +645,35 @@ proc mac*(secret: Secret, id: int): seq[byte] {.inline.} = offset += secret.ivsize + secret.keysize copyMem(addr result[0], unsafeAddr secret.data[offset], secret.macsize) -proc ephemeral*(scheme: ECDHEScheme): CryptoResult[KeyPair] = +proc ephemeral*( + scheme: ECDHEScheme, + rng: var BrHmacDrbgContext): CryptoResult[KeyPair] = ## Generate ephemeral keys used to perform ECDHE. var keypair: EcKeyPair if scheme == Secp256r1: - keypair = ? EcKeyPair.random(Secp256r1).orError(KeyError) + keypair = ? EcKeyPair.random(Secp256r1, rng).orError(KeyError) elif scheme == Secp384r1: - keypair = ? EcKeyPair.random(Secp384r1).orError(KeyError) + keypair = ? EcKeyPair.random(Secp384r1, rng).orError(KeyError) elif scheme == Secp521r1: - keypair = ? EcKeyPair.random(Secp521r1).orError(KeyError) + keypair = ? EcKeyPair.random(Secp521r1, rng).orError(KeyError) ok(KeyPair( seckey: PrivateKey(scheme: ECDSA, eckey: keypair.seckey), pubkey: PublicKey(scheme: ECDSA, eckey: keypair.pubkey))) -proc ephemeral*(scheme: string): CryptoResult[KeyPair] {.inline.} = +proc ephemeral*( + scheme: string, rng: var BrHmacDrbgContext): CryptoResult[KeyPair] = ## Generate ephemeral keys used to perform ECDHE using string encoding. ## ## Currently supported encoding strings are P-256, P-384, P-521, if encoding ## string is not supported P-521 key will be generated. if scheme == "P-256": - ephemeral(Secp256r1) + ephemeral(Secp256r1, rng) elif scheme == "P-384": - ephemeral(Secp384r1) + ephemeral(Secp384r1, rng) elif scheme == "P-521": - ephemeral(Secp521r1) + ephemeral(Secp521r1, rng) else: - ephemeral(Secp521r1) + ephemeral(Secp521r1, rng) proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey, data: var openarray[byte]): int = diff --git a/libp2p/crypto/curve25519.nim b/libp2p/crypto/curve25519.nim index 5c0b0ed44..fbb84a3b3 100644 --- a/libp2p/crypto/curve25519.nim +++ b/libp2p/crypto/curve25519.nim @@ -28,8 +28,8 @@ type Curve25519* = object Curve25519Key* = array[Curve25519KeySize, byte] pcuchar = ptr cuchar - Curve25519Error* = enum - Curver25519RngError + Curve25519Error* = enum + Curver25519GenError proc intoCurve25519Key*(s: openarray[byte]): Curve25519Key = assert s.len == Curve25519KeySize @@ -105,16 +105,10 @@ proc mulgen*(_: type[Curve25519], dst: var Curve25519Key, point: Curve25519Key) proc public*(private: Curve25519Key): Curve25519Key = Curve25519.mulgen(result, private) -proc random*(_: type[Curve25519Key]): Result[Curve25519Key, Curve25519Error] = - var rng: BrHmacDrbgContext +proc random*(_: type[Curve25519Key], rng: var BrHmacDrbgContext): Result[Curve25519Key, Curve25519Error] = var res: Curve25519Key - let seeder = brPrngSeederSystem(nil) - brHmacDrbgInit(addr rng, addr sha256Vtable, nil, 0) - if seeder(addr rng.vtable) == 0: - err(Curver25519RngError) + let defaultBrEc = brEcGetDefault() + if brEcKeygen(addr rng.vtable, defaultBrEc, nil, addr res[0], EC_curve25519) != Curve25519KeySize: + err(Curver25519GenError) else: - let defaultBrEc = brEcGetDefault() - if brEcKeygen(addr rng.vtable, defaultBrEc, nil, addr res[0], EC_curve25519) != Curve25519KeySize: - err(Curver25519RngError) - else: - ok(res) + ok(res) diff --git a/libp2p/crypto/ecnist.nim b/libp2p/crypto/ecnist.nim index 03209305b..c33ea90c8 100644 --- a/libp2p/crypto/ecnist.nim +++ b/libp2p/crypto/ecnist.nim @@ -227,17 +227,14 @@ proc clear*[T: EcPKI|EcKeyPair](pki: var T) = pki.pubkey.key.qlen = 0 pki.pubkey.key.curve = 0 -proc random*(t: typedesc[EcPrivateKey], kind: EcCurveKind): EcResult[EcPrivateKey] = +proc random*( + T: typedesc[EcPrivateKey], kind: EcCurveKind, + rng: var BrHmacDrbgContext): EcResult[EcPrivateKey] = ## Generate new random EC private key using BearSSL's HMAC-SHA256-DRBG ## algorithm. ## ## ``kind`` elliptic curve kind of your choice (secp256r1, secp384r1 or ## secp521r1). - var rng: BrHmacDrbgContext - var seeder = brPrngSeederSystem(nil) - brHmacDrbgInit(addr rng, addr sha256Vtable, nil, 0) - if seeder(addr rng.vtable) == 0: - return err(EcRngError) var ecimp = brEcGetDefault() var res = new EcPrivateKey res.buffer = newSeq[byte](BR_EC_KBUF_PRIV_MAX_SIZE) @@ -266,14 +263,16 @@ proc getKey*(seckey: EcPrivateKey): EcResult[EcPublicKey] = else: err(EcKeyIncorrectError) -proc random*(t: typedesc[EcKeyPair], kind: EcCurveKind): EcResult[EcKeyPair] = +proc random*( + T: typedesc[EcKeyPair], kind: EcCurveKind, + rng: var BrHmacDrbgContext): EcResult[T] = ## Generate new random EC private and public keypair using BearSSL's ## HMAC-SHA256-DRBG algorithm. ## ## ``kind`` elliptic curve kind of your choice (secp256r1, secp384r1 or ## secp521r1). let - seckey = ? EcPrivateKey.random(kind) + seckey = ? EcPrivateKey.random(kind, rng) pubkey = ? seckey.getKey() key = EcKeyPair(seckey: seckey, pubkey: pubkey) ok(key) diff --git a/libp2p/crypto/ed25519/ed25519.nim b/libp2p/crypto/ed25519/ed25519.nim index 64305fd4e..3e69f4d1c 100644 --- a/libp2p/crypto/ed25519/ed25519.nim +++ b/libp2p/crypto/ed25519/ed25519.nim @@ -13,8 +13,8 @@ {.push raises: Defect.} -import constants -import nimcrypto/[hash, sha2, sysrand, utils] +import constants, bearssl +import nimcrypto/[hash, sha2, utils] import stew/results export results @@ -44,7 +44,6 @@ type pubkey*: EdPublicKey EdError* = enum - EdRngError, EdIncorrectError proc `-`(x: uint32): uint32 {.inline.} = @@ -1643,41 +1642,43 @@ proc checkScalar*(scalar: openarray[byte]): uint32 = c = -1 result = NEQ(z, 0'u32) and LT0(c) -proc random*(t: typedesc[EdPrivateKey]): Result[EdPrivateKey, EdError] = - ## Generate new random ED25519 private key using OS specific CSPRNG. +proc random*(t: typedesc[EdPrivateKey], rng: var BrHmacDrbgContext): EdPrivateKey = + ## Generate new random ED25519 private key using the given random number generator var point: GeP3 pk: array[EdPublicKeySize, byte] res: EdPrivateKey - if randomBytes(res.data.toOpenArray(0, 31)) != 32: - err(EdRngError) - else: - var hh = sha512.digest(res.data.toOpenArray(0, 31)) - hh.data[0] = hh.data[0] and 0xF8'u8 - hh.data[31] = hh.data[31] and 0x3F'u8 - hh.data[31] = hh.data[31] or 0x40'u8 - geScalarMultBase(point, hh.data) - geP3ToBytes(pk, point) - copyMem(addr res.data[32], addr pk[0], 32) - ok(res) -proc random*(t: typedesc[EdKeyPair]): Result[EdKeyPair, EdError] = + brHmacDrbgGenerate(addr rng, addr res.data[0], 32) + + var hh = sha512.digest(res.data.toOpenArray(0, 31)) + hh.data[0] = hh.data[0] and 0xF8'u8 + hh.data[31] = hh.data[31] and 0x3F'u8 + hh.data[31] = hh.data[31] or 0x40'u8 + geScalarMultBase(point, hh.data) + geP3ToBytes(pk, point) + res.data[32..63] = pk + + res + +proc random*(t: typedesc[EdKeyPair], rng: var BrHmacDrbgContext): EdKeyPair = ## Generate new random ED25519 private and public keypair using OS specific ## CSPRNG. var point: GeP3 res: EdKeyPair - if randomBytes(res.seckey.data.toOpenArray(0, 31)) != 32: - err(EdRngError) - else: - var hh = sha512.digest(res.seckey.data.toOpenArray(0, 31)) - hh.data[0] = hh.data[0] and 0xF8'u8 - hh.data[31] = hh.data[31] and 0x3F'u8 - hh.data[31] = hh.data[31] or 0x40'u8 - geScalarMultBase(point, hh.data) - geP3ToBytes(res.pubkey.data, point) - copyMem(addr res.seckey.data[32], addr res.pubkey.data[0], 32) - ok(res) + + brHmacDrbgGenerate(addr rng, addr res.seckey.data[0], 32) + + var hh = sha512.digest(res.seckey.data.toOpenArray(0, 31)) + hh.data[0] = hh.data[0] and 0xF8'u8 + hh.data[31] = hh.data[31] and 0x3F'u8 + hh.data[31] = hh.data[31] or 0x40'u8 + geScalarMultBase(point, hh.data) + geP3ToBytes(res.pubkey.data, point) + res.seckey.data[32..63] = res.pubkey.data + + res proc getKey*(key: EdPrivateKey): EdPublicKey = ## Calculate and return ED25519 public key from private key ``key``. diff --git a/libp2p/crypto/minasn1.nim b/libp2p/crypto/minasn1.nim index 63545f221..9363d2118 100644 --- a/libp2p/crypto/minasn1.nim +++ b/libp2p/crypto/minasn1.nim @@ -17,8 +17,6 @@ import nimcrypto/utils type Asn1Error* {.pure.} = enum - None, - Error, Overflow, Incomplete, Indefinite, diff --git a/libp2p/crypto/rsa.nim b/libp2p/crypto/rsa.nim index 5f40140c2..3aa7f7100 100644 --- a/libp2p/crypto/rsa.nim +++ b/libp2p/crypto/rsa.nim @@ -76,7 +76,6 @@ type RsaKP* = RsaPrivateKey | RsaKeyPair RsaError* = enum - RsaRngError, RsaGenError, RsaKeyIncorrectError, RsaSignatureError @@ -112,7 +111,8 @@ template trimZeroes(b: seq[byte], pt, ptlen: untyped) = pt = cast[ptr cuchar](cast[uint](pt) + 1) ptlen -= 1 -proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize, +proc random*[T: RsaKP](t: typedesc[T], rng: var BrHmacDrbgContext, + bits = DefaultKeySize, pubexp = DefaultPublicExponent): RsaResult[T] = ## Generate new random RSA private key using BearSSL's HMAC-SHA256-DRBG ## algorithm. @@ -121,38 +121,26 @@ proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize, ## range [512, 4096] (default = 2048). ## ## ``pubexp`` is RSA public exponent, which must be prime (default = 3). - var rng: BrHmacDrbgContext - var keygen: BrRsaKeygen - var seeder = brPrngSeederSystem(nil) - brHmacDrbgInit(addr rng, addr sha256Vtable, nil, 0) - if seeder(addr rng.vtable) == 0: - return err(RsaRngError) - - keygen = brRsaKeygenGetDefault() - - let length = brRsaPrivateKeyBufferSize(bits) + - brRsaPublicKeyBufferSize(bits) + - ((bits + 7) shr 3) - let sko = 0 - let pko = brRsaPrivateKeyBufferSize(bits) - let eko = pko + brRsaPublicKeyBufferSize(bits) - - var res: T - - when T is RsaKeyPair: - res = new T - else: - res = new RsaPrivateKey + let + sko = 0 + pko = brRsaPrivateKeyBufferSize(bits) + eko = pko + brRsaPublicKeyBufferSize(bits) + length = eko + ((bits + 7) shr 3) + let res = new T res.buffer = newSeq[byte](length) + + var keygen = brRsaKeygenGetDefault() + if keygen(addr rng.vtable, addr res.seck, addr res.buffer[sko], addr res.pubk, addr res.buffer[pko], cuint(bits), pubexp) == 0: return err(RsaGenError) - let compute = brRsaComputePrivexpGetDefault() - let computed = compute(addr res.buffer[eko], addr res.seck, pubexp) + let + compute = brRsaComputePrivexpGetDefault() + computed = compute(addr res.buffer[eko], addr res.seck, pubexp) if computed == 0: return err(RsaGenError) diff --git a/libp2p/crypto/secp.nim b/libp2p/crypto/secp.nim index 926e0f600..70f8e9b45 100644 --- a/libp2p/crypto/secp.nim +++ b/libp2p/crypto/secp.nim @@ -9,10 +9,12 @@ {.push raises: [Defect].} -import secp256k1, stew/byteutils, nimcrypto/hash, nimcrypto/sha2 -export sha2 -import stew/results -export results +import + secp256k1, bearssl, + stew/[byteutils, results], + nimcrypto/[hash, sha2] + +export sha2, results const SkRawPrivateKeySize* = 256 div 8 @@ -32,11 +34,19 @@ type template pubkey*(v: SkKeyPair): SkPublicKey = SkPublicKey(secp256k1.SkKeyPair(v).pubkey) template seckey*(v: SkKeyPair): SkPrivateKey = SkPrivateKey(secp256k1.SkKeyPair(v).seckey) -proc random*(t: typedesc[SkPrivateKey]): SkResult[SkPrivateKey] = - ok(SkPrivateKey(? SkSecretKey.random())) +proc random*(t: typedesc[SkPrivateKey], rng: var BrHmacDrbgContext): SkPrivateKey = + let rngPtr = unsafeAddr rng # doesn't escape + proc callRng(data: var openArray[byte]) = + brHmacDrbgGenerate(rngPtr[], data) -proc random*(t: typedesc[SkKeyPair]): SkResult[SkKeyPair] = - ok(SkKeyPair(? secp256k1.SkKeyPair.random())) + SkPrivateKey(SkSecretKey.random(callRng)) + +proc random*(t: typedesc[SkKeyPair], rng: var BrHmacDrbgContext): SkKeyPair = + let rngPtr = unsafeAddr rng # doesn't escape + proc callRng(data: var openArray[byte]) = + brHmacDrbgGenerate(rngPtr[], data) + + SkKeyPair(secp256k1.SkKeyPair.random(callRng)) template seckey*(v: SkKeyPair): SkPrivateKey = SkPrivateKey(secp256k1.SkKeyPair(v).seckey) @@ -90,14 +100,14 @@ proc init*(t: typedesc[SkPrivateKey], data: openarray[byte]): SkResult[SkPrivate ## representation ``data``. ## ## Procedure returns `private key` on success. - ok(SkPrivateKey(? SkSecretKey.fromRaw(data))) + SkSecretKey.fromRaw(data).mapConvert(SkPrivateKey) proc init*(t: typedesc[SkPrivateKey], data: string): SkResult[SkPrivateKey] = ## Initialize Secp256k1 `private key` from hexadecimal string ## representation ``data``. ## ## Procedure returns `private key` on success. - ok(SkPrivateKey(? SkSecretKey.fromHex(data))) + SkSecretKey.fromHex(data).mapConvert(SkPrivateKey) proc init*(t: typedesc[SkPublicKey], data: openarray[byte]): SkResult[SkPublicKey] = ## Initialize Secp256k1 `public key` from raw binary @@ -169,11 +179,11 @@ proc toBytes*(sig: SkSignature, data: var openarray[byte]): int = proc getBytes*(key: SkPrivateKey): seq[byte] {.inline.} = ## Serialize Secp256k1 `private key` and return it. - result = @(SkSecretKey(key).toRaw()) + @(SkSecretKey(key).toRaw()) proc getBytes*(key: SkPublicKey): seq[byte] {.inline.} = ## Serialize Secp256k1 `public key` and return it. - result = @(secp256k1.SkPublicKey(key).toRawCompressed()) + @(secp256k1.SkPublicKey(key).toRawCompressed()) proc getBytes*(sig: SkSignature): seq[byte] {.inline.} = ## Serialize Secp256k1 `signature` and return it. @@ -184,12 +194,12 @@ proc getBytes*(sig: SkSignature): seq[byte] {.inline.} = proc sign*[T: byte|char](key: SkPrivateKey, msg: openarray[T]): SkSignature = ## Sign message `msg` using private key `key` and return signature object. let h = sha256.digest(msg) - SkSignature(sign(SkSecretKey(key), h)) + SkSignature(sign(SkSecretKey(key), SkMessage(h.data))) proc verify*[T: byte|char](sig: SkSignature, msg: openarray[T], key: SkPublicKey): bool = let h = sha256.digest(msg) - verify(secp256k1.SkSignature(sig), h, secp256k1.SkPublicKey(key)) + verify(secp256k1.SkSignature(sig), SkMessage(h.data), secp256k1.SkPublicKey(key)) func clear*(key: var SkPrivateKey) {.borrow.} diff --git a/libp2p/peerinfo.nim b/libp2p/peerinfo.nim index 2b5353349..b885714d9 100644 --- a/libp2p/peerinfo.nim +++ b/libp2p/peerinfo.nim @@ -33,6 +33,7 @@ type lifefut: Future[void] protoVersion*: string agentVersion*: string + secure*: string case keyType*: KeyType: of HasPrivate: privateKey*: PrivateKey diff --git a/libp2p/protocols/secure/noise.nim b/libp2p/protocols/secure/noise.nim index 4319573ed..929104bd2 100644 --- a/libp2p/protocols/secure/noise.nim +++ b/libp2p/protocols/secure/noise.nim @@ -9,8 +9,9 @@ import chronos import chronicles +import bearssl import stew/[endians2, byteutils] -import nimcrypto/[utils, sysrand, sha2, hmac] +import nimcrypto/[utils, sha2, hmac] import ../../stream/lpstream import ../../peerid import ../../peerinfo @@ -69,10 +70,10 @@ type rs: Curve25519Key Noise* = ref object of Secure + rng: ref BrHmacDrbgContext localPrivateKey: PrivateKey localPublicKey: PublicKey - noisePrivateKey: Curve25519Key - noisePublicKey: Curve25519Key + noiseKeys: KeyPair commonPrologue: seq[byte] outgoing: bool @@ -87,8 +88,8 @@ type # Utility -proc genKeyPair(): KeyPair = - result.privateKey = Curve25519Key.random().tryGet() +proc genKeyPair(rng: var BrHmacDrbgContext): KeyPair = + result.privateKey = Curve25519Key.random(rng).tryGet() result.publicKey = result.privateKey.public() proc hashProtocol(name: string): MDigest[256] = @@ -200,7 +201,7 @@ proc init(_: type[HandshakeState]): HandshakeState = template write_e: untyped = trace "noise write e" # Sets e (which must be empty) to GENERATE_KEYPAIR(). Appends e.public_key to the buffer. Calls MixHash(e.public_key). - hs.e = genKeyPair() + hs.e = genKeyPair(p.rng[]) msg &= hs.e.publicKey hs.ss.mixHash(hs.e.publicKey) @@ -293,8 +294,7 @@ proc handshakeXXOutbound(p: Noise, conn: Connection, p2pProof: ProtoBuffer): Fut p2psecret = p2pProof.buffer hs.ss.mixHash(p.commonPrologue) - hs.s.privateKey = p.noisePrivateKey - hs.s.publicKey = p.noisePublicKey + hs.s = p.noiseKeys # -> e var msg: seq[byte] @@ -340,8 +340,7 @@ proc handshakeXXInbound(p: Noise, conn: Connection, p2pProof: ProtoBuffer): Futu p2psecret = p2pProof.buffer hs.ss.mixHash(p.commonPrologue) - hs.s.privateKey = p.noisePrivateKey - hs.s.publicKey = p.noisePublicKey + hs.s = p.noiseKeys # -> e @@ -418,7 +417,7 @@ method handshake*(p: Noise, conn: Connection, initiator: bool): Future[SecureCon # https://github.com/libp2p/specs/tree/master/noise#libp2p-data-in-handshake-messages let signedPayload = p.localPrivateKey.sign( - PayloadString.toBytes & p.noisePublicKey.getBytes).tryGet() + PayloadString.toBytes & p.noiseKeys.publicKey.getBytes).tryGet() var libp2pProof = initProtoBuffer() @@ -485,12 +484,15 @@ method init*(p: Noise) {.gcsafe.} = procCall Secure(p).init() p.codec = NoiseCodec -proc newNoise*(privateKey: PrivateKey; outgoing: bool = true; commonPrologue: seq[byte] = @[]): Noise = - new result - result.outgoing = outgoing - result.localPrivateKey = privateKey - result.localPublicKey = privateKey.getKey().tryGet() - result.noisePrivateKey = Curve25519Key.random().tryGet() - result.noisePublicKey = result.noisePrivateKey.public() - result.commonPrologue = commonPrologue +proc newNoise*( + rng: ref BrHmacDrbgContext, privateKey: PrivateKey; + outgoing: bool = true; commonPrologue: seq[byte] = @[]): Noise = + result = Noise( + rng: rng, + outgoing: outgoing, + localPrivateKey: privateKey, + localPublicKey: privateKey.getKey().tryGet(), + noiseKeys: genKeyPair(rng[]), + commonPrologue: commonPrologue, + ) result.init() diff --git a/libp2p/protocols/secure/secio.nim b/libp2p/protocols/secure/secio.nim index 331092461..bbd3950a2 100644 --- a/libp2p/protocols/secure/secio.nim +++ b/libp2p/protocols/secure/secio.nim @@ -6,8 +6,8 @@ ## at your option. ## This file may not be copied, modified, or distributed except according to ## those terms. -import chronos, chronicles, oids, stew/endians2 -import nimcrypto/[sysrand, hmac, sha2, sha, hash, rijndael, twofish, bcmode] +import chronos, chronicles, oids, stew/endians2, bearssl +import nimcrypto/[hmac, sha2, sha, hash, rijndael, twofish, bcmode] import secure, ../../stream/connection, ../../peerinfo, @@ -32,6 +32,7 @@ const type Secio = ref object of Secure + rng: ref BrHmacDrbgContext localPrivateKey: PrivateKey localPublicKey: PublicKey remotePublicKey: PublicKey @@ -288,8 +289,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S localPeerId: PeerID localBytesPubkey = s.localPublicKey.getBytes().tryGet() - if randomBytes(localNonce) != SecioNonceSize: - raise (ref SecioError)(msg: "Could not generate random data") + brHmacDrbgGenerate(s.rng[], localNonce) var request = createProposal(localNonce, localBytesPubkey, @@ -340,7 +340,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S trace "Encryption scheme selected", scheme = scheme, cipher = cipher, hash = hash - var ekeypair = ephemeral(scheme).tryGet() + var ekeypair = ephemeral(scheme, s.rng[]).tryGet() # We need EC public key in raw binary form var epubkey = ekeypair.pubkey.eckey.getRawBytes().tryGet() var localCorpus = request[4..^1] & answer & epubkey @@ -410,8 +410,10 @@ method init(s: Secio) {.gcsafe.} = procCall Secure(s).init() s.codec = SecioCodec -proc newSecio*(localPrivateKey: PrivateKey): Secio = - new result - result.localPrivateKey = localPrivateKey - result.localPublicKey = localPrivateKey.getKey().tryGet() +proc newSecio*(rng: ref BrHmacDrbgContext, localPrivateKey: PrivateKey): Secio = + result = Secio( + rng: rng, + localPrivateKey: localPrivateKey, + localPublicKey: localPrivateKey.getKey().tryGet(), + ) result.init() diff --git a/libp2p/protocols/secure/secure.nim b/libp2p/protocols/secure/secure.nim index 3aa354f92..e48025aa5 100644 --- a/libp2p/protocols/secure/secure.nim +++ b/libp2p/protocols/secure/secure.nim @@ -8,7 +8,7 @@ ## those terms. import options -import chronos, chronicles +import chronos, chronicles, bearssl import ../protocol, ../../stream/streamseq, ../../stream/connection, @@ -66,6 +66,8 @@ proc handleConn*(s: Secure, conn: Connection, initiator: bool): Future[Connectio return sconn method init*(s: Secure) {.gcsafe.} = + procCall LPProtocol(s).init() + proc handle(conn: Connection, proto: string) {.async, gcsafe.} = trace "handling connection upgrade", proto try: diff --git a/libp2p/standard_setup.nim b/libp2p/standard_setup.nim index 73695d437..fc9d2eeb2 100644 --- a/libp2p/standard_setup.nim +++ b/libp2p/standard_setup.nim @@ -4,7 +4,7 @@ const libp2p_pubsub_verify {.booldefine.} = true import - options, tables, chronos, + options, tables, chronos, bearssl, switch, peerid, peerinfo, stream/connection, multiaddress, crypto/crypto, transports/[transport, tcptransport], muxers/[muxer, mplex/mplex, mplex/types], @@ -36,12 +36,16 @@ proc newStandardSwitch*(privKey = none(PrivateKey), verifySignature = libp2p_pubsub_verify, sign = libp2p_pubsub_sign, transportFlags: set[ServerFlags] = {}, - msgIdProvider: MsgIdProvider = defaultMsgIdProvider): Switch = + msgIdProvider: MsgIdProvider = defaultMsgIdProvider, + rng = newRng()): Switch = proc createMplex(conn: Connection): Muxer = newMplex(conn) + if rng == nil: # newRng could fail + raise (ref CatchableError)(msg: "Cannot initialize RNG") + let - seckey = privKey.get(otherwise = PrivateKey.random(ECDSA).tryGet()) + seckey = privKey.get(otherwise = PrivateKey.random(ECDSA, rng[]).tryGet()) peerInfo = PeerInfo.init(seckey, [address]) mplexProvider = newMuxerProvider(createMplex, MplexCodec) transports = @[Transport(TcpTransport.init(transportFlags))] @@ -53,9 +57,9 @@ proc newStandardSwitch*(privKey = none(PrivateKey), for sec in secureManagers: case sec of SecureProtocol.Noise: - secureManagerInstances &= newNoise(seckey).Secure + secureManagerInstances &= newNoise(rng, seckey).Secure of SecureProtocol.Secio: - secureManagerInstances &= newSecio(seckey).Secure + secureManagerInstances &= newSecio(rng, seckey).Secure let pubSub = if gossip: newPubSub(GossipSub, diff --git a/libp2p/switch.nim b/libp2p/switch.nim index c7047c98c..0ec74ad88 100644 --- a/libp2p/switch.nim +++ b/libp2p/switch.nim @@ -645,15 +645,19 @@ proc newSwitch*(peerInfo: PeerInfo, muxers: Table[string, MuxerProvider], secureManagers: openarray[Secure] = [], pubSub: Option[PubSub] = none(PubSub)): Switch = - new result - result.peerInfo = peerInfo - result.ms = newMultistream() - result.transports = transports - result.connections = initTable[string, seq[ConnectionHolder]]() - result.muxed = initTable[string, seq[MuxerHolder]]() - result.identity = identity - result.muxers = muxers - result.secureManagers = @secureManagers + if secureManagers.len == 0: + raise (ref CatchableError)(msg: "Provide at least one secure manager") + + result = Switch( + peerInfo: peerInfo, + ms: newMultistream(), + transports: transports, + connections: initTable[string, seq[ConnectionHolder]](), + muxed: initTable[string, seq[MuxerHolder]](), + identity: identity, + muxers: muxers, + secureManagers: @secureManagers, + ) let s = result # can't capture result result.streamHandler = proc(stream: Connection) {.async, gcsafe.} = @@ -674,11 +678,6 @@ proc newSwitch*(peerInfo: PeerInfo, val.muxerHandler = proc(muxer: Muxer): Future[void] = s.muxerHandler(muxer) - if result.secureManagers.len <= 0: - # use plain text if no secure managers are provided - warn "no secure managers, falling back to plain text", codec = PlainTextCodec - result.secureManagers &= Secure(newPlainText()) - if pubSub.isSome: result.pubSub = pubSub result.mount(pubSub.get()) diff --git a/tests/helpers.nim b/tests/helpers.nim index db1e08f99..2e10c0153 100644 --- a/tests/helpers.nim +++ b/tests/helpers.nim @@ -1,7 +1,8 @@ -import chronos +import chronos, bearssl import ../libp2p/transports/tcptransport import ../libp2p/stream/bufferstream +import ../libp2p/crypto/crypto import ../libp2p/stream/lpstream const @@ -23,3 +24,20 @@ iterator testTrackers*(extras: openArray[string] = []): TrackerBase = for name in extras: let t = getTracker(name) if not isNil(t): yield t + +type RngWrap = object + rng: ref BrHmacDrbgContext + +var rngVar: RngWrap + +proc getRng(): ref BrHmacDrbgContext = + # TODO if `rngVar` is a threadvar like it should be, there are random and + # spurious compile failures on mac - this is not gcsafe but for the + # purpose of the tests, it's ok as long as we only use a single thread + {.gcsafe.}: + if rngVar.rng.isNil: + rngVar.rng = newRng() + rngVar.rng + +template rng*(): ref BrHmacDrbgContext = + getRng() diff --git a/tests/pubsub/testfloodsub.nim b/tests/pubsub/testfloodsub.nim index 319a41ede..119c51e67 100644 --- a/tests/pubsub/testfloodsub.nim +++ b/tests/pubsub/testfloodsub.nim @@ -15,7 +15,6 @@ import utils, ../../libp2p/[errors, switch, stream/connection, - stream/bufferstream, crypto/crypto, protocols/pubsub/pubsub, protocols/pubsub/floodsub, diff --git a/tests/pubsub/testgossipinternal.nim b/tests/pubsub/testgossipinternal.nim index 603dfaa9b..e3d3c6060 100644 --- a/tests/pubsub/testgossipinternal.nim +++ b/tests/pubsub/testgossipinternal.nim @@ -2,7 +2,7 @@ include ../../libp2p/protocols/pubsub/gossipsub {.used.} -import unittest +import unittest, bearssl import stew/byteutils import ../../libp2p/errors import ../../libp2p/crypto/crypto @@ -15,6 +15,9 @@ type proc noop(data: seq[byte]) {.async, gcsafe.} = discard +proc randomPeerInfo(): PeerInfo = + PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) + suite "GossipSub internal": teardown: for tracker in testTrackers(): @@ -23,8 +26,7 @@ suite "GossipSub internal": test "`rebalanceMesh` Degree Lo": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) let topic = "foobar" gossipSub.mesh[topic] = initHashSet[string]() @@ -33,7 +35,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].conn = conn @@ -52,8 +54,7 @@ suite "GossipSub internal": test "`rebalanceMesh` Degree Hi": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) let topic = "foobar" gossipSub.gossipsub[topic] = initHashSet[string]() @@ -62,7 +63,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].conn = conn @@ -81,8 +82,7 @@ suite "GossipSub internal": test "`replenishFanout` Degree Lo": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -94,7 +94,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newBufferStream(noop) conns &= conn - var peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + var peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -113,8 +113,7 @@ suite "GossipSub internal": test "`dropFanoutPeers` drop expired fanout topics": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -128,7 +127,7 @@ suite "GossipSub internal": for i in 0..<6: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -148,8 +147,7 @@ suite "GossipSub internal": test "`dropFanoutPeers` leave unexpired fanout topics": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -166,7 +164,7 @@ suite "GossipSub internal": for i in 0..<6: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -189,8 +187,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should gather up to degree D non intersecting peers": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -205,7 +202,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -218,7 +215,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -228,7 +225,7 @@ suite "GossipSub internal": for i in 0..5: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, false) gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg) @@ -252,8 +249,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in mesh": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -265,7 +261,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -278,7 +274,7 @@ suite "GossipSub internal": for i in 0..5: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, false) gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg) @@ -295,8 +291,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in fanout": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -308,7 +303,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -321,7 +316,7 @@ suite "GossipSub internal": for i in 0..5: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo let msg = Message.init(peerInfo, ("HELLO" & $i).toBytes(), topic, false) gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg) @@ -338,8 +333,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in gossip": proc testRun(): Future[bool] {.async.} = - let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(ECDSA).get())) + let gossipSub = newPubSub(TestGossipSub, randomPeerInfo()) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -351,7 +345,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -364,7 +358,7 @@ suite "GossipSub internal": for i in 0..5: let conn = newBufferStream(noop) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA).get()) + let peerInfo = randomPeerInfo() conn.peerInfo = peerInfo let msg = Message.init(peerInfo, ("bar" & $i).toBytes(), topic, false) gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg) diff --git a/tests/pubsub/testgossipsub.nim b/tests/pubsub/testgossipsub.nim index 197c967c0..5050d6eeb 100644 --- a/tests/pubsub/testgossipsub.nim +++ b/tests/pubsub/testgossipsub.nim @@ -17,7 +17,6 @@ import utils, ../../libp2p/[errors, peerinfo, stream/connection, crypto/crypto, - stream/bufferstream, protocols/pubsub/pubsub, protocols/pubsub/gossipsub, protocols/pubsub/rpc/messages] diff --git a/tests/pubsub/testmcache.nim b/tests/pubsub/testmcache.nim index 90a1b1139..2301e570a 100644 --- a/tests/pubsub/testmcache.nim +++ b/tests/pubsub/testmcache.nim @@ -1,6 +1,6 @@ {.used.} -import unittest, options, sets, sequtils +import unittest, options, sets, sequtils, bearssl import stew/byteutils import ../../libp2p/[peerid, crypto/crypto, @@ -8,11 +8,15 @@ import ../../libp2p/[peerid, protocols/pubsub/rpc/message, protocols/pubsub/rpc/messages] +var rng = newRng() + +proc randomPeerID(): PeerID = + PeerID.init(PrivateKey.random(ECDSA, rng[]).get()).get() + suite "MCache": test "put/get": var mCache = newMCache(3, 5) - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), - seqno: "12345".toBytes()) + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes()) let msgId = defaultMsgIdProvider(msg) mCache.put(msgId, msg) check mCache.get(msgId).isSome and mCache.get(msgId).get() == msg @@ -21,13 +25,13 @@ suite "MCache": var mCache = newMCache(3, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["foo"]) mCache.put(defaultMsgIdProvider(msg), msg) for i in 0..<5: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["bar"]) mCache.put(defaultMsgIdProvider(msg), msg) @@ -42,7 +46,7 @@ suite "MCache": var mCache = newMCache(1, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["foo"]) mCache.put(defaultMsgIdProvider(msg), msg) @@ -51,7 +55,7 @@ suite "MCache": check mCache.window("foo").len == 0 for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["bar"]) mCache.put(defaultMsgIdProvider(msg), msg) @@ -60,7 +64,7 @@ suite "MCache": check mCache.window("bar").len == 0 for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["baz"]) mCache.put(defaultMsgIdProvider(msg), msg) @@ -72,19 +76,19 @@ suite "MCache": var mCache = newMCache(1, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["foo"]) mCache.put(defaultMsgIdProvider(msg), msg) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["bar"]) mCache.put(defaultMsgIdProvider(msg), msg) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(ECDSA).get()).get(), + var msg = Message(fromPeer: randomPeerID(), seqno: "12345".toBytes(), topicIDs: @["baz"]) mCache.put(defaultMsgIdProvider(msg), msg) diff --git a/tests/pubsub/testmessage.nim b/tests/pubsub/testmessage.nim index 1c9092d45..48acffcef 100644 --- a/tests/pubsub/testmessage.nim +++ b/tests/pubsub/testmessage.nim @@ -1,14 +1,18 @@ import unittest +{.used.} + import ../../libp2p/[peerid, peerinfo, crypto/crypto, protocols/pubsub/rpc/message, protocols/pubsub/rpc/messages] +let rng = newRng() + suite "Message": test "signature": let - peer = PeerInfo.init(PrivateKey.random(ECDSA).get()) + peer = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) msg = Message.init(peer, @[], "topic", sign = true) check verify(msg, peer) diff --git a/tests/testcrypto.nim b/tests/testcrypto.nim index 0b61101dd..a44c867cf 100644 --- a/tests/testcrypto.nim +++ b/tests/testcrypto.nim @@ -374,6 +374,8 @@ proc testStretcher(s, e: int, cs: string, ds: string): bool = if not result: break +let rng = newRng() + suite "Key interface test suite": test "Go test vectors": @@ -394,9 +396,9 @@ suite "Key interface test suite": var bmsg = cast[seq[byte]](msg) for i in 0..<5: - var seckey = PrivateKey.random(ECDSA).get() + var seckey = PrivateKey.random(ECDSA, rng[]).get() var pubkey = seckey.getKey().get() - var pair = KeyPair.random(ECDSA).get() + var pair = KeyPair.random(ECDSA, rng[]).get() var sig1 = pair.seckey.sign(bmsg).get() var sig2 = seckey.sign(bmsg).get() var sersig1 = sig1.getBytes() @@ -414,9 +416,9 @@ suite "Key interface test suite": recsig2.verify(bmsg, recpub2) == true for i in 0..<5: - var seckey = PrivateKey.random(Ed25519).get() + var seckey = PrivateKey.random(Ed25519, rng[]).get() var pubkey = seckey.getKey().get() - var pair = KeyPair.random(Ed25519).get() + var pair = KeyPair.random(Ed25519, rng[]).get() var sig1 = pair.seckey.sign(bmsg).get() var sig2 = seckey.sign(bmsg).get() var sersig1 = sig1.getBytes() @@ -434,9 +436,9 @@ suite "Key interface test suite": recsig2.verify(bmsg, recpub2) == true for i in 0..<5: - var seckey = PrivateKey.random(RSA, 512).get() + var seckey = PrivateKey.random(RSA, rng[], 512).get() var pubkey = seckey.getKey().get() - var pair = KeyPair.random(RSA, 512).get() + var pair = KeyPair.random(RSA, rng[], 512).get() var sig1 = pair.seckey.sign(bmsg).get() var sig2 = seckey.sign(bmsg).get() var sersig1 = sig1.getBytes() diff --git a/tests/testecnist.nim b/tests/testecnist.nim index bbd4b2565..aa2245ce3 100644 --- a/tests/testecnist.nim +++ b/tests/testecnist.nim @@ -8,7 +8,7 @@ ## those terms. import unittest import nimcrypto/utils -import ../libp2p/crypto/ecnist +import ../libp2p/crypto/[crypto, ecnist] import stew/results when defined(nimHasUsed): {.used.} @@ -294,13 +294,14 @@ const 35ab""" ] -suite "EC NIST-P256/384/521 test suite": +let rng = newRng() +suite "EC NIST-P256/384/521 test suite": test "[secp256r1] Private key serialize/deserialize test": for i in 0.. 0 @@ -319,7 +320,7 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 @@ -335,8 +336,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp256r1] ECDHE test": for i in 0.. 0 @@ -426,7 +427,7 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 @@ -442,8 +443,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp384r1] ECDHE test": for i in 0.. 0 @@ -533,7 +534,7 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 @@ -549,8 +550,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp521r1] ECDHE test": for i in 0.. 0 @@ -135,7 +138,7 @@ suite "Ed25519 test suite": for i in 0.. 0 @@ -171,7 +174,7 @@ suite "Ed25519 test suite": test "Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0.. 0 check: @@ -291,7 +296,7 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 check: @@ -308,7 +313,7 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa2048] Private key serialize/deserialize test": var rkey1, rkey2: RsaPrivateKey var skey2 = newSeq[byte](4096) - var key = RsaPrivateKey.random(2048).expect("random failed") + var key = RsaPrivateKey.random(rng[], 2048).expect("random failed") var skey1 = key.getBytes().expect("bytes") check key.toBytes(skey2).expect("bytes") > 0 check: @@ -327,7 +332,7 @@ suite "RSA 512/1024/2048/4096 test suite": when defined(release): var rkey1, rkey2: RsaPrivateKey var skey2 = newSeq[byte](4096) - var key = RsaPrivateKey.random(4096).expect("random failed") + var key = RsaPrivateKey.random(rng[], 4096).expect("random failed") var skey1 = key.getBytes().expect("bytes") check key.toBytes(skey2).expect("bytes") > 0 check: @@ -345,7 +350,7 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 @@ -363,7 +368,7 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 @@ -380,7 +385,7 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa2048] Public key serialize/deserialize test": var rkey1, rkey2: RsaPublicKey var skey2 = newSeq[byte](4096) - var pair = RsaKeyPair.random(2048).expect("random failed") + var pair = RsaKeyPair.random(rng[], 2048).expect("random failed") var skey1 = pair.pubkey.getBytes().expect("bytes") check: pair.pubkey.toBytes(skey2).expect("bytes") > 0 @@ -398,7 +403,7 @@ suite "RSA 512/1024/2048/4096 test suite": when defined(release): var rkey1, rkey2: RsaPublicKey var skey2 = newSeq[byte](4096) - var pair = RsaKeyPair.random(4096).expect("random failed") + var pair = RsaKeyPair.random(rng[], 4096).expect("random failed") var skey1 = pair.pubkey.getBytes().expect("bytes") check: pair.pubkey.toBytes(skey2).expect("bytes") > 0 @@ -415,7 +420,7 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa512] Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0.. 0 @@ -36,7 +39,7 @@ suite "Secp256k1 testing suite": for i in 0.. 0 @@ -52,7 +55,7 @@ suite "Secp256k1 testing suite": test "Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0..