diff --git a/ethp2p/auth.nim b/ethp2p/auth.nim index be32f3e..6116aea 100644 --- a/ethp2p/auth.nim +++ b/ethp2p/auth.nim @@ -26,6 +26,18 @@ const AuthAckMessageLength* = 210 type + PlainAuthMessage* = object {.packed.} + signature: RawSignature + keyhash: array[keccak256.sizeDigest, byte] + pubkey: PublicKey + nonce: array[keccak256.sizeDigest, byte] + flag: byte + + PlainAuthAckMessage* = object {.packed.} + pubkey: PublicKey + nonce: array[keccak256.sizeDigest, byte] + flag: byte + HandshakeFlag* = enum Initiator, ## `Handshake` owner is connection initiator Responder, ## `Handshake` owner is connection responder @@ -62,8 +74,8 @@ type egressMac*: array[keccak256.sizeDigest, byte] ingressMac*: array[keccak256.sizeDigest, byte] - PlainAuthMessage* = array[PlainAuthMessageLength, byte] - PlainAuthAckMessage* = array[PlainAuthAckMessageLength, byte] + # PlainAuthMessage* = array[PlainAuthMessageLength, byte] + # PlainAuthAckMessage* = array[PlainAuthAckMessageLength, byte] AuthMessage* = array[AuthMessageLength, byte] AuthAckMessage* = array[AuthAckMessageLength, byte] @@ -95,50 +107,44 @@ proc newHandshake*(flags: set[HandshakeFlag] = {Initiator}): Handshake = result.ephemeral = newKeyPair() if Initiator in flags: - p = addr result.initiatorNonce[0] + if randomBytes(result.initiatorNonce) != len(result.initiatorNonce): + raise newException(AuthException, "Could not obtain random data!") else: - p = addr result.responderNonce[0] + if randomBytes(result.responderNonce) != len(result.responderNonce): + raise newException(AuthException, "Could not obtain random data!") - if randomBytes(p, KeyLength) != KeyLength: - raise newException(AuthException, "Could not obtain random data!") - -proc authMessage*(h: var Handshake, +proc authMessagePreEIP8*(h: var Handshake, pubkey: PublicKey, - output: var PlainAuthMessage): AuthStatus = + output: var PlainAuthMessage, + flag: int = 0): AuthStatus = ## Create plain preEIP8 authentication message. var secret: SharedSecret var signature: Signature - var flag = byte(0x00) + var flagb = byte(flag) if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success: return(EcdhError) - if h.initiatorNonce.empty(): - if randomBytes(addr h.initiatorNonce[0], KeyLength) != KeyLength: - return(RandomError) - var xornonce = h.initiatorNonce xornonce.sxor(secret) if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success: return(SignatureError) - copyMem(addr h.remoteHPubkey, unsafeAddr pubkey, sizeof(PublicKey)) + h.remoteHPubkey = pubkey + + output.signature = signature.getRaw() + output.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw().data).data + output.pubkey = cast[PublicKey](h.host.pubkey.getRaw().data) + output.nonce = h.initiatorNonce + output.flag = flagb - move(output, signature.getRaw().data, 0, 64) - move(output, keccak256.digest(h.ephemeral.pubkey.getRaw().data).data, 65, 96) - move(output, h.host.pubkey.getRaw().data, 97, 160) - move(output, h.initiatorNonce, 161, 192) - output[193] = flag - -proc authAckMessage*(h: var Handshake, - output: var PlainAuthAckMessage): AuthStatus = - if EIP8 in h.flags: - discard - else: - move(output, h.ephemeral.pubkey.getRaw().data, 0, 63) - move(output, h.responderNonce, 64, 95) - output[96] = byte(0x00) +proc authAckMessagePreEIP8*(h: var Handshake, + output: var PlainAuthAckMessage, + flag: int = 0): AuthStatus = + output.pubkey = cast[PublicKey](h.ephemeral.pubkey.getRaw().data) + output.nonce = h.responderNonce + output.flag = byte(flag) proc encryptAuthMessage*(input: ptr byte, inputlen: int, output: ptr byte, outputlen: int, diff --git a/ethp2p/ecc.nim b/ethp2p/ecc.nim index 3ed7a12..98b02e8 100644 --- a/ethp2p/ecc.nim +++ b/ethp2p/ecc.nim @@ -16,7 +16,6 @@ const PublicKeyLength* = 64 SignatureLength* = 65 - type EccContext* = ref object of RootRef context*: ptr secp256k1_context @@ -264,7 +263,7 @@ proc newPrivateKey*(): PrivateKey = ## Generates new secret key. let ctx = getSecpContext() while true: - if randomBytes(addr result[0], KeyLength) == KeyLength: + if randomBytes(result) == KeyLength: if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) == 1: break diff --git a/ethp2p/ecies.nim b/ethp2p/ecies.nim index 3f49f54..ac86635 100644 --- a/ethp2p/ecies.nim +++ b/ethp2p/ecies.nim @@ -166,7 +166,7 @@ proc eciesDecrypt*(input: openarray[byte], ctx: HMAC[sha256] secret: SharedSecret - if len(input) == 0: + if len(input) <= 0: return(IncompleteError) var header = cast[ptr EciesHeader](unsafeAddr input[0]) @@ -188,7 +188,6 @@ proc eciesDecrypt*(input: openarray[byte], burnMem(material) let macsize = eciesMacLength(len(input) - eciesOverheadLength()) - let datsize = eciesDecryptedLength(len(input)) ctx.init(macKey.data) burnMem(macKey) ctx.update(toOpenArray(input, eciesIvPos(), eciesIvPos() + macsize - 1)) @@ -201,6 +200,7 @@ proc eciesDecrypt*(input: openarray[byte], sha256.sizeDigest): return(IncorrectTag) + let datsize = eciesDecryptedLength(len(input)) cipher.init(encKey, header.iv) burnMem(encKey) cipher.decrypt(toOpenArray(input, eciesDataPos(), diff --git a/tests/testecies.nim b/tests/testecies.nim index f14bdc9..291d078 100644 --- a/tests/testecies.nim +++ b/tests/testecies.nim @@ -9,7 +9,7 @@ import unittest import ethp2p/ecc, ethp2p/ecies -import nimcrypto/utils, nimcrypto/sha2, nimcrypto/hmac +import nimcrypto/utils, nimcrypto/sha2, nimcrypto/hmac, nimcrypto/rijndael proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool = result = true @@ -20,7 +20,19 @@ proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool = result = false break +template offsetOf(a, b): int = + cast[int](cast[uint](unsafeAddr b) - cast[uint](unsafeAddr a)) + suite "ECIES test suite": + test "ECIES structures alignment": + var header: EciesHeader + check: + offsetOf(header, header.version) == 0 + offsetOf(header, header.pubkey) == 1 + offsetOf(header, header.iv) == 1 + 64 + offsetOf(header, header.data) == 1 + 64 + aes128.sizeBlock + sizeof(header) == 1 + 64 + aes128.sizeBlock + 1 + test "KDF test vectors": # KDF test # Copied from https://github.com/ethereum/pydevp2p/blob/develop/devp2p/tests/test_ecies.py#L53