remove ecdhRaw usage and replace it with ecdh+custom hash function

This commit is contained in:
jangko 2023-04-20 11:54:54 +07:00
parent 6053c252e7
commit 9bf2e1786b
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
6 changed files with 47 additions and 26 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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