mirror of
https://github.com/status-im/nim-eth-p2p.git
synced 2025-01-26 22:58:52 +00:00
first attempt
This commit is contained in:
parent
b48a4cacf1
commit
1afd8b67e1
635
ethp2p/ecies.nim
635
ethp2p/ecies.nim
@ -13,6 +13,9 @@ import ecc, nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac
|
||||
import nimcrypto/rijndael, nimcrypto/utils, nimcrypto/sysrand
|
||||
import nimcrypto/bcmode, nimcrypto/utils
|
||||
|
||||
const
|
||||
emptyMac* = array[0, byte]([])
|
||||
|
||||
type
|
||||
EciesException* = object of Exception
|
||||
EciesStatus* = enum
|
||||
@ -24,24 +27,14 @@ type
|
||||
IncorrectSize, ## ECIES data has incorrect size (size is too low)
|
||||
WrongHeader, ## ECIES header is incorrect
|
||||
IncorrectKey, ## Recovered public key is invalid
|
||||
IncorrectTag ## ECIES tag verification failed
|
||||
IncorrectTag, ## ECIES tag verification failed
|
||||
IncompleteError ## Decryption needs more data
|
||||
|
||||
when false:
|
||||
# REVIEW(zah):
|
||||
# Why do we work with arrays and known fixed offsets (such sa eciesIvPos)
|
||||
# instead of defining object types with named fields:
|
||||
type
|
||||
EciesPrefix = object
|
||||
leadingByte: byte
|
||||
pubKey: PublicKey
|
||||
iv: array[aes128.sizeBlock]
|
||||
|
||||
# You can then write to these fields by doing:
|
||||
var eciesPrefix = cast[ptr EciesPrefix](addr array[0])
|
||||
eciesPrefix.pubKey = ...
|
||||
eciesPrefix.iv = ...
|
||||
|
||||
# This will make the code slightly easier to read and review for correctness
|
||||
EciesHeader* = object {.packed.}
|
||||
version*: byte
|
||||
pubkey*: array[PublicKeyLength, byte]
|
||||
iv*: array[aes128.sizeBlock, byte]
|
||||
data*: byte
|
||||
|
||||
template eciesOverheadLength*(): int =
|
||||
## Return data overhead size for ECIES encrypted message
|
||||
@ -63,13 +56,16 @@ template eciesMacPos(size: int): int =
|
||||
## Return position of MAC code in encrypted block
|
||||
size - sha256.sizeDigest
|
||||
|
||||
template eciesIvPos(): int =
|
||||
## Return position of IV in encrypted block
|
||||
sizeof(PublicKey) + 1
|
||||
|
||||
template eciesDataPos(): int =
|
||||
## Return position of encrypted data in block
|
||||
sizeof(PublicKey) + 1 + aes128.sizeBlock
|
||||
1 + sizeof(PublicKey) + aes128.sizeBlock
|
||||
|
||||
template eciesIvPos(): int =
|
||||
## Return position of IV in block
|
||||
1 + sizeof(PublicKey)
|
||||
|
||||
template eciesTagPos(size: int): int =
|
||||
1 + sizeof(PublicKey) + aes128.sizeBlock + size
|
||||
|
||||
proc kdf*(data: openarray[byte]): array[KeyLength, byte] {.noInit.} =
|
||||
## NIST SP 800-56a Concatenation Key Derivation Function (see section 5.8.1)
|
||||
@ -87,307 +83,402 @@ proc kdf*(data: openarray[byte]): array[KeyLength, byte] {.noInit.} =
|
||||
ctx.init()
|
||||
ctx.update(cast[ptr byte](addr counterLe), uint(sizeof(uint32)))
|
||||
ctx.update(unsafeAddr data[0], uint(len(data)))
|
||||
# REVIEW: unnecessary copy here
|
||||
var hash = ctx.finish().data
|
||||
copyMem(addr storage[offset], addr hash[0], ctx.sizeDigest)
|
||||
var hash = ctx.finish()
|
||||
copyMem(addr storage[offset], addr hash.data[0], ctx.sizeDigest)
|
||||
offset += int(ctx.sizeDigest)
|
||||
ctx.init() # clean ctx
|
||||
ctx.clear() # clean ctx
|
||||
copyMem(addr result[0], addr storage[0], KeyLength)
|
||||
|
||||
# REVIEW(zah): We can make Araq happy by using the new openarray
|
||||
# for these input and output parameters
|
||||
proc eciesEncrypt*(inp, oup: ptr byte, inl, oul: int, pubkey: PublicKey,
|
||||
shmac: ptr byte = nil, shlen: int = 0): EciesStatus =
|
||||
## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
##
|
||||
## `inp` - [INPUT] pointer to input data
|
||||
## `oup` - [INPUT] pointer to output data
|
||||
## `inl` - [INPUT] input data size
|
||||
## `oul` - [INPUT] output data size
|
||||
## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
## `shmac` - [INPUT] additional mac data
|
||||
## `shlen` - [INPUT] additional mac data size
|
||||
|
||||
proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte],
|
||||
pubkey: PublicKey,
|
||||
sharedmac: openarray[byte]): EciesStatus =
|
||||
## Encrypt data with ECIES method using given public key `pubkey`.
|
||||
## ``input`` - input data
|
||||
## ``output`` - output data
|
||||
## ``pubkey`` - ECC public key
|
||||
## ``sharedmac`` - additional data used to calculate encrypted message MAC
|
||||
## Length of output data can be calculated using ``eciesEncryptedLength()``
|
||||
## macro.
|
||||
var
|
||||
encKey: array[KeyLength div 2, byte]
|
||||
macKey: array[KeyLength, byte]
|
||||
encKey: array[aes128.sizeKey, byte]
|
||||
cipher: CTR[aes128]
|
||||
ctx: HMAC[sha256]
|
||||
iv: array[aes128.sizeBlock, byte]
|
||||
tag: array[sha256.sizeDigest, byte]
|
||||
secret: SharedSecret
|
||||
material: array[KeyLength, byte]
|
||||
|
||||
assert(not isNil(inp) and not isNil(oup))
|
||||
assert(inl > 0 and oul > 0)
|
||||
|
||||
if oul < eciesEncryptedLength(inl):
|
||||
if len(output) < eciesEncryptedLength(len(input)):
|
||||
return(BufferOverrun)
|
||||
if randomBytes(addr iv[0], len(iv)) != len(iv):
|
||||
if randomBytes(iv) != aes128.sizeBlock:
|
||||
return(RandomError)
|
||||
|
||||
var ephemeral = newKeyPair()
|
||||
var output = cast[ptr UncheckedArray[byte]](oup)
|
||||
var epub = ephemeral.pubkey.getRaw()
|
||||
|
||||
if ecdhAgree(ephemeral.seckey, pubkey, secret) != EccStatus.Success:
|
||||
return(EcdhError)
|
||||
|
||||
material = kdf(secret)
|
||||
burnMem(secret)
|
||||
|
||||
when false:
|
||||
# REVIEW: Please try to write the code in a way that's easy to review
|
||||
# only by looking at the current line. For example, the zeroMem call
|
||||
# below could have been written:
|
||||
zeroMem(addr secret[0], sizeof(secret))
|
||||
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||
var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
||||
burnMem(material)
|
||||
|
||||
# or even better:
|
||||
zeroArray(secret)
|
||||
var header = cast[ptr EciesHeader](addr output[0])
|
||||
header.version = 0x04
|
||||
header.pubkey = epub.data
|
||||
header.iv = iv
|
||||
|
||||
# where `zeroArray` is a template that does the right thing:
|
||||
template zeroArray(a: array) = zeroMem(unsafeAddr a[0], sizeof(a))
|
||||
var so = eciesDataPos()
|
||||
var eo = so + len(input)
|
||||
cipher.init(encKey, iv)
|
||||
cipher.encrypt(input, toOpenArray(output, so, eo))
|
||||
burnMem(encKey)
|
||||
cipher.clear()
|
||||
|
||||
# When constants are used, sometimes errors will slip through the
|
||||
# cracks after copy/pasting code and it's harder to notice the problem
|
||||
# in a code review.
|
||||
so = eciesIvPos()
|
||||
eo = so + aes128.sizeBlock + len(input)
|
||||
ctx.init(macKey.data)
|
||||
ctx.update(toOpenArray(output, so, eo))
|
||||
if len(sharedmac) > 0:
|
||||
ctx.update(sharedmac)
|
||||
var tag = ctx.finish()
|
||||
|
||||
zeroMem(addr secret[0], sizeof(SharedSecret)) # clean shared secret
|
||||
copyMem(addr encKey[0], addr material[0], KeyLength div 2)
|
||||
so = eciesTagPos(len(input))
|
||||
copyMem(addr output[so], addr tag.data[0], ctx.sizeDigest)
|
||||
ctx.clear()
|
||||
|
||||
# REVIEW: The line below will introduce an array copy. Is this intentional?
|
||||
# If you store the result MDigest value on the stack and use the `data` field
|
||||
# in `ctx.init` below, there won't be copies. I've also noticed that you are
|
||||
# trying to zero out the `macKey` variable at the end of the function, which
|
||||
# I assume is done as a security measure. The temporary MDigest here will
|
||||
# store the same bytes and won't be zeroed out.
|
||||
macKey = sha256.digest(material, KeyLength div 2).data
|
||||
zeroMem(addr material[0], KeyLength) # clean material
|
||||
|
||||
cipher.init(addr encKey[0], addr iv[0])
|
||||
cipher.encrypt(inp, cast[ptr byte](addr output[eciesDataPos()]), uint(inl))
|
||||
zeroMem(addr encKey[0], KeyLength div 2) # clean encKey
|
||||
zeroMem(addr cipher, sizeof(CTR[aes128])) # clean cipher context
|
||||
|
||||
output[0] = 0x04
|
||||
copyMem(addr output[1], addr epub.data[0], sizeof(PublicKey))
|
||||
copyMem(addr output[eciesIvPos()], addr iv[0], aes128.sizeBlock)
|
||||
|
||||
ctx.init(addr macKey[0], uint(len(macKey)))
|
||||
ctx.update(addr output[eciesIvPos()], uint(eciesMacLength(inl)))
|
||||
if not isNil(shmac) and shlen > 0:
|
||||
ctx.update(shmac, uint(shlen))
|
||||
tag = ctx.finish().data
|
||||
|
||||
# REVIEW: If this is an important step after creating a HMAC, perhaps
|
||||
# it could be provided as an alternative way to call `finish` or
|
||||
# at least it could be a proc like `ctx.clear()`
|
||||
zeroMem(addr ctx, sizeof(HMAC[sha256])) # clean hmac context
|
||||
zeroMem(addr macKey[0], KeyLength) # clean macKey
|
||||
copyMem(addr output[eciesDataPos() + inl], addr tag[0], sha256.sizeDigest)
|
||||
result = Success
|
||||
|
||||
proc eciesDecrypt*(inp, oup: ptr byte, inl, oul: int, seckey: PrivateKey,
|
||||
shmac: ptr byte = nil, shlen: int = 0): EciesStatus =
|
||||
## Decrypt data with ECIES method using the given private key `seckey`.
|
||||
##
|
||||
## `inp` - [INPUT] pointer to input data
|
||||
## `oup` - [INPUT] pointer to output data
|
||||
## `inl` - [INPUT] input data size
|
||||
## `oul` - [INPUT] output data size
|
||||
## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
## `shmac` - [INPUT] additional mac data (default = nil)
|
||||
## `shlen` - [INPUT] additional mac data size (default = 0)
|
||||
|
||||
proc eciesDecrypt*(input: openarray[byte],
|
||||
output: var openarray[byte],
|
||||
seckey: PrivateKey,
|
||||
sharedmac: openarray[byte]): EciesStatus =
|
||||
## Decrypt data with ECIES method using given private key `seckey`.
|
||||
## ``input`` - input data
|
||||
## ``output`` - output data
|
||||
## ``pubkey`` - ECC private key
|
||||
## ``sharedmac`` - additional data used to calculate encrypted message MAC
|
||||
## Length of output data can be calculated using ``eciesDecryptedLength()``
|
||||
## macro.
|
||||
var
|
||||
pubkey: PublicKey
|
||||
encKey: array[KeyLength div 2, byte]
|
||||
macKey: array[KeyLength, byte]
|
||||
tag: array[sha256.sizeDigest, byte]
|
||||
encKey: array[aes128.sizeKey, byte]
|
||||
cipher: CTR[aes128]
|
||||
ctx: HMAC[sha256]
|
||||
secret: SharedSecret
|
||||
|
||||
assert(not isNil(inp) and not isNil(oup))
|
||||
assert(inl > 0 and oul > 0)
|
||||
if len(input) == 0:
|
||||
return(IncompleteError)
|
||||
|
||||
var input = cast[ptr UncheckedArray[byte]](inp)
|
||||
if inl <= eciesOverheadLength():
|
||||
return(IncorrectSize)
|
||||
if inl - eciesOverheadLength() > oul:
|
||||
return(BufferOverrun)
|
||||
if input[0] != 0x04:
|
||||
var header = cast[ptr EciesHeader](unsafeAddr input[0])
|
||||
if header.version != 0x04:
|
||||
return(WrongHeader)
|
||||
|
||||
if recoverPublicKey(addr input[1], KeyLength * 2,
|
||||
pubkey) != EccStatus.Success:
|
||||
if len(input) <= eciesOverheadLength():
|
||||
return(IncompleteError)
|
||||
if len(input) - eciesOverheadLength() > len(output):
|
||||
return(BufferOverrun)
|
||||
if recoverPublicKey(header.pubkey, pubkey) != EccStatus.Success:
|
||||
return(IncorrectKey)
|
||||
if ecdhAgree(seckey, pubkey, secret) != EccStatus.Success:
|
||||
return(EcdhError)
|
||||
|
||||
var material = kdf(secret)
|
||||
zeroMem(addr secret[0], sizeof(SharedSecret)) # clean shared secret
|
||||
copyMem(addr encKey[0], addr material[0], KeyLength div 2)
|
||||
# REVIEW: unnecessary copy
|
||||
macKey = sha256.digest(material, KeyLength div 2).data
|
||||
zeroMem(addr material[0], KeyLength) # clean material
|
||||
burnMem(secret)
|
||||
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||
var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
||||
burnMem(material)
|
||||
|
||||
let macsize = eciesMacLength(inl - eciesOverheadLength())
|
||||
ctx.init(addr macKey[0], uint(len(macKey)))
|
||||
let macsize = eciesMacLength(len(input) - eciesOverheadLength())
|
||||
let datsize = eciesDecryptedLength(len(input))
|
||||
ctx.init(macKey.data)
|
||||
burnMem(macKey)
|
||||
ctx.update(toOpenArray(input, eciesIvPos(), eciesIvPos() + macsize))
|
||||
if len(sharedmac) > 0:
|
||||
ctx.update(sharedmac)
|
||||
var tag = ctx.finish()
|
||||
ctx.clear()
|
||||
|
||||
ctx.update(addr input[eciesIvPos()], uint(macsize))
|
||||
if not isNil(shmac) and shlen > 0:
|
||||
ctx.update(shmac, uint(shlen))
|
||||
tag = ctx.finish().data
|
||||
zeroMem(addr ctx, sizeof(HMAC[sha256])) # clean hmac context
|
||||
zeroMem(addr macKey[0], KeyLength) # clean macKey
|
||||
|
||||
if not equalMem(addr tag[0], addr input[eciesMacPos(inl)], sha256.sizeDigest):
|
||||
if not equalMem(addr tag.data[0], unsafeAddr input[eciesMacPos(len(input))],
|
||||
sha256.sizeDigest):
|
||||
return(IncorrectTag)
|
||||
|
||||
cipher.init(addr encKey[0], addr input[eciesIvPos()])
|
||||
cipher.decrypt(cast[ptr byte](addr input[eciesDataPos()]),
|
||||
cast[ptr byte](oup), uint(inl - eciesOverheadLength()))
|
||||
|
||||
zeroMem(addr encKey[0], KeyLength div 2) # clean encKey
|
||||
zeroMem(addr cipher, sizeof(CTR[aes128])) # clean cipher context
|
||||
cipher.init(encKey, header.iv)
|
||||
burnMem(encKey)
|
||||
cipher.decrypt(toOpenArray(input, eciesDataPos(), eciesDataPos() + datsize),
|
||||
output)
|
||||
cipher.clear()
|
||||
result = Success
|
||||
|
||||
proc eciesEncrypt*[A, B](input: openarray[A],
|
||||
pubkey: PublicKey,
|
||||
output: var openarray[B],
|
||||
outlen: var int,
|
||||
ostart: int = 0,
|
||||
ofinish: int = -1): EciesStatus =
|
||||
## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
##
|
||||
## `input` - [INPUT] input data
|
||||
## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
## `output` - [OUTPUT] output data
|
||||
## `outlen` - [OUTPUT] output data size
|
||||
## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
##
|
||||
## Encryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
## Negative values of `ostart` and `ofinish` are treated as index with value
|
||||
## (len(data) + `ostart/ofinish`).
|
||||
|
||||
let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
let length = (eo - so + 1) * sizeof(A)
|
||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
if eo >= len(input):
|
||||
return(BufferOverrun)
|
||||
if len(input) == 0:
|
||||
return(EmptyMessage)
|
||||
let esize = eciesEncryptedLength(length)
|
||||
if (len(output) * sizeof(B)) < esize:
|
||||
return(BufferOverrun)
|
||||
outlen = esize
|
||||
result = eciesEncrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
length, esize, pubkey)
|
||||
# proc eciesEncrypt*(inp, oup: ptr byte, inl, oul: int, pubkey: PublicKey,
|
||||
# shmac: ptr byte = nil, shlen: int = 0): EciesStatus =
|
||||
# ## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
# ##
|
||||
# ## `inp` - [INPUT] pointer to input data
|
||||
# ## `oup` - [INPUT] pointer to output data
|
||||
# ## `inl` - [INPUT] input data size
|
||||
# ## `oul` - [INPUT] output data size
|
||||
# ## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
# ## `shmac` - [INPUT] additional mac data
|
||||
# ## `shlen` - [INPUT] additional mac data size
|
||||
|
||||
proc eciesEncrypt*[A, B, C](input: openarray[A],
|
||||
pubkey: PublicKey,
|
||||
output: var openarray[B],
|
||||
outlen: var int,
|
||||
shmac: openarray[C],
|
||||
ostart: int = 0,
|
||||
ofinish: int = -1): EciesStatus =
|
||||
## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
##
|
||||
## `input` - [INPUT] input data
|
||||
## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
## `output` - [OUTPUT] output data
|
||||
## `outlen` - [OUTPUT] output data size
|
||||
## `shmac` - [INPUT] additional mac data
|
||||
## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
##
|
||||
## Encryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
## Negative values of `ostart` and `ofinish` are treated as index with value
|
||||
## (len(data) + `ostart/ofinish`).
|
||||
# var
|
||||
# encKey: array[aes128.sizeKey, byte]
|
||||
# cipher: CTR[aes128]
|
||||
# ctx: HMAC[sha256]
|
||||
# iv: array[aes128.sizeBlock, byte]
|
||||
# secret: SharedSecret
|
||||
# material: array[KeyLength, byte]
|
||||
|
||||
let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
let length = (eo - so + 1) * sizeof(A)
|
||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
if eo >= len(input):
|
||||
return(BufferOverrun)
|
||||
if len(input) == 0:
|
||||
return(EmptyMessage)
|
||||
let esize = eciesEncryptedLength(length)
|
||||
if len(output) * sizeof(B) < esize:
|
||||
return(BufferOverrun)
|
||||
outlen = esize
|
||||
result = eciesEncrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
length, esize, pubkey,
|
||||
cast[ptr byte](unsafeAddr shmac[0]),
|
||||
len(shmac) * sizeof(C))
|
||||
# assert(not isNil(inp) and not isNil(oup))
|
||||
# assert(inl > 0 and oul > 0)
|
||||
|
||||
proc eciesDecrypt*[A, B](input: openarray[A],
|
||||
seckey: PrivateKey,
|
||||
output: var openarray[B],
|
||||
outlen: var int,
|
||||
ostart: int = 0,
|
||||
ofinish: int = -1): EciesStatus =
|
||||
## Decrypt data with ECIES method using given private key `seckey`.
|
||||
##
|
||||
## `input` - [INPUT] input data
|
||||
## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
## `output` - [OUTPUT] output data
|
||||
## `outlen` - [OUTPUT] output data size
|
||||
## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
##
|
||||
## Decryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
# if oul < eciesEncryptedLength(inl):
|
||||
# return(BufferOverrun)
|
||||
# if randomBytes(addr iv[0], len(iv)) != len(iv):
|
||||
# return(RandomError)
|
||||
|
||||
let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
let length = (eo - so + 1) * sizeof(A)
|
||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
if eo >= len(input):
|
||||
return(BufferOverrun)
|
||||
if len(input) == 0:
|
||||
return(EmptyMessage)
|
||||
let dsize = eciesDecryptedLength(length)
|
||||
if len(output) * sizeof(B) < dsize:
|
||||
return(BufferOverrun)
|
||||
outlen = dsize
|
||||
result = eciesDecrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
length, dsize, seckey)
|
||||
# var ephemeral = newKeyPair()
|
||||
# var output = cast[ptr UncheckedArray[byte]](oup)
|
||||
# var epub = ephemeral.pubkey.getRaw()
|
||||
|
||||
proc eciesDecrypt*[A, B, C](input: openarray[A],
|
||||
seckey: PrivateKey,
|
||||
output: var openarray[B],
|
||||
outlen: var int,
|
||||
shmac: openarray[C],
|
||||
ostart: int = 0,
|
||||
ofinish: int = -1): EciesStatus =
|
||||
## Decrypt data with ECIES method using given private key `seckey`.
|
||||
##
|
||||
## `input` - [INPUT] input data
|
||||
## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
## `output` - [OUTPUT] output data
|
||||
## `outlen` - [OUTPUT] output data size
|
||||
## `shmac` - additional mac data
|
||||
## `ostart` - starting index in `data` (default = -1, data[0])
|
||||
## `ofinish` - ending index in `data` (default = -1, data[len(data) - 1])
|
||||
##
|
||||
## Decryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
# if ecdhAgree(ephemeral.seckey, pubkey, secret) != EccStatus.Success:
|
||||
# return(EcdhError)
|
||||
|
||||
let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
let length = (eo - so + 1) * sizeof(A)
|
||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
if eo >= len(input):
|
||||
return(BufferOverrun)
|
||||
if len(input) == 0:
|
||||
return(EmptyMessage)
|
||||
let dsize = eciesDecryptedLength(length)
|
||||
if len(output) * sizeof(B) < dsize:
|
||||
return(BufferOverrun)
|
||||
outlen = dsize
|
||||
result = eciesDecrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
length, dsize, seckey,
|
||||
cast[ptr byte](unsafeAddr shmac[0]),
|
||||
len(shmac) * sizeof(C))
|
||||
# material = kdf(secret)
|
||||
# burnMem(secret)
|
||||
|
||||
# copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||
# var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
||||
# burnMem(material)
|
||||
|
||||
# var header = cast[ptr EciesHeader](oup)
|
||||
# header.version = 0x04
|
||||
# header.pubkey = epub.data
|
||||
# header.iv = iv
|
||||
|
||||
# cipher.init(addr encKey[0], addr iv[0])
|
||||
# cipher.encrypt(inp, cast[ptr byte](addr header.data), uint(inl))
|
||||
# burnMem(encKey)
|
||||
# cipher.clear()
|
||||
|
||||
# ctx.init(cast[ptr byte](addr macKey.data[0]), uint(sha256.sizeDigest))
|
||||
# burnMem(macKey)
|
||||
# ctx.update(cast[ptr byte](addr header.iv), uint(eciesMacLength(inl)))
|
||||
# if not isNil(shmac) and shlen > 0:
|
||||
# ctx.update(shmac, uint(shlen))
|
||||
# var tag = ctx.finish()
|
||||
# ctx.clear()
|
||||
|
||||
# # echo dump(output, oul)
|
||||
|
||||
# let tagPos = cast[ptr byte](cast[uint](addr header.data) + uint(inl))
|
||||
# copyMem(tagPos, addr tag.data[0], sha256.sizeDigest)
|
||||
# result = Success
|
||||
|
||||
# proc eciesDecrypt*(inp, oup: ptr byte, inl, oul: int, seckey: PrivateKey,
|
||||
# shmac: ptr byte = nil, shlen: int = 0): EciesStatus =
|
||||
# ## Decrypt data with ECIES method using the given private key `seckey`.
|
||||
# ##
|
||||
# ## `inp` - [INPUT] pointer to input data
|
||||
# ## `oup` - [INPUT] pointer to output data
|
||||
# ## `inl` - [INPUT] input data size
|
||||
# ## `oul` - [INPUT] output data size
|
||||
# ## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
# ## `shmac` - [INPUT] additional mac data (default = nil)
|
||||
# ## `shlen` - [INPUT] additional mac data size (default = 0)
|
||||
|
||||
# var
|
||||
# pubkey: PublicKey
|
||||
# encKey: array[aes128.sizeKey, byte]
|
||||
# cipher: CTR[aes128]
|
||||
# ctx: HMAC[sha256]
|
||||
# secret: SharedSecret
|
||||
|
||||
# assert(not isNil(inp) and not isNil(oup))
|
||||
# assert(inl > 0 and oul > 0)
|
||||
|
||||
# var input = cast[ptr UncheckedArray[byte]](inp)
|
||||
# if inl <= eciesOverheadLength():
|
||||
# return(IncorrectSize)
|
||||
# if inl - eciesOverheadLength() > oul:
|
||||
# return(BufferOverrun)
|
||||
|
||||
# var header = cast[ptr EciesHeader](input)
|
||||
# if header.version != 0x04:
|
||||
# return(WrongHeader)
|
||||
|
||||
# if recoverPublicKey(addr input[1], KeyLength * 2,
|
||||
# pubkey) != EccStatus.Success:
|
||||
# return(IncorrectKey)
|
||||
|
||||
# if ecdhAgree(seckey, pubkey, secret) != EccStatus.Success:
|
||||
# return(EcdhError)
|
||||
|
||||
# var material = kdf(secret)
|
||||
# burnMem(secret)
|
||||
# copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||
# var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
||||
# burnMem(material)
|
||||
|
||||
# let macsize = eciesMacLength(inl - eciesOverheadLength())
|
||||
# ctx.init(addr macKey.data[0], uint(sha256.sizeDigest))
|
||||
# burnMem(macKey)
|
||||
# ctx.update(cast[ptr byte](addr header.iv), uint(macsize))
|
||||
# if not isNil(shmac) and shlen > 0:
|
||||
# ctx.update(shmac, uint(shlen))
|
||||
# var tag = ctx.finish()
|
||||
# ctx.clear()
|
||||
|
||||
# if not equalMem(addr tag.data[0], addr input[eciesMacPos(inl)],
|
||||
# sha256.sizeDigest):
|
||||
# return(IncorrectTag)
|
||||
|
||||
# cipher.init(addr encKey[0], cast[ptr byte](addr header.iv))
|
||||
# burnMem(encKey)
|
||||
# cipher.decrypt(cast[ptr byte](addr header.data),
|
||||
# cast[ptr byte](oup), uint(inl - eciesOverheadLength()))
|
||||
# cipher.clear()
|
||||
# result = Success
|
||||
|
||||
# proc eciesEncrypt*[A, B](input: openarray[A],
|
||||
# pubkey: PublicKey,
|
||||
# output: var openarray[B],
|
||||
# outlen: var int,
|
||||
# ostart: int = 0,
|
||||
# ofinish: int = -1): EciesStatus =
|
||||
# ## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
# ##
|
||||
# ## `input` - [INPUT] input data
|
||||
# ## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
# ## `output` - [OUTPUT] output data
|
||||
# ## `outlen` - [OUTPUT] output data size
|
||||
# ## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
# ## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
# ##
|
||||
# ## Encryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
# ## Negative values of `ostart` and `ofinish` are treated as index with value
|
||||
# ## (len(data) + `ostart/ofinish`).
|
||||
|
||||
# let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
# let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
# let length = (eo - so + 1) * sizeof(A)
|
||||
# # We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
# if eo >= len(input):
|
||||
# return(BufferOverrun)
|
||||
# if len(input) == 0:
|
||||
# return(EmptyMessage)
|
||||
# let esize = eciesEncryptedLength(length)
|
||||
# if (len(output) * sizeof(B)) < esize:
|
||||
# return(BufferOverrun)
|
||||
# outlen = esize
|
||||
# result = eciesEncrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
# length, esize, pubkey)
|
||||
|
||||
# proc eciesEncrypt*[A, B, C](input: openarray[A],
|
||||
# pubkey: PublicKey,
|
||||
# output: var openarray[B],
|
||||
# outlen: var int,
|
||||
# shmac: openarray[C],
|
||||
# ostart: int = 0,
|
||||
# ofinish: int = -1): EciesStatus =
|
||||
# ## Encrypt data with ECIES method to the given public key `pubkey`.
|
||||
# ##
|
||||
# ## `input` - [INPUT] input data
|
||||
# ## `pubkey` - [INPUT] Ecc secp256k1 public key
|
||||
# ## `output` - [OUTPUT] output data
|
||||
# ## `outlen` - [OUTPUT] output data size
|
||||
# ## `shmac` - [INPUT] additional mac data
|
||||
# ## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
# ## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
# ##
|
||||
# ## Encryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
# ## Negative values of `ostart` and `ofinish` are treated as index with value
|
||||
# ## (len(data) + `ostart/ofinish`).
|
||||
|
||||
# let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
# let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
# let length = (eo - so + 1) * sizeof(A)
|
||||
# # We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
# if eo >= len(input):
|
||||
# return(BufferOverrun)
|
||||
# if len(input) == 0:
|
||||
# return(EmptyMessage)
|
||||
# let esize = eciesEncryptedLength(length)
|
||||
# if len(output) * sizeof(B) < esize:
|
||||
# return(BufferOverrun)
|
||||
# outlen = esize
|
||||
# result = eciesEncrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
# length, esize, pubkey,
|
||||
# cast[ptr byte](unsafeAddr shmac[0]),
|
||||
# len(shmac) * sizeof(C))
|
||||
|
||||
# proc eciesDecrypt*[A, B](input: openarray[A],
|
||||
# seckey: PrivateKey,
|
||||
# output: var openarray[B],
|
||||
# outlen: var int,
|
||||
# ostart: int = 0,
|
||||
# ofinish: int = -1): EciesStatus =
|
||||
# ## Decrypt data with ECIES method using given private key `seckey`.
|
||||
# ##
|
||||
# ## `input` - [INPUT] input data
|
||||
# ## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
# ## `output` - [OUTPUT] output data
|
||||
# ## `outlen` - [OUTPUT] output data size
|
||||
# ## `ostart` - [INPUT] starting index in `data` (default = -1, start of input)
|
||||
# ## `ofinish` - [INPUT] ending index in `data` (default = -1, whole input)
|
||||
# ##
|
||||
# ## Decryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
|
||||
# let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
# let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
# let length = (eo - so + 1) * sizeof(A)
|
||||
# # We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
# if eo >= len(input):
|
||||
# return(BufferOverrun)
|
||||
# if len(input) == 0:
|
||||
# return(EmptyMessage)
|
||||
# let dsize = eciesDecryptedLength(length)
|
||||
# if len(output) * sizeof(B) < dsize:
|
||||
# return(BufferOverrun)
|
||||
# outlen = dsize
|
||||
# result = eciesDecrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
# length, dsize, seckey)
|
||||
|
||||
# proc eciesDecrypt*[A, B, C](input: openarray[A],
|
||||
# seckey: PrivateKey,
|
||||
# output: var openarray[B],
|
||||
# outlen: var int,
|
||||
# shmac: openarray[C],
|
||||
# ostart: int = 0,
|
||||
# ofinish: int = -1): EciesStatus =
|
||||
# ## Decrypt data with ECIES method using given private key `seckey`.
|
||||
# ##
|
||||
# ## `input` - [INPUT] input data
|
||||
# ## `seckey` - [INPUT] Ecc secp256k1 private key
|
||||
# ## `output` - [OUTPUT] output data
|
||||
# ## `outlen` - [OUTPUT] output data size
|
||||
# ## `shmac` - additional mac data
|
||||
# ## `ostart` - starting index in `data` (default = -1, data[0])
|
||||
# ## `ofinish` - ending index in `data` (default = -1, data[len(data) - 1])
|
||||
# ##
|
||||
# ## Decryption is done on `data` with inclusive range [ostart, ofinish]
|
||||
|
||||
# let so = if ostart < 0: (len(input) + ostart) else: ostart
|
||||
# let eo = if ofinish < 0: (len(input) + ofinish) else: ofinish
|
||||
# let length = (eo - so + 1) * sizeof(A)
|
||||
# # We don't need to check `so` because compiler will do it for `data[so]`.
|
||||
# if eo >= len(input):
|
||||
# return(BufferOverrun)
|
||||
# if len(input) == 0:
|
||||
# return(EmptyMessage)
|
||||
# let dsize = eciesDecryptedLength(length)
|
||||
# if len(output) * sizeof(B) < dsize:
|
||||
# return(BufferOverrun)
|
||||
# outlen = dsize
|
||||
# result = eciesDecrypt(cast[ptr byte](unsafeAddr input[so]), addr output[0],
|
||||
# length, dsize, seckey,
|
||||
# cast[ptr byte](unsafeAddr shmac[0]),
|
||||
# len(shmac) * sizeof(C))
|
||||
|
@ -53,6 +53,7 @@ suite "ECIES test suite":
|
||||
test "ECIES \"Hello World!\" encryption/decryption test":
|
||||
# ECIES encryption
|
||||
var m = "Hello World!"
|
||||
var plain = cast[seq[byte]](m)
|
||||
var encr = newSeq[byte](eciesEncryptedLength(len(m)))
|
||||
var decr = newSeq[byte](len(m))
|
||||
var shmac = [0x13'u8, 0x13'u8]
|
||||
@ -61,105 +62,104 @@ suite "ECIES test suite":
|
||||
var p = s.getPublicKey()
|
||||
check:
|
||||
# Without additional mac data
|
||||
eciesEncrypt(m, p, encr, outlen) == EciesStatus.Success
|
||||
eciesDecrypt(encr, s, decr, outlen) == EciesStatus.Success
|
||||
outlen == len(m)
|
||||
equalMem(addr m[0], addr decr[0], outlen) == true
|
||||
# With additional mac data
|
||||
eciesEncrypt(m, p, encr, outlen, shmac) == EciesStatus.Success
|
||||
eciesDecrypt(encr, s, decr, outlen, shmac) == EciesStatus.Success
|
||||
outlen == len(m)
|
||||
eciesEncrypt(plain, encr, p, [0'u8]) == EciesStatus.Success
|
||||
eciesDecrypt(encr, decr, s, [0'u8]) == EciesStatus.Success
|
||||
equalMem(addr m[0], addr decr[0], outlen) == true
|
||||
# # With additional mac data
|
||||
# eciesEncrypt(m, p, encr, outlen, shmac) == EciesStatus.Success
|
||||
# eciesDecrypt(encr, s, decr, outlen, shmac) == EciesStatus.Success
|
||||
# outlen == len(m)
|
||||
# equalMem(addr m[0], addr decr[0], outlen) == true
|
||||
|
||||
test "ECIES/py-evm/cpp-ethereum test_ecies.py#L43/rlpx.cpp#L187":
|
||||
# ECIES
|
||||
# https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_ecies.py#L43
|
||||
# https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libp2p/rlpx.cpp#L187
|
||||
const secretKeys = [
|
||||
"c45f950382d542169ea207959ee0220ec1491755abe405cd7498d6b16adb6df8",
|
||||
"5e173f6ac3c669587538e7727cf19b782a4f2fda07c1eaa662c593e5e85e3051"
|
||||
]
|
||||
const cipherText = [
|
||||
"""04a0274c5951e32132e7f088c9bdfdc76c9d91f0dc6078e848f8e3361193dbdc
|
||||
43b94351ea3d89e4ff33ddcefbc80070498824857f499656c4f79bbd97b6c51a
|
||||
514251d69fd1785ef8764bd1d262a883f780964cce6a14ff206daf1206aa073a
|
||||
2d35ce2697ebf3514225bef186631b2fd2316a4b7bcdefec8d75a1025ba2c540
|
||||
4a34e7795e1dd4bc01c6113ece07b0df13b69d3ba654a36e35e69ff9d482d88d
|
||||
2f0228e7d96fe11dccbb465a1831c7d4ad3a026924b182fc2bdfe016a6944312
|
||||
021da5cc459713b13b86a686cf34d6fe6615020e4acf26bf0d5b7579ba813e77
|
||||
23eb95b3cef9942f01a58bd61baee7c9bdd438956b426a4ffe238e61746a8c93
|
||||
d5e10680617c82e48d706ac4953f5e1c4c4f7d013c87d34a06626f498f34576d
|
||||
c017fdd3d581e83cfd26cf125b6d2bda1f1d56""",
|
||||
"""049934a7b2d7f9af8fd9db941d9da281ac9381b5740e1f64f7092f3588d4f87f
|
||||
5ce55191a6653e5e80c1c5dd538169aa123e70dc6ffc5af1827e546c0e958e42
|
||||
dad355bcc1fcb9cdf2cf47ff524d2ad98cbf275e661bf4cf00960e74b5956b79
|
||||
9771334f426df007350b46049adb21a6e78ab1408d5e6ccde6fb5e69f0f4c92b
|
||||
b9c725c02f99fa72b9cdc8dd53cff089e0e73317f61cc5abf6152513cb7d833f
|
||||
09d2851603919bf0fbe44d79a09245c6e8338eb502083dc84b846f2fee1cc310
|
||||
d2cc8b1b9334728f97220bb799376233e113"""
|
||||
]
|
||||
const expectText = [
|
||||
"""884c36f7ae6b406637c1f61b2f57e1d2cab813d24c6559aaf843c3f48962f32f
|
||||
46662c066d39669b7b2e3ba14781477417600e7728399278b1b5d801a519aa57
|
||||
0034fdb5419558137e0d44cd13d319afe5629eeccb47fd9dfe55cc6089426e46
|
||||
cc762dd8a0636e07a54b31169eba0c7a20a1ac1ef68596f1f283b5c676bae406
|
||||
4abfcce24799d09f67e392632d3ffdc12e3d6430dcb0ea19c318343ffa7aae74
|
||||
d4cd26fecb93657d1cd9e9eaf4f8be720b56dd1d39f190c4e1c6b7ec66f077bb
|
||||
1100""",
|
||||
"""802b052f8b066640bba94a4fc39d63815c377fced6fcb84d27f791c9921ddf3e
|
||||
9bf0108e298f490812847109cbd778fae393e80323fd643209841a3b7f110397
|
||||
f37ec61d84cea03dcc5e8385db93248584e8af4b4d1c832d8c7453c0089687a7
|
||||
00"""
|
||||
]
|
||||
var data: array[1024, byte]
|
||||
var outlen = 0
|
||||
for i in 0..1:
|
||||
var s = secretKeys[i].getPrivateKey()
|
||||
var cipher = fromHex(stripSpaces(cipherText[i]))
|
||||
var expect = fromHex(stripSpaces(expectText[i]))
|
||||
check:
|
||||
eciesDecrypt(cipher, s, data, outlen) == EciesStatus.Success
|
||||
outlen == len(expect)
|
||||
compare(data, expect) == true
|
||||
# test "ECIES/py-evm/cpp-ethereum test_ecies.py#L43/rlpx.cpp#L187":
|
||||
# # ECIES
|
||||
# # https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_ecies.py#L43
|
||||
# # https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libp2p/rlpx.cpp#L187
|
||||
# const secretKeys = [
|
||||
# "c45f950382d542169ea207959ee0220ec1491755abe405cd7498d6b16adb6df8",
|
||||
# "5e173f6ac3c669587538e7727cf19b782a4f2fda07c1eaa662c593e5e85e3051"
|
||||
# ]
|
||||
# const cipherText = [
|
||||
# """04a0274c5951e32132e7f088c9bdfdc76c9d91f0dc6078e848f8e3361193dbdc
|
||||
# 43b94351ea3d89e4ff33ddcefbc80070498824857f499656c4f79bbd97b6c51a
|
||||
# 514251d69fd1785ef8764bd1d262a883f780964cce6a14ff206daf1206aa073a
|
||||
# 2d35ce2697ebf3514225bef186631b2fd2316a4b7bcdefec8d75a1025ba2c540
|
||||
# 4a34e7795e1dd4bc01c6113ece07b0df13b69d3ba654a36e35e69ff9d482d88d
|
||||
# 2f0228e7d96fe11dccbb465a1831c7d4ad3a026924b182fc2bdfe016a6944312
|
||||
# 021da5cc459713b13b86a686cf34d6fe6615020e4acf26bf0d5b7579ba813e77
|
||||
# 23eb95b3cef9942f01a58bd61baee7c9bdd438956b426a4ffe238e61746a8c93
|
||||
# d5e10680617c82e48d706ac4953f5e1c4c4f7d013c87d34a06626f498f34576d
|
||||
# c017fdd3d581e83cfd26cf125b6d2bda1f1d56""",
|
||||
# """049934a7b2d7f9af8fd9db941d9da281ac9381b5740e1f64f7092f3588d4f87f
|
||||
# 5ce55191a6653e5e80c1c5dd538169aa123e70dc6ffc5af1827e546c0e958e42
|
||||
# dad355bcc1fcb9cdf2cf47ff524d2ad98cbf275e661bf4cf00960e74b5956b79
|
||||
# 9771334f426df007350b46049adb21a6e78ab1408d5e6ccde6fb5e69f0f4c92b
|
||||
# b9c725c02f99fa72b9cdc8dd53cff089e0e73317f61cc5abf6152513cb7d833f
|
||||
# 09d2851603919bf0fbe44d79a09245c6e8338eb502083dc84b846f2fee1cc310
|
||||
# d2cc8b1b9334728f97220bb799376233e113"""
|
||||
# ]
|
||||
# const expectText = [
|
||||
# """884c36f7ae6b406637c1f61b2f57e1d2cab813d24c6559aaf843c3f48962f32f
|
||||
# 46662c066d39669b7b2e3ba14781477417600e7728399278b1b5d801a519aa57
|
||||
# 0034fdb5419558137e0d44cd13d319afe5629eeccb47fd9dfe55cc6089426e46
|
||||
# cc762dd8a0636e07a54b31169eba0c7a20a1ac1ef68596f1f283b5c676bae406
|
||||
# 4abfcce24799d09f67e392632d3ffdc12e3d6430dcb0ea19c318343ffa7aae74
|
||||
# d4cd26fecb93657d1cd9e9eaf4f8be720b56dd1d39f190c4e1c6b7ec66f077bb
|
||||
# 1100""",
|
||||
# """802b052f8b066640bba94a4fc39d63815c377fced6fcb84d27f791c9921ddf3e
|
||||
# 9bf0108e298f490812847109cbd778fae393e80323fd643209841a3b7f110397
|
||||
# f37ec61d84cea03dcc5e8385db93248584e8af4b4d1c832d8c7453c0089687a7
|
||||
# 00"""
|
||||
# ]
|
||||
# var data: array[1024, byte]
|
||||
# var outlen = 0
|
||||
# for i in 0..1:
|
||||
# var s = secretKeys[i].getPrivateKey()
|
||||
# var cipher = fromHex(stripSpaces(cipherText[i]))
|
||||
# var expect = fromHex(stripSpaces(expectText[i]))
|
||||
# check:
|
||||
# eciesDecrypt(cipher, s, data, outlen) == EciesStatus.Success
|
||||
# outlen == len(expect)
|
||||
# compare(data, expect) == true
|
||||
|
||||
test "ECIES/cpp-ethereum rlpx.cpp#L432-L459":
|
||||
# ECIES
|
||||
# https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libp2p/rlpx.cpp#L432-L459
|
||||
const secretKeys = [
|
||||
"57baf2c62005ddec64c357d96183ebc90bf9100583280e848aa31d683cad73cb",
|
||||
"472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b",
|
||||
"472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b",
|
||||
"472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b"
|
||||
]
|
||||
const cipherData = [
|
||||
"""04ff2c874d0a47917c84eea0b2a4141ca95233720b5c70f81a8415bae1dc7b74
|
||||
6b61df7558811c1d6054333907333ef9bb0cc2fbf8b34abb9730d14e0140f455
|
||||
3f4b15d705120af46cf653a1dc5b95b312cf8444714f95a4f7a0425b67fc064d
|
||||
18f4d0a528761565ca02d97faffdac23de10""",
|
||||
"""046f647e1bd8a5cd1446d31513bac233e18bdc28ec0e59d46de453137a725995
|
||||
33f1e97c98154343420d5f16e171e5107999a7c7f1a6e26f57bcb0d2280655d0
|
||||
8fb148d36f1d4b28642d3bb4a136f0e33e3dd2e3cffe4b45a03fb7c5b5ea5e65
|
||||
617250fdc89e1a315563c20504b9d3a72555""",
|
||||
"""0443c24d6ccef3ad095140760bb143078b3880557a06392f17c5e368502d7953
|
||||
2bc18903d59ced4bbe858e870610ab0d5f8b7963dd5c9c4cf81128d10efd7c7a
|
||||
a80091563c273e996578403694673581829e25a865191bdc9954db14285b56eb
|
||||
0043b6288172e0d003c10f42fe413222e273d1d4340c38a2d8344d7aadcbc846
|
||||
ee""",
|
||||
"""04c4e40c86bb5324e017e598c6d48c19362ae527af8ab21b077284a4656c8735
|
||||
e62d73fb3d740acefbec30ca4c024739a1fcdff69ecaf03301eebf156eb5f17c
|
||||
ca6f9d7a7e214a1f3f6e34d1ee0ec00ce0ef7d2b242fbfec0f276e17941f9f1b
|
||||
fbe26de10a15a6fac3cda039904ddd1d7e06e7b96b4878f61860e47f0b84c8ce
|
||||
b64f6a900ff23844f4359ae49b44154980a626d3c73226c19e"""
|
||||
]
|
||||
const expectData = [
|
||||
"a", "a", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
]
|
||||
var data: array[1024, byte]
|
||||
var outlen = 0
|
||||
for i in 0..3:
|
||||
var s = secretKeys[i].getPrivateKey()
|
||||
var cipher = fromHex(stripSpaces(cipherData[i]))
|
||||
check:
|
||||
eciesDecrypt(cipher, s, data, outlen) == EciesStatus.Success
|
||||
outlen == len(expectData[i])
|
||||
compare(data, expectData[i]) == true
|
||||
# test "ECIES/cpp-ethereum rlpx.cpp#L432-L459":
|
||||
# # ECIES
|
||||
# # https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libp2p/rlpx.cpp#L432-L459
|
||||
# const secretKeys = [
|
||||
# "57baf2c62005ddec64c357d96183ebc90bf9100583280e848aa31d683cad73cb",
|
||||
# "472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b",
|
||||
# "472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b",
|
||||
# "472413e97f1fd58d84e28a559479e6b6902d2e8a0cee672ef38a3a35d263886b"
|
||||
# ]
|
||||
# const cipherData = [
|
||||
# """04ff2c874d0a47917c84eea0b2a4141ca95233720b5c70f81a8415bae1dc7b74
|
||||
# 6b61df7558811c1d6054333907333ef9bb0cc2fbf8b34abb9730d14e0140f455
|
||||
# 3f4b15d705120af46cf653a1dc5b95b312cf8444714f95a4f7a0425b67fc064d
|
||||
# 18f4d0a528761565ca02d97faffdac23de10""",
|
||||
# """046f647e1bd8a5cd1446d31513bac233e18bdc28ec0e59d46de453137a725995
|
||||
# 33f1e97c98154343420d5f16e171e5107999a7c7f1a6e26f57bcb0d2280655d0
|
||||
# 8fb148d36f1d4b28642d3bb4a136f0e33e3dd2e3cffe4b45a03fb7c5b5ea5e65
|
||||
# 617250fdc89e1a315563c20504b9d3a72555""",
|
||||
# """0443c24d6ccef3ad095140760bb143078b3880557a06392f17c5e368502d7953
|
||||
# 2bc18903d59ced4bbe858e870610ab0d5f8b7963dd5c9c4cf81128d10efd7c7a
|
||||
# a80091563c273e996578403694673581829e25a865191bdc9954db14285b56eb
|
||||
# 0043b6288172e0d003c10f42fe413222e273d1d4340c38a2d8344d7aadcbc846
|
||||
# ee""",
|
||||
# """04c4e40c86bb5324e017e598c6d48c19362ae527af8ab21b077284a4656c8735
|
||||
# e62d73fb3d740acefbec30ca4c024739a1fcdff69ecaf03301eebf156eb5f17c
|
||||
# ca6f9d7a7e214a1f3f6e34d1ee0ec00ce0ef7d2b242fbfec0f276e17941f9f1b
|
||||
# fbe26de10a15a6fac3cda039904ddd1d7e06e7b96b4878f61860e47f0b84c8ce
|
||||
# b64f6a900ff23844f4359ae49b44154980a626d3c73226c19e"""
|
||||
# ]
|
||||
# const expectData = [
|
||||
# "a", "a", "aaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
# ]
|
||||
# var data: array[1024, byte]
|
||||
# var outlen = 0
|
||||
# for i in 0..3:
|
||||
# var s = secretKeys[i].getPrivateKey()
|
||||
# var cipher = fromHex(stripSpaces(cipherData[i]))
|
||||
# check:
|
||||
# eciesDecrypt(cipher, s, data, outlen) == EciesStatus.Success
|
||||
# outlen == len(expectData[i])
|
||||
# compare(data, expectData[i]) == true
|
||||
|
Loading…
x
Reference in New Issue
Block a user