Some fixes and tests for ECIES.

This commit is contained in:
cheatfate 2018-03-30 18:42:23 +03:00
parent f020ff4712
commit d8c63e7da1
4 changed files with 51 additions and 34 deletions

View File

@ -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,

View File

@ -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

View File

@ -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(),

View File

@ -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