diff --git a/ethp2p.nimble b/ethp2p.nimble index e6c7de9..abfbdf9 100644 --- a/ethp2p.nimble +++ b/ethp2p.nimble @@ -18,7 +18,6 @@ requires "nim > 0.18.0", proc runTest(name: string, lang = "c") = exec "nim " & lang & " -r tests/" & name task test, "Runs the test suite": - runTest "testecc" runTest "testecies" runTest "testauth" diff --git a/ethp2p/auth.nim b/ethp2p/auth.nim index 1acad5c..9530e5b 100644 --- a/ethp2p/auth.nim +++ b/ethp2p/auth.nim @@ -10,7 +10,7 @@ ## This module implements Ethereum authentication import endians -import ecc, ecies, rlp +import eth_keys, ecies, rlp import nimcrypto/sysrand, nimcrypto/hash, nimcrypto/utils, nimcrypto/hmac import nimcrypto/rijndael, nimcrypto/keccak, nimcrypto/sha2 @@ -30,15 +30,17 @@ const AckMessageMaxEIP8* = AckMessageEIP8Length + 255 type + Nonce* = array[KeyLength, byte] + AuthMessageV4* = object {.packed.} - signature: RawSignature + signature: array[RawSignatureSize, byte] keyhash: array[keccak256.sizeDigest, byte] pubkey: PublicKey nonce: array[keccak256.sizeDigest, byte] flag: byte AckMessageV4* = object {.packed.} - pubkey: PublicKey + pubkey: array[RawPublicKeySize, byte] nonce: array[keccak256.sizeDigest, byte] flag: byte @@ -115,16 +117,17 @@ proc authMessagePreEIP8(h: var Handshake, outlen = 0 flagb = byte(flag) header = cast[ptr AuthMessageV4](addr buffer[0]) - if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) var xornonce = h.initiatorNonce - xornonce.sxor(secret) - if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success: + xornonce.sxor(secret.data) + if signRawMessage(xornonce, h.ephemeral.seckey, + signature) != EthKeysStatus.Success: return(SignatureError) h.remoteHPubkey = pubkey header.signature = signature.getRaw() - header.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw().data).data - header.pubkey = cast[PublicKey](h.host.pubkey.getRaw().data) + header.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw()).data + header.pubkey = cast[PublicKey](h.host.pubkey.getRaw()) header.nonce = h.initiatorNonce header.flag = flagb if encrypt: @@ -156,15 +159,16 @@ proc authMessageEIP8(h: var Handshake, assert(EIP8 in h.flags) outlen = 0 - if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) var xornonce = h.initiatorNonce - xornonce.sxor(secret) - if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success: + xornonce.sxor(secret.data) + if signRawMessage(xornonce, h.ephemeral.seckey, + signature) != EthKeysStatus.Success: return(SignatureError) h.remoteHPubkey = pubkey - var payload = rlp.encodeList(signature.getRaw().data, - h.host.pubkey.getRaw().data, + var payload = rlp.encodeList(signature.getRaw(), + h.host.pubkey.getRaw(), h.initiatorNonce, [byte(h.version)]) assert(len(payload) == PlainAuthMessageEIP8Length) @@ -208,7 +212,7 @@ proc ackMessagePreEIP8(h: var Handshake, var buffer: array[PlainAckMessageV4Length, byte] outlen = 0 var header = cast[ptr AckMessageV4](addr buffer[0]) - header.pubkey = cast[PublicKey](h.ephemeral.pubkey.getRaw().data) + header.pubkey = h.ephemeral.pubkey.getRaw() header.nonce = h.responderNonce header.flag = byte(flag) if encrypt: @@ -234,7 +238,7 @@ proc ackMessageEIP8(h: var Handshake, buffer: array[PlainAckMessageMaxEIP8, byte] padsize: byte assert(EIP8 in h.flags) - var payload = rlp.encodeList(h.ephemeral.pubkey.getRaw().data, + var payload = rlp.encodeList(h.ephemeral.pubkey.getRaw(), h.responderNonce, [byte(h.version)]) assert(len(payload) == PlainAckMessageEIP8Length) @@ -316,14 +320,14 @@ proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthStatus = if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success: return(EciesError) var header = cast[ptr AuthMessageV4](addr buffer[0]) - if recoverPublicKey(header.pubkey.data, pubkey) != EccStatus.Success: + if recoverPublicKey(header.pubkey.data, pubkey) != EthKeysStatus.Success: return(InvalidPubKey) - if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) var xornonce = header.nonce - xornonce.sxor(secret) - if recoverSignatureKey(header.signature.data, xornonce, - h.remoteEPubkey) != EccStatus.Success: + xornonce.sxor(secret.data) + if recoverSignatureKey(header.signature, xornonce, + h.remoteEPubkey) != EthKeysStatus.Success: return(SignatureError) h.initiatorNonce = header.nonce h.remoteHPubkey = pubkey @@ -347,9 +351,9 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthStatus = var reader = rlpFromBytes(buffer.toRange()) if not reader.isList() or reader.listLen() < 4: return(InvalidAuth) - if reader.listElem(0).blobLen != SignatureLength: + if reader.listElem(0).blobLen != RawSignatureSize: return(InvalidAuth) - if reader.listElem(1).blobLen != PublicKeyLength: + if reader.listElem(1).blobLen != RawPublicKeySize: return(InvalidAuth) if reader.listElem(2).blobLen != KeyLength: return(InvalidAuth) @@ -359,17 +363,17 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthStatus = var pubkeyBr = reader.listElem(1).toBytes() var nonceBr = reader.listElem(2).toBytes() var versionBr = reader.listElem(3).toBytes() - if recoverPublicKey(pubkeyBr.baseAddr, PublicKeyLength, - pubkey) != EccStatus.Success: + if recoverPublicKey(pubkeyBr.toOpenArray(), + pubkey) != EthKeysStatus.Success: return(InvalidPubKey) copyMem(addr nonce[0], nonceBr.baseAddr, KeyLength) - if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) var xornonce = nonce - xornonce.sxor(secret) - if recoverSignatureKey(signatureBr.baseAddr, SignatureLength, - addr xornonce[0], - h.remoteEPubkey) != EccStatus.Success: + xornonce.sxor(secret.data) + if recoverSignatureKey(signatureBr.toOpenArray(), + xornonce, + h.remoteEPubkey) != EthKeysStatus.Success: return(SignatureError) h.initiatorNonce = nonce h.remoteHPubkey = pubkey @@ -393,7 +397,7 @@ proc decodeAckMessageEip8*(h: var Handshake, m: openarray[byte]): AuthStatus = var reader = rlpFromBytes(buffer.toRange()) if not reader.isList() or reader.listLen() < 3: return(InvalidAck) - if reader.listElem(0).blobLen != PublicKeyLength: + if reader.listElem(0).blobLen != RawPublicKeySize: return(InvalidAck) if reader.listElem(1).blobLen != KeyLength: return(InvalidAck) @@ -402,8 +406,8 @@ proc decodeAckMessageEip8*(h: var Handshake, m: openarray[byte]): AuthStatus = let pubkeyBr = reader.listElem(0).toBytes() let nonceBr = reader.listElem(1).toBytes() let versionBr = reader.listElem(2).toBytes() - if recoverPublicKey(pubkeyBr.baseAddr, PublicKeyLength, - h.remoteEPubkey) != EccStatus.Success: + if recoverPublicKey(pubkeyBr.toOpenArray(), + h.remoteEPubkey) != EthKeysStatus.Success: return(InvalidPubKey) copyMem(addr h.responderNonce[0], nonceBr.baseAddr, KeyLength) h.version = cast[ptr byte](versionBr.baseAddr)[] @@ -419,7 +423,7 @@ proc decodeAckMessageV4(h: var Handshake, m: openarray[byte]): AuthStatus = if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success: return(EciesError) var header = cast[ptr AckMessageV4](addr buffer[0]) - if recoverPublicKey(header.pubkey.data, h.remoteEPubkey) != EccStatus.Success: + if recoverPublicKey(header.pubkey, h.remoteEPubkey) != EthKeysStatus.Success: return(InvalidPubKey) h.responderNonce = header.nonce result = Success @@ -476,7 +480,8 @@ proc getSecrets*(h: Handshake, authmsg: openarray[byte], xornonce: Nonce # ecdhe-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk) - if ecdhAgree(h.ephemeral.seckey, h.remoteEPubkey, shsec) != EccStatus.Success: + if ecdhAgree(h.ephemeral.seckey, h.remoteEPubkey, + shsec) != EthKeysStatus.Success: return(EcdhError) # shared-secret = keccak(ecdhe-secret || keccak(nonce || initiator-nonce)) @@ -486,19 +491,19 @@ proc getSecrets*(h: Handshake, authmsg: openarray[byte], ctx1.update(h.initiatorNonce) mac1 = ctx1.finish() ctx1.clear() - ctx0.update(shsec) + ctx0.update(shsec.data) ctx0.update(mac1.data) mac1 = ctx0.finish() # aes-secret = keccak(ecdhe-secret || shared-secret) ctx0.init() - ctx0.update(shsec) + ctx0.update(shsec.data) ctx0.update(mac1.data) mac1 = ctx0.finish() # mac-secret = keccak(ecdhe-secret || aes-secret) ctx0.init() - ctx0.update(shsec) + ctx0.update(shsec.data) ctx0.update(mac1.data) secret.aesKey = mac1.data mac1 = ctx0.finish() diff --git a/ethp2p/ecc.nim b/ethp2p/ecc.nim deleted file mode 100644 index 98b02e8..0000000 --- a/ethp2p/ecc.nim +++ /dev/null @@ -1,323 +0,0 @@ -# -# Ethereum P2P -# (c) Copyright 2018 -# Status Research & Development GmbH -# -# See the file "LICENSE", included in this -# distribution, for details about the copyright. -# - -## This module implements `libsecp256k1` ECC/ECDH functions - -import secp256k1, hexdump, nimcrypto/sysrand, nimcrypto/utils - -const - KeyLength* = 32 - PublicKeyLength* = 64 - SignatureLength* = 65 - -type - EccContext* = ref object of RootRef - context*: ptr secp256k1_context - error*: string - - EccStatus* = enum - Success, ## Operation was successful - Error ## Operation failed - - PublicKey* = secp256k1_pubkey - ## Representation of public key - - PrivateKey* = array[KeyLength, byte] - ## Representation of secret key - - SharedSecret* = array[KeyLength, byte] - ## Representation of ECDH shared secret - - Nonce* = array[KeyLength, byte] - ## Representation of nonce - - RawPublickey* = object - ## Representation of serialized public key - header*: byte - data*: array[KeyLength * 2, byte] - - KeyPair* = object - ## Representation of private/public keys pair - seckey*: PrivateKey - pubkey*: PublicKey - - Signature* = secp256k1_ecdsa_recoverable_signature - ## Representation of signature - - RawSignature* = object - ## Representation of serialized signature - data*: array[KeyLength * 2 + 1, byte] - - Secp256k1Exception* = object of Exception - ## Exceptions generated by `libsecp256k1` - EccException* = object of Exception - ## Exception generated by this module - -var eccContext* {.threadvar.}: EccContext - ## Thread local variable which holds current context - -proc illegalCallback(message: cstring; data: pointer) {.cdecl.} = - let ctx = cast[EccContext](data) - ctx.error = $message - -proc errorCallback(message: cstring, data: pointer) {.cdecl.} = - let ctx = cast[EccContext](data) - ctx.error = $message - -proc newEccContext*(): EccContext = - ## Create new `EccContext`. - result = new EccContext - let flags = cuint(SECP256K1_CONTEXT_VERIFY or SECP256K1_CONTEXT_SIGN) - result.context = secp256k1_context_create(flags) - secp256k1_context_set_illegal_callback(result.context, illegalCallback, - cast[pointer](result)) - secp256k1_context_set_error_callback(result.context, errorCallback, - cast[pointer](result)) - result.error = "" - -proc getSecpContext*(): ptr secp256k1_context = - ## Get current `secp256k1_context` - if isNil(eccContext): - eccContext = newEccContext() - result = eccContext.context - -proc getEccContext*(): EccContext = - ## Get current `EccContext` - if isNil(eccContext): - eccContext = newEccContext() - result = eccContext - -template raiseSecp256k1Error*() = - ## Raises `libsecp256k1` error as exception - let mctx = getEccContext() - if len(mctx.error) > 0: - var msg = mctx.error - mctx.error.setLen(0) - raise newException(Secp256k1Exception, msg) - -proc eccErrorMsg*(): string = - let mctx = getEccContext() - result = mctx.error - -proc setErrorMsg*(m: string) = - let mctx = getEccContext() - mctx.error = m - -proc getRaw*(pubkey: PublicKey): RawPublickey = - ## Converts public key `pubkey` to serialized form of `secp256k1_pubkey`. - var length = csize(sizeof(RawPublickey)) - let ctx = getSecpContext() - if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr result), - addr length, unsafeAddr pubkey, - SECP256K1_EC_UNCOMPRESSED) != 1: - raiseSecp256k1Error() - if length != 65: - raise newException(EccException, "Invalid public key length!") - if result.header != 0x04'u8: - raise newException(EccException, "Invalid public key header!") - -proc getRaw*(s: Signature): RawSignature = - ## Converts signature `s` to serialized form. - let ctx = getSecpContext() - var recid = cint(0) - if secp256k1_ecdsa_recoverable_signature_serialize_compact( - ctx, cast[ptr cuchar](unsafeAddr result), addr recid, unsafeAddr s) != 1: - raiseSecp256k1Error() - result.data[64] = uint8(recid) - -proc signMessage*(seckey: PrivateKey, data: ptr byte, length: int, - sig: var Signature): EccStatus = - ## Sign message pointed by `data` with size `length` and save signature to - ## `sig`. - let ctx = getSecpContext() - if secp256k1_ecdsa_sign_recoverable(ctx, addr sig, - cast[ptr cuchar](data), - cast[ptr cuchar](unsafeAddr seckey[0]), - nil, nil) != 1: - return(Error) - return(Success) - -proc signMessage*[T](seckey: PrivateKey, data: openarray[T], - sig: var Signature, ostart: int = 0, - ofinish: int = -1): EccStatus = - ## Sign message ``data``[`soffset`..`eoffset`] and store result into `sig`. - let so = ostart - let eo = if ofinish == -1: (len(data) - 1) else: ofinish - let length = (eo - so + 1) * sizeof(T) - # We don't need to check `so` because compiler will do it for `data[so]`. - if eo >= len(data): - setErrorMsg("Index is out of bounds!") - return(Error) - if len(data) < KeyLength or length < KeyLength: - setErrorMsg("There no reason to sign this message!") - return(Error) - result = signMessage(seckey, cast[ptr byte](unsafeAddr data[so]), - length, sig) - -proc recoverSignatureKey*(data: ptr byte, length: int, message: ptr byte, - pubkey: var PublicKey): EccStatus = - ## Check signature and return public key from `data` with size `length` and - ## `message`. - let ctx = getSecpContext() - var s: secp256k1_ecdsa_recoverable_signature - if length >= 65: - var recid = cint(cast[ptr UncheckedArray[byte]](data)[KeyLength * 2]) - if secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, addr s, - cast[ptr cuchar](data), - recid) != 1: - return(Error) - - if secp256k1_ecdsa_recover(ctx, addr pubkey, addr s, - cast[ptr cuchar](message)) != 1: - setErrorMsg("Message signature verification failed!") - return(Error) - return(Success) - else: - setErrorMsg("Incorrect signature size") - return(Error) - -proc recoverSignatureKey*[A, B](data: openarray[A], - message: openarray[B], - pubkey: var PublicKey, - ostart: int = 0, - ofinish: int = -1): EccStatus = - ## Check signature in ``data``[`soffset`..`eoffset`] and recover public key - ## from signature to ``pubkey`` using message `message`. - if len(message) == 0: - setErrorMsg("Message could not be empty!") - return(Error) - let so = ostart - let eo = if ofinish == -1: (len(data) - 1) else: ofinish - let length = (eo - so + 1) * sizeof(A) - # We don't need to check `so` because compiler will do it for `data[so]`. - if eo > len(data): - setErrorMsg("Index is out of bounds!") - return(Error) - if length < sizeof(RawSignature) or len(data) < sizeof(RawSignature): - setErrorMsg("Invalid signature size!") - return(Error) - result = recoverSignatureKey(cast[ptr byte](unsafeAddr data[so]), length, - cast[ptr byte](unsafeAddr message[0]), pubkey) - -proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey, - secret: var SharedSecret): EccStatus = - ## Calculate ECDH shared secret - var res: array[KeyLength + 1, byte] - let ctx = getSecpContext() - if secp256k1_ecdh_raw(ctx, cast[ptr cuchar](addr res), - unsafeAddr pubkey, - cast[ptr cuchar](unsafeAddr seckey)) != 1: - return(Error) - copyMem(addr secret[0], addr res[1], KeyLength) - return(Success) - -proc getPublicKey*(seckey: PrivateKey): PublicKey = - ## Return public key for private key `seckey`. - let ctx = getSecpContext() - if secp256k1_ec_pubkey_create(ctx, addr result, - cast[ptr cuchar](unsafeAddr seckey[0])) != 1: - raiseSecp256k1Error() - - -proc recoverPublicKey*(data: ptr byte, length: int, - pubkey: var PublicKey): EccStatus = - ## Unserialize public key from `data` pointer and size `length` and' - ## set `pubkey`. - let ctx = getSecpContext() - if length < sizeof(PublicKey): - setErrorMsg("Invalid public key!") - return(Error) - var rawkey: RawPublickey - rawkey.header = 0x04 # mark key with COMPRESSED flag - copyMem(addr rawkey.data[0], data, len(rawkey.data)) - if secp256k1_ec_pubkey_parse(ctx, addr pubkey, - cast[ptr cuchar](addr rawkey), - sizeof(RawPublickey)) != 1: - return(Error) - return(Success) - -proc recoverPublicKey*[T](data: openarray[T], pubkey: var PublicKey, - ostart: int = 0, ofinish: int = -1, ): EccStatus = - ## Unserialize public key from openarray[T] `data`, from position `ostart` to - ## position `ofinish` and save it to `pubkey`. - let so = ostart - let eo = if ofinish == -1: (len(data) - 1) else: ofinish - let length = (eo - so + 1) * sizeof(T) - # We don't need to check `so` because compiler will do it for `data[so]`. - if eo > len(data): - setErrorMsg("Index is out of bounds!") - return(Error) - if length < sizeof(PublicKey) or len(data) < sizeof(PublicKey): - setErrorMsg("Invalid public key size!") - return(Error) - result = recoverPublicKey(cast[ptr byte](unsafeAddr data[so]), length, - pubkey) - -proc newPrivateKey*(): PrivateKey = - ## Generates new secret key. - let ctx = getSecpContext() - while true: - if randomBytes(result) == KeyLength: - if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) == 1: - break - -proc newKeyPair*(): KeyPair = - ## Generates new private and public key. - result.seckey = newPrivateKey() - result.pubkey = result.seckey.getPublicKey() - -proc getPrivateKey*(hexstr: string): PrivateKey = - ## Set secret key from hexadecimal string representation. - let ctx = getSecpContext() - var o = fromHex(stripSpaces(hexstr)) - if len(o) < KeyLength: - raise newException(EccException, "Invalid private key!") - copyMem(addr result[0], unsafeAddr o[0], KeyLength) - if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) != 1: - raise newException(EccException, "Invalid private key!") - -proc getPublicKey*(hexstr: string): PublicKey = - ## Set public key from hexadecimal string representation. - var o = fromHex(stripSpaces(hexstr)) - if recoverPublicKey(o, result) != Success: - raise newException(EccException, "Invalid public key!") - -proc dump*(s: openarray[byte], c: string = ""): string = - ## Return hexadecimal dump of array `s`. - result = if len(c) > 0: c & "=>\n" else: "" - if len(s) > 0: - result &= dumpHex(unsafeAddr s[0], len(s)) - else: - result &= "[]" - -proc dump*(s: PublicKey, c: string = ""): string = - ## Return hexadecimal dump of public key `s`. - result = if len(c) > 0: c & "=>\n" else: "" - result &= dumpHex(unsafeAddr s.data[0], sizeof(secp256k1_pubkey)) - -proc dump*(s: RawSignature, c: string = ""): string = - ## Return hexadecimal dump of serialized signature `s`. - result = if len(c) > 0: c & "=>\n" else: "" - result &= dumpHex(unsafeAddr s.data[0], sizeof(RawSignature)) - -proc dump*(s: RawPublickey, c: string = ""): string = - ## Return hexadecimal dump of serialized public key `s`. - result = if len(c) > 0: c & "=>\n" else: "" - result &= dumpHex(unsafeAddr s, sizeof(RawSignature)) - -proc dump*(s: secp256k1_ecdsa_recoverable_signature, c: string = ""): string = - ## Return hexadecimal dump of signature `s`. - result = if len(c) > 0: c & "=>\n" else: "" - result &= dumpHex(unsafeAddr s.data[0], - sizeof(secp256k1_ecdsa_recoverable_signature)) - -proc dump*(p: pointer, s: int, c: string = ""): string = - ## Return hexadecimal dump of memory blob `p` and size `s`. - result = if len(c) > 0: c & "=>\n" else: "" - result &= dumpHex(p, s) diff --git a/ethp2p/ecies.nim b/ethp2p/ecies.nim index ac86635..73456aa 100644 --- a/ethp2p/ecies.nim +++ b/ethp2p/ecies.nim @@ -9,7 +9,8 @@ ## This module implements ECIES method encryption/decryption. -import ecc, nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac +import eth_keys +import nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac import nimcrypto/rijndael, nimcrypto/utils, nimcrypto/sysrand import nimcrypto/bcmode, nimcrypto/utils @@ -30,7 +31,7 @@ type EciesHeader* = object {.packed.} version*: byte - pubkey*: array[PublicKeyLength, byte] + pubkey*: array[RawPublicKeySize, byte] iv*: array[aes128.sizeBlock, byte] data*: byte @@ -109,12 +110,11 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte], return(RandomError) var ephemeral = newKeyPair() - var epub = ephemeral.pubkey.getRaw() - if ecdhAgree(ephemeral.seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(ephemeral.seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) - material = kdf(secret) + material = kdf(secret.data) burnMem(secret) copyMem(addr encKey[0], addr material[0], aes128.sizeKey) @@ -123,7 +123,7 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte], var header = cast[ptr EciesHeader](addr output[0]) header.version = 0x04 - header.pubkey = epub.data + header.pubkey = ephemeral.pubkey.getRaw() header.iv = iv var so = eciesDataPos() @@ -176,12 +176,12 @@ proc eciesDecrypt*(input: openarray[byte], return(IncompleteError) if len(input) - eciesOverheadLength() > len(output): return(BufferOverrun) - if recoverPublicKey(header.pubkey, pubkey) != EccStatus.Success: + if recoverPublicKey(header.pubkey, pubkey) != EthKeysStatus.Success: return(IncorrectKey) - if ecdhAgree(seckey, pubkey, secret) != EccStatus.Success: + if ecdhAgree(seckey, pubkey, secret) != EthKeysStatus.Success: return(EcdhError) - var material = kdf(secret) + var material = kdf(secret.data) burnMem(secret) copyMem(addr encKey[0], addr material[0], aes128.sizeKey) var macKey = sha256.digest(material, ostart = KeyLength div 2) diff --git a/tests/testauth.nim b/tests/testauth.nim index 615b6f6..f97e9c2 100644 --- a/tests/testauth.nim +++ b/tests/testauth.nim @@ -8,7 +8,7 @@ # import unittest -import ethp2p/ecc, ethp2p/auth, nimcrypto/utils +import eth_keys, ethp2p/auth, nimcrypto/utils # This was generated by `print` actual auth message generated by # https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_auth.py @@ -216,18 +216,18 @@ suite "Ethereum P2P handshake test suite": proc newTestHandshake(flags: set[HandshakeFlag]): Handshake = result = newHandshake(flags) if Initiator in flags: - result.host.seckey = getPrivateKey(testValue("initiator_private_key")) + result.host.seckey = initPrivateKey(testValue("initiator_private_key")) result.host.pubkey = result.host.seckey.getPublicKey() let epki = testValue("initiator_ephemeral_private_key") - result.ephemeral.seckey = getPrivateKey(epki) + result.ephemeral.seckey = initPrivateKey(epki) result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey() let nonce = fromHex(stripSpaces(testValue("initiator_nonce"))) result.initiatorNonce[0..^1] = nonce[0..^1] elif Responder in flags: - result.host.seckey = getPrivateKey(testValue("receiver_private_key")) + result.host.seckey = initPrivateKey(testValue("receiver_private_key")) result.host.pubkey = result.host.seckey.getPublicKey() let epkr = testValue("receiver_ephemeral_private_key") - result.ephemeral.seckey = getPrivateKey(epkr) + result.ephemeral.seckey = initPrivateKey(epkr) result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey() let nonce = fromHex(stripSpaces(testValue("receiver_nonce"))) result.responderNonce[0..^1] = nonce[0..^1] @@ -326,18 +326,18 @@ suite "Ethereum P2P handshake test suite": proc newTestHandshake(flags: set[HandshakeFlag]): Handshake = result = newHandshake(flags) if Initiator in flags: - result.host.seckey = getPrivateKey(testE8Value("initiator_private_key")) + result.host.seckey = initPrivateKey(testE8Value("initiator_private_key")) result.host.pubkey = result.host.seckey.getPublicKey() let esec = testE8Value("initiator_ephemeral_private_key") - result.ephemeral.seckey = getPrivateKey(esec) + result.ephemeral.seckey = initPrivateKey(esec) result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey() let nonce = fromHex(stripSpaces(testE8Value("initiator_nonce"))) result.initiatorNonce[0..^1] = nonce[0..^1] elif Responder in flags: - result.host.seckey = getPrivateKey(testE8Value("receiver_private_key")) + result.host.seckey = initPrivateKey(testE8Value("receiver_private_key")) result.host.pubkey = result.host.seckey.getPublicKey() let esec = testE8Value("receiver_ephemeral_private_key") - result.ephemeral.seckey = getPrivateKey(esec) + result.ephemeral.seckey = initPrivateKey(esec) result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey() let nonce = fromHex(stripSpaces(testE8Value("receiver_nonce"))) result.responderNonce[0..^1] = nonce[0..^1] diff --git a/tests/testecc.nim b/tests/testecc.nim deleted file mode 100644 index aa85a7b..0000000 --- a/tests/testecc.nim +++ /dev/null @@ -1,139 +0,0 @@ -# -# Ethereum P2P -# (c) Copyright 2018 -# Status Research & Development GmbH -# -# See the file "LICENSE", included in this -# distribution, for details about the copyright. -# - -import unittest -import ethp2p/ecc -import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils - -proc compare(x: openarray[byte], y: openarray[byte]): bool = - result = len(x) == len(y) - if result: - for i in 0..(len(x) - 1): - if x[i] != y[i]: - result = false - break - -suite "ECC/ECDSA/ECDHE tests suite": - test "ECDHE/py-evm test_ecies.py#L19": - # ECDHE test vectors - # Copied from - # https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_ecies.py#L19 - const privateKeys = [ - "332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b", - "7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad" - ] - const publicKeys = [ - """f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a07 - f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1""", - """83ede0f19c3c98649265956a4193677b14c338a22de2086a08d84e4446fe37e4e - 233478259ec90dbeef52f4f6c890f8c38660ec7b61b9d439b8a6d1c323dc025""" - ] - const sharedSecrets = [ - "ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08", - "167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62" - ] - var secret: array[KeyLength, byte] - for i in 0..1: - var s = privateKeys[i].getPrivateKey() - var p = publicKeys[i].getPublicKey() - let expect = fromHex(stripSpaces(sharedSecrets[i])) - check: - ecdhAgree(s, p, secret) == Success - compare(expect, secret) == true - - test "ECDHE/cpp-ethereum crypto.cpp#L394": - # ECDHE test vectors - # Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L394 - var expectm = """ - 8ac7e464348b85d9fdfc0a81f2fdc0bbbb8ee5fb3840de6ed60ad9372e718977""" - var secret: array[KeyLength, byte] - var s = keccak256.digest("ecdhAgree").data - var p = s.getPublicKey() - let expect = fromHex(stripSpaces(expectm)) - check: - ecdhAgree(s, p, secret) == Success - compare(expect, secret) == true - - test "ECDHE/cpp-ethereum rlpx.cpp#L425": - # ECDHE test vectors - # Copied from https://github.com/ethereum/cpp-ethereum/blob/2409d7ec7d34d5ff5770463b87eb87f758e621fe/test/unittests/libp2p/rlpx.cpp#L425 - var s0 = """ - 332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b""" - var p0 = """ - f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a0 - 7f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1""" - var e0 = """ - ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08""" - var secret: array[KeyLength, byte] - var s = getPrivateKey(s0) - var p = getPublicKey(p0) - let expect = fromHex(stripSpaces(e0)) - check: - ecdhAgree(s, p, secret) == Success - compare(expect, secret) == true - - test "ECDSA/cpp-ethereum crypto.cpp#L132": - # ECDSA test vectors - # Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L132 - var signature = """ - b826808a8c41e00b7c5d71f211f005a84a7b97949d5e765831e1da4e34c9b8295d - 2a622eee50f25af78241c1cb7cfff11bcf2a13fe65dee1e3b86fd79a4e3ed000""" - var pubkey = """ - e40930c838d6cca526795596e368d16083f0672f4ab61788277abfa23c3740e1cc - 84453b0b24f49086feba0bd978bb4446bae8dff1e79fcc1e9cf482ec2d07c3""" - var check1 = fromHex(stripSpaces(signature)) - var check2 = fromHex(stripSpaces(pubkey)) - var sig: Signature - var key: PublicKey - var s = keccak256.digest("sec").data - var m = keccak256.digest("msg").data - check signMessage(s, m, sig) == Success - var sersig = sig.getRaw().data - check recoverSignatureKey(sersig, m, key) == Success - var serkey = key.getRaw().data - check: - compare(sersig, check1) == true - compare(serkey, check2) == true - - test "ECDSA/100 signatures": - # signature test - var rkey: PublicKey - var sig: Signature - for i in 1..100: - var m = newPrivateKey() - var s = newPrivateKey() - var key = s.getPublicKey() - check signMessage(s, m, sig) == Success - var sersig = sig.getRaw().data - check: - recoverSignatureKey(sersig, m, rkey) == Success - key == rkey - - test "KEYS/100 create/recovery keys": - # key create/recovery test - var rkey: PublicKey - for i in 1..100: - var s = newPrivateKey() - var key = s.getPublicKey() - check: - recoverPublicKey(key.getRaw().data, rkey) == Success - key == rkey - - test "ECDHE/100 shared secrets": - # ECDHE shared secret test - var secret1, secret2: SharedSecret - for i in 1..100: - var aliceSecret = newPrivateKey() - var alicePublic = aliceSecret.getPublicKey() - var bobSecret = newPrivateKey() - var bobPublic = bobSecret.getPublicKey() - check: - ecdhAgree(aliceSecret, bobPublic, secret1) == Success - ecdhAgree(bobSecret, alicePublic, secret2) == Success - secret1 == secret2 diff --git a/tests/testecies.nim b/tests/testecies.nim index 291d078..dc24151 100644 --- a/tests/testecies.nim +++ b/tests/testecies.nim @@ -8,7 +8,7 @@ # import unittest -import ethp2p/ecc, ethp2p/ecies +import eth_keys, ethp2p/ecies import nimcrypto/utils, nimcrypto/sha2, nimcrypto/hmac, nimcrypto/rijndael proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool = @@ -123,7 +123,7 @@ suite "ECIES test suite": ] var data: array[1024, byte] for i in 0..1: - var s = secretKeys[i].getPrivateKey() + var s = initPrivateKey(secretKeys[i]) var cipher = fromHex(stripSpaces(cipherText[i])) var expect = fromHex(stripSpaces(expectText[i])) check: @@ -164,7 +164,7 @@ suite "ECIES test suite": ] var data: array[1024, byte] for i in 0..3: - var s = secretKeys[i].getPrivateKey() + var s = initPrivateKey(secretKeys[i]) var cipher = fromHex(stripSpaces(cipherData[i])) check: eciesDecrypt(cipher, data, s) == EciesStatus.Success