mirror of
https://github.com/status-im/nim-eth-p2p.git
synced 2025-02-18 01:36:32 +00:00
Some fixes and tests for ECIES.
This commit is contained in:
parent
f020ff4712
commit
d8c63e7da1
@ -26,6 +26,18 @@ const
|
|||||||
AuthAckMessageLength* = 210
|
AuthAckMessageLength* = 210
|
||||||
|
|
||||||
type
|
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
|
HandshakeFlag* = enum
|
||||||
Initiator, ## `Handshake` owner is connection initiator
|
Initiator, ## `Handshake` owner is connection initiator
|
||||||
Responder, ## `Handshake` owner is connection responder
|
Responder, ## `Handshake` owner is connection responder
|
||||||
@ -62,8 +74,8 @@ type
|
|||||||
egressMac*: array[keccak256.sizeDigest, byte]
|
egressMac*: array[keccak256.sizeDigest, byte]
|
||||||
ingressMac*: array[keccak256.sizeDigest, byte]
|
ingressMac*: array[keccak256.sizeDigest, byte]
|
||||||
|
|
||||||
PlainAuthMessage* = array[PlainAuthMessageLength, byte]
|
# PlainAuthMessage* = array[PlainAuthMessageLength, byte]
|
||||||
PlainAuthAckMessage* = array[PlainAuthAckMessageLength, byte]
|
# PlainAuthAckMessage* = array[PlainAuthAckMessageLength, byte]
|
||||||
AuthMessage* = array[AuthMessageLength, byte]
|
AuthMessage* = array[AuthMessageLength, byte]
|
||||||
AuthAckMessage* = array[AuthAckMessageLength, byte]
|
AuthAckMessage* = array[AuthAckMessageLength, byte]
|
||||||
|
|
||||||
@ -95,50 +107,44 @@ proc newHandshake*(flags: set[HandshakeFlag] = {Initiator}): Handshake =
|
|||||||
result.ephemeral = newKeyPair()
|
result.ephemeral = newKeyPair()
|
||||||
|
|
||||||
if Initiator in flags:
|
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:
|
else:
|
||||||
p = addr result.responderNonce[0]
|
if randomBytes(result.responderNonce) != len(result.responderNonce):
|
||||||
|
|
||||||
if randomBytes(p, KeyLength) != KeyLength:
|
|
||||||
raise newException(AuthException, "Could not obtain random data!")
|
raise newException(AuthException, "Could not obtain random data!")
|
||||||
|
|
||||||
proc authMessage*(h: var Handshake,
|
proc authMessagePreEIP8*(h: var Handshake,
|
||||||
pubkey: PublicKey,
|
pubkey: PublicKey,
|
||||||
output: var PlainAuthMessage): AuthStatus =
|
output: var PlainAuthMessage,
|
||||||
|
flag: int = 0): AuthStatus =
|
||||||
## Create plain preEIP8 authentication message.
|
## Create plain preEIP8 authentication message.
|
||||||
var secret: SharedSecret
|
var secret: SharedSecret
|
||||||
var signature: Signature
|
var signature: Signature
|
||||||
var flag = byte(0x00)
|
var flagb = byte(flag)
|
||||||
|
|
||||||
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
|
|
||||||
if h.initiatorNonce.empty():
|
|
||||||
if randomBytes(addr h.initiatorNonce[0], KeyLength) != KeyLength:
|
|
||||||
return(RandomError)
|
|
||||||
|
|
||||||
var xornonce = h.initiatorNonce
|
var xornonce = h.initiatorNonce
|
||||||
xornonce.sxor(secret)
|
xornonce.sxor(secret)
|
||||||
|
|
||||||
if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success:
|
if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success:
|
||||||
return(SignatureError)
|
return(SignatureError)
|
||||||
|
|
||||||
copyMem(addr h.remoteHPubkey, unsafeAddr pubkey, sizeof(PublicKey))
|
h.remoteHPubkey = pubkey
|
||||||
|
|
||||||
move(output, signature.getRaw().data, 0, 64)
|
output.signature = signature.getRaw()
|
||||||
move(output, keccak256.digest(h.ephemeral.pubkey.getRaw().data).data, 65, 96)
|
output.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw().data).data
|
||||||
move(output, h.host.pubkey.getRaw().data, 97, 160)
|
output.pubkey = cast[PublicKey](h.host.pubkey.getRaw().data)
|
||||||
move(output, h.initiatorNonce, 161, 192)
|
output.nonce = h.initiatorNonce
|
||||||
output[193] = flag
|
output.flag = flagb
|
||||||
|
|
||||||
proc authAckMessage*(h: var Handshake,
|
proc authAckMessagePreEIP8*(h: var Handshake,
|
||||||
output: var PlainAuthAckMessage): AuthStatus =
|
output: var PlainAuthAckMessage,
|
||||||
if EIP8 in h.flags:
|
flag: int = 0): AuthStatus =
|
||||||
discard
|
output.pubkey = cast[PublicKey](h.ephemeral.pubkey.getRaw().data)
|
||||||
else:
|
output.nonce = h.responderNonce
|
||||||
move(output, h.ephemeral.pubkey.getRaw().data, 0, 63)
|
output.flag = byte(flag)
|
||||||
move(output, h.responderNonce, 64, 95)
|
|
||||||
output[96] = byte(0x00)
|
|
||||||
|
|
||||||
proc encryptAuthMessage*(input: ptr byte, inputlen: int,
|
proc encryptAuthMessage*(input: ptr byte, inputlen: int,
|
||||||
output: ptr byte, outputlen: int,
|
output: ptr byte, outputlen: int,
|
||||||
|
@ -16,7 +16,6 @@ const
|
|||||||
PublicKeyLength* = 64
|
PublicKeyLength* = 64
|
||||||
SignatureLength* = 65
|
SignatureLength* = 65
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
EccContext* = ref object of RootRef
|
EccContext* = ref object of RootRef
|
||||||
context*: ptr secp256k1_context
|
context*: ptr secp256k1_context
|
||||||
@ -264,7 +263,7 @@ proc newPrivateKey*(): PrivateKey =
|
|||||||
## Generates new secret key.
|
## Generates new secret key.
|
||||||
let ctx = getSecpContext()
|
let ctx = getSecpContext()
|
||||||
while true:
|
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:
|
if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) == 1:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ proc eciesDecrypt*(input: openarray[byte],
|
|||||||
ctx: HMAC[sha256]
|
ctx: HMAC[sha256]
|
||||||
secret: SharedSecret
|
secret: SharedSecret
|
||||||
|
|
||||||
if len(input) == 0:
|
if len(input) <= 0:
|
||||||
return(IncompleteError)
|
return(IncompleteError)
|
||||||
|
|
||||||
var header = cast[ptr EciesHeader](unsafeAddr input[0])
|
var header = cast[ptr EciesHeader](unsafeAddr input[0])
|
||||||
@ -188,7 +188,6 @@ proc eciesDecrypt*(input: openarray[byte],
|
|||||||
burnMem(material)
|
burnMem(material)
|
||||||
|
|
||||||
let macsize = eciesMacLength(len(input) - eciesOverheadLength())
|
let macsize = eciesMacLength(len(input) - eciesOverheadLength())
|
||||||
let datsize = eciesDecryptedLength(len(input))
|
|
||||||
ctx.init(macKey.data)
|
ctx.init(macKey.data)
|
||||||
burnMem(macKey)
|
burnMem(macKey)
|
||||||
ctx.update(toOpenArray(input, eciesIvPos(), eciesIvPos() + macsize - 1))
|
ctx.update(toOpenArray(input, eciesIvPos(), eciesIvPos() + macsize - 1))
|
||||||
@ -201,6 +200,7 @@ proc eciesDecrypt*(input: openarray[byte],
|
|||||||
sha256.sizeDigest):
|
sha256.sizeDigest):
|
||||||
return(IncorrectTag)
|
return(IncorrectTag)
|
||||||
|
|
||||||
|
let datsize = eciesDecryptedLength(len(input))
|
||||||
cipher.init(encKey, header.iv)
|
cipher.init(encKey, header.iv)
|
||||||
burnMem(encKey)
|
burnMem(encKey)
|
||||||
cipher.decrypt(toOpenArray(input, eciesDataPos(),
|
cipher.decrypt(toOpenArray(input, eciesDataPos(),
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import ethp2p/ecc, ethp2p/ecies
|
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 =
|
proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool =
|
||||||
result = true
|
result = true
|
||||||
@ -20,7 +20,19 @@ proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool =
|
|||||||
result = false
|
result = false
|
||||||
break
|
break
|
||||||
|
|
||||||
|
template offsetOf(a, b): int =
|
||||||
|
cast[int](cast[uint](unsafeAddr b) - cast[uint](unsafeAddr a))
|
||||||
|
|
||||||
suite "ECIES test suite":
|
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":
|
test "KDF test vectors":
|
||||||
# KDF test
|
# KDF test
|
||||||
# Copied from https://github.com/ethereum/pydevp2p/blob/develop/devp2p/tests/test_ecies.py#L53
|
# Copied from https://github.com/ethereum/pydevp2p/blob/develop/devp2p/tests/test_ecies.py#L53
|
||||||
|
Loading…
x
Reference in New Issue
Block a user