mirror of https://github.com/status-im/nim-eth.git
remove ecdhRaw usage and replace it with ecdh+custom hash function
This commit is contained in:
parent
6053c252e7
commit
9bf2e1786b
39
eth/keys.nim
39
eth/keys.nim
|
@ -17,7 +17,7 @@
|
||||||
import
|
import
|
||||||
std/strformat,
|
std/strformat,
|
||||||
secp256k1, bearssl/hash as bhash, bearssl/rand,
|
secp256k1, bearssl/hash as bhash, bearssl/rand,
|
||||||
stew/[byteutils, objects, results],
|
stew/[byteutils, objects, results, ptrops],
|
||||||
./common/eth_hash
|
./common/eth_hash
|
||||||
|
|
||||||
from nimcrypto/utils import burnMem
|
from nimcrypto/utils import burnMem
|
||||||
|
@ -25,7 +25,9 @@ from nimcrypto/utils import burnMem
|
||||||
export secp256k1, results, rand
|
export secp256k1, results, rand
|
||||||
|
|
||||||
const
|
const
|
||||||
KeyLength* = SkEcdhRawSecretSize - 1
|
FullKeyLength* = 33
|
||||||
|
|
||||||
|
KeyLength* = FullKeyLength - 1
|
||||||
## Shared secret key length without format marker
|
## Shared secret key length without format marker
|
||||||
RawPublicKeySize* = SkRawPublicKeySize - 1
|
RawPublicKeySize* = SkRawPublicKeySize - 1
|
||||||
## Size of uncompressed public key without format marker (0x04)
|
## Size of uncompressed public key without format marker (0x04)
|
||||||
|
@ -43,7 +45,9 @@ type
|
||||||
SignatureNR* = distinct SkSignature
|
SignatureNR* = distinct SkSignature
|
||||||
## ...but ENR uses non-recoverable signatures!
|
## ...but ENR uses non-recoverable signatures!
|
||||||
|
|
||||||
SharedSecretFull* = SkEcdhRawSecret
|
SharedSecretFull* = object
|
||||||
|
data*: array[FullKeyLength, byte]
|
||||||
|
|
||||||
SharedSecret* = object
|
SharedSecret* = object
|
||||||
data*: array[KeyLength, byte]
|
data*: array[KeyLength, byte]
|
||||||
|
|
||||||
|
@ -230,11 +234,28 @@ func verify*(sig: SignatureNR, msg: openArray[byte], key: PublicKey): bool =
|
||||||
let hash = keccakHash(msg)
|
let hash = keccakHash(msg)
|
||||||
verify(sig, SkMessage(hash.data), key)
|
verify(sig, SkMessage(hash.data), key)
|
||||||
|
|
||||||
func ecdhRaw*(seckey: PrivateKey, pubkey: PublicKey): SharedSecret =
|
proc ecdhSecretHash(output: ptr byte, x32, y32: ptr byte, data: pointer): cint
|
||||||
let tmp = ecdhRaw(SkSecretKey(seckey), SkPublicKey(pubkey))
|
{.cdecl, raises: [].} =
|
||||||
|
copyMem(output, x32, 32)
|
||||||
|
return 1
|
||||||
|
|
||||||
# Remove first byte!
|
func ecdhSecret*(seckey: PrivateKey, pubkey: PublicKey): SharedSecret =
|
||||||
copyMem(addr result.data[0], unsafeAddr(tmp.data[1]), sizeof(result))
|
# This function only fail if the hash function return zero.
|
||||||
|
# Because our hash function always success, we can turn the error into defect
|
||||||
|
let res = ecdh[KeyLength](SkSecretKey(seckey), SkPublicKey(pubkey), ecdhSecretHash, nil)
|
||||||
|
doAssert res.isOk, $res.error
|
||||||
|
SharedSecret(data: res.get)
|
||||||
|
|
||||||
func ecdhRawFull*(seckey: PrivateKey, pubkey: PublicKey): SharedSecretFull =
|
proc ecdhSecretFullHash(output: ptr byte, x32, y32: ptr byte, data: pointer): cint
|
||||||
SharedSecretFull(ecdhRaw(SkSecretKey(seckey), SkPublicKey(pubkey)))
|
{.cdecl, raises: [].} =
|
||||||
|
# output[0] = 0x02 | (y32[31] & 1)
|
||||||
|
output[] = 0x02 or (y32.offset(31)[] and 0x01)
|
||||||
|
copyMem(output.offset(1), x32, 32)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
func ecdhSecretFull*(seckey: PrivateKey, pubkey: PublicKey): SharedSecretFull =
|
||||||
|
# This function only fail if the hash function return zero.
|
||||||
|
# Because our hash function always success, we can turn the error into defect
|
||||||
|
let res = ecdh[FullKeyLength](SkSecretKey(seckey), SkPublicKey(pubkey), ecdhSecretFullHash, nil)
|
||||||
|
doAssert res.isOk, $res.error
|
||||||
|
SharedSecretFull(data: res.get)
|
||||||
|
|
|
@ -150,7 +150,7 @@ proc authMessagePreEIP8(h: var Handshake,
|
||||||
outlen = 0
|
outlen = 0
|
||||||
let header = cast[ptr AuthMessageV4](addr buffer[0])
|
let header = cast[ptr AuthMessageV4](addr buffer[0])
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhSecret(h.host.seckey, pubkey)
|
||||||
secret.data = secret.data xor h.initiatorNonce
|
secret.data = secret.data xor h.initiatorNonce
|
||||||
|
|
||||||
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
||||||
|
@ -190,7 +190,7 @@ proc authMessageEIP8(h: var Handshake,
|
||||||
doAssert(EIP8 in h.flags)
|
doAssert(EIP8 in h.flags)
|
||||||
outlen = 0
|
outlen = 0
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhSecret(h.host.seckey, pubkey)
|
||||||
secret.data = secret.data xor h.initiatorNonce
|
secret.data = secret.data xor h.initiatorNonce
|
||||||
|
|
||||||
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
let signature = sign(h.ephemeral.seckey, SkMessage(secret.data))
|
||||||
|
@ -364,7 +364,7 @@ proc decodeAuthMessageV4(h: var Handshake, m: openArray[byte]): AuthResult[void]
|
||||||
pubkey = ? PublicKey.fromRaw(header.pubkey).mapErrTo(InvalidPubKey)
|
pubkey = ? PublicKey.fromRaw(header.pubkey).mapErrTo(InvalidPubKey)
|
||||||
signature = ? Signature.fromRaw(header.signature).mapErrTo(SignatureError)
|
signature = ? Signature.fromRaw(header.signature).mapErrTo(SignatureError)
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhSecret(h.host.seckey, pubkey)
|
||||||
secret.data = secret.data xor header.nonce
|
secret.data = secret.data xor header.nonce
|
||||||
|
|
||||||
var recovered = recover(signature, SkMessage(secret.data))
|
var recovered = recover(signature, SkMessage(secret.data))
|
||||||
|
@ -415,7 +415,7 @@ proc decodeAuthMessageEIP8(h: var Handshake, m: openArray[byte]): AuthResult[voi
|
||||||
pubkey = ? PublicKey.fromRaw(pubkeyBr).mapErrTo(InvalidPubKey)
|
pubkey = ? PublicKey.fromRaw(pubkeyBr).mapErrTo(InvalidPubKey)
|
||||||
nonce = toArray(KeyLength, nonceBr)
|
nonce = toArray(KeyLength, nonceBr)
|
||||||
|
|
||||||
var secret = ecdhRaw(h.host.seckey, pubkey)
|
var secret = ecdhSecret(h.host.seckey, pubkey)
|
||||||
secret.data = secret.data xor nonce
|
secret.data = secret.data xor nonce
|
||||||
|
|
||||||
let recovered = recover(signature, SkMessage(secret.data))
|
let recovered = recover(signature, SkMessage(secret.data))
|
||||||
|
@ -524,7 +524,7 @@ proc getSecrets*(
|
||||||
secret: ConnectionSecret
|
secret: ConnectionSecret
|
||||||
|
|
||||||
# ecdhe-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
|
# ecdhe-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
|
||||||
var shsec = ecdhRaw(h.ephemeral.seckey, h.remoteEPubkey)
|
var shsec = ecdhSecret(h.ephemeral.seckey, h.remoteEPubkey)
|
||||||
|
|
||||||
# shared-secret = keccak(ecdhe-secret || keccak(nonce || initiator-nonce))
|
# shared-secret = keccak(ecdhe-secret || keccak(nonce || initiator-nonce))
|
||||||
ctx0.init()
|
ctx0.init()
|
||||||
|
|
|
@ -138,7 +138,7 @@ proc verifyIdSignature*(sig: SignatureNR, challengeData, ephKey: openArray[byte]
|
||||||
|
|
||||||
proc deriveKeys*(n1, n2: NodeId, priv: PrivateKey, pub: PublicKey,
|
proc deriveKeys*(n1, n2: NodeId, priv: PrivateKey, pub: PublicKey,
|
||||||
challengeData: openArray[byte]): HandshakeSecrets =
|
challengeData: openArray[byte]): HandshakeSecrets =
|
||||||
let eph = ecdhRawFull(priv, pub)
|
let eph = ecdhSecretFull(priv, pub)
|
||||||
|
|
||||||
var info = newSeqOfCap[byte](keyAgreementPrefix.len + 32 * 2)
|
var info = newSeqOfCap[byte](keyAgreementPrefix.len + 32 * 2)
|
||||||
for i, c in keyAgreementPrefix: info.add(byte(c))
|
for i, c in keyAgreementPrefix: info.add(byte(c))
|
||||||
|
|
|
@ -114,7 +114,7 @@ proc eciesEncrypt*(rng: var HmacDrbgContext, input: openArray[byte],
|
||||||
|
|
||||||
var
|
var
|
||||||
ephemeral = KeyPair.random(rng)
|
ephemeral = KeyPair.random(rng)
|
||||||
secret = ecdhRaw(ephemeral.seckey, pubkey)
|
secret = ecdhSecret(ephemeral.seckey, pubkey)
|
||||||
material = kdf(secret.data)
|
material = kdf(secret.data)
|
||||||
|
|
||||||
clear(secret)
|
clear(secret)
|
||||||
|
@ -183,10 +183,10 @@ proc eciesDecrypt*(input: openArray[byte],
|
||||||
|
|
||||||
var
|
var
|
||||||
pubkey = ? PublicKey.fromRaw(header.pubkey).mapErrTo(IncorrectKey)
|
pubkey = ? PublicKey.fromRaw(header.pubkey).mapErrTo(IncorrectKey)
|
||||||
secret = ecdhRaw(seckey, pubkey)
|
secret = ecdhSecret(seckey, pubkey)
|
||||||
|
material = kdf(secret.data)
|
||||||
|
|
||||||
var material = kdf(secret.data)
|
clear(secret)
|
||||||
burnMem(secret)
|
|
||||||
|
|
||||||
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||||
var macKey =
|
var macKey =
|
||||||
|
|
|
@ -160,7 +160,7 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
var s = PrivateKey.fromHex(privateKeys[i])[]
|
var s = PrivateKey.fromHex(privateKeys[i])[]
|
||||||
var p = PublicKey.fromHex(stripSpaces(publicKeys[i]))[]
|
var p = PublicKey.fromHex(stripSpaces(publicKeys[i]))[]
|
||||||
let expect = fromHex(stripSpaces(sharedSecrets[i]))
|
let expect = fromHex(stripSpaces(sharedSecrets[i]))
|
||||||
let secret = ecdhRaw(s, p)
|
let secret = ecdhSecret(s, p)
|
||||||
check:
|
check:
|
||||||
expect == secret.data
|
expect == secret.data
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
var s = PrivateKey.fromRaw(keccak256.digest("ecdhAgree").data)[]
|
var s = PrivateKey.fromRaw(keccak256.digest("ecdhAgree").data)[]
|
||||||
var p = s.toPublicKey()
|
var p = s.toPublicKey()
|
||||||
let expect = fromHex(stripSpaces(expectm))
|
let expect = fromHex(stripSpaces(expectm))
|
||||||
let secret = ecdhRaw(s, p)
|
let secret = ecdhSecret(s, p)
|
||||||
check:
|
check:
|
||||||
expect == secret.data
|
expect == secret.data
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
var s = PrivateKey.fromHex(stripSpaces(s0))[]
|
var s = PrivateKey.fromHex(stripSpaces(s0))[]
|
||||||
var p = PublicKey.fromHex(stripSpaces(p0))[]
|
var p = PublicKey.fromHex(stripSpaces(p0))[]
|
||||||
let expect = fromHex(stripSpaces(e0))
|
let expect = fromHex(stripSpaces(e0))
|
||||||
let secret = ecdhRaw(s, p)
|
let secret = ecdhSecret(s, p)
|
||||||
check:
|
check:
|
||||||
compare(expect, secret.data) == true
|
compare(expect, secret.data) == true
|
||||||
|
|
||||||
|
@ -242,8 +242,8 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
var alicePublic = aliceSecret.toPublicKey()
|
var alicePublic = aliceSecret.toPublicKey()
|
||||||
var bobSecret = PrivateKey.random(rng[])
|
var bobSecret = PrivateKey.random(rng[])
|
||||||
var bobPublic = bobSecret.toPublicKey()
|
var bobPublic = bobSecret.toPublicKey()
|
||||||
var secret1 = ecdhRaw(aliceSecret, bobPublic)
|
var secret1 = ecdhSecret(aliceSecret, bobPublic)
|
||||||
var secret2 = ecdhRaw(bobSecret, alicePublic)
|
var secret2 = ecdhSecret(bobSecret, alicePublic)
|
||||||
check:
|
check:
|
||||||
secret1 == secret2
|
secret1 == secret2
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ suite "Discovery v5.1 Cryptographic Primitives Test Vectors":
|
||||||
let
|
let
|
||||||
pub = PublicKey.fromHex(publicKey)[]
|
pub = PublicKey.fromHex(publicKey)[]
|
||||||
priv = PrivateKey.fromHex(secretKey)[]
|
priv = PrivateKey.fromHex(secretKey)[]
|
||||||
eph = ecdhRawFull(priv, pub)
|
eph = ecdhSecretFull(priv, pub)
|
||||||
check:
|
check:
|
||||||
eph.data == hexToSeqByte(sharedSecret)
|
eph.data == hexToSeqByte(sharedSecret)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue