2018-03-28 03:17:01 +03:00
|
|
|
#
|
|
|
|
# Ethereum P2P
|
|
|
|
# (c) Copyright 2018
|
|
|
|
# Status Research & Development GmbH
|
|
|
|
#
|
|
|
|
# See the file "LICENSE", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
#
|
|
|
|
|
|
|
|
## This module implements ECIES method encryption/decryption.
|
|
|
|
|
|
|
|
import ecc, nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac
|
|
|
|
import nimcrypto/rijndael, nimcrypto/utils, nimcrypto/sysrand
|
|
|
|
import nimcrypto/bcmode, nimcrypto/utils
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
const
|
|
|
|
emptyMac* = array[0, byte]([])
|
|
|
|
|
2018-03-28 03:17:01 +03:00
|
|
|
type
|
|
|
|
EciesException* = object of Exception
|
|
|
|
EciesStatus* = enum
|
|
|
|
Success, ## Operation was successful
|
|
|
|
BufferOverrun, ## Output buffer size is too small
|
|
|
|
EmptyMessage, ## Attempt to encrypt/decrypt empty message
|
|
|
|
RandomError, ## Could not obtain random data
|
|
|
|
EcdhError, ## ECDH shared secret could not be calculated
|
|
|
|
IncorrectSize, ## ECIES data has incorrect size (size is too low)
|
|
|
|
WrongHeader, ## ECIES header is incorrect
|
|
|
|
IncorrectKey, ## Recovered public key is invalid
|
2018-03-29 23:53:19 +03:00
|
|
|
IncorrectTag, ## ECIES tag verification failed
|
|
|
|
IncompleteError ## Decryption needs more data
|
2018-03-28 17:29:41 +03:00
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
EciesHeader* = object {.packed.}
|
|
|
|
version*: byte
|
|
|
|
pubkey*: array[PublicKeyLength, byte]
|
|
|
|
iv*: array[aes128.sizeBlock, byte]
|
|
|
|
data*: byte
|
2018-03-28 17:29:41 +03:00
|
|
|
|
2018-03-28 03:17:01 +03:00
|
|
|
template eciesOverheadLength*(): int =
|
|
|
|
## Return data overhead size for ECIES encrypted message
|
|
|
|
1 + sizeof(PublicKey) + aes128.sizeBlock + sha256.sizeDigest
|
|
|
|
|
|
|
|
template eciesEncryptedLength*(size: int): int =
|
|
|
|
## Return size of encrypted message for message with size `size`.
|
|
|
|
size + eciesOverheadLength()
|
|
|
|
|
|
|
|
template eciesDecryptedLength*(size: int): int =
|
|
|
|
## Return size of decrypted message for encrypted message with size `size`.
|
|
|
|
size - eciesOverheadLength()
|
|
|
|
|
|
|
|
template eciesMacLength(size: int): int =
|
|
|
|
## Return size of authenticated data
|
|
|
|
size + aes128.sizeBlock
|
|
|
|
|
|
|
|
template eciesMacPos(size: int): int =
|
|
|
|
## Return position of MAC code in encrypted block
|
|
|
|
size - sha256.sizeDigest
|
|
|
|
|
|
|
|
template eciesDataPos(): int =
|
|
|
|
## Return position of encrypted data in block
|
2018-03-29 23:53:19 +03:00
|
|
|
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
|
2018-03-28 03:17:01 +03:00
|
|
|
|
|
|
|
proc kdf*(data: openarray[byte]): array[KeyLength, byte] {.noInit.} =
|
|
|
|
## NIST SP 800-56a Concatenation Key Derivation Function (see section 5.8.1)
|
|
|
|
var ctx: sha256
|
|
|
|
var counter: uint32
|
|
|
|
var counterLe: uint32
|
|
|
|
let reps = ((KeyLength + 7) * 8) div (int(ctx.sizeDigest) * 8)
|
|
|
|
var offset = 0
|
2018-03-28 17:29:41 +03:00
|
|
|
# REVIEW: There is a relationship between KeyLength and sha256.sizeDigest here
|
|
|
|
# that could be expressed in the code with a static assert.
|
2018-03-28 03:17:01 +03:00
|
|
|
var storage = newSeq[byte](KeyLength * (reps + 1))
|
|
|
|
while counter <= uint32(reps):
|
|
|
|
counter = counter + 1
|
|
|
|
counterLe = LSWAP(counter)
|
|
|
|
ctx.init()
|
|
|
|
ctx.update(cast[ptr byte](addr counterLe), uint(sizeof(uint32)))
|
|
|
|
ctx.update(unsafeAddr data[0], uint(len(data)))
|
2018-03-29 23:53:19 +03:00
|
|
|
var hash = ctx.finish()
|
|
|
|
copyMem(addr storage[offset], addr hash.data[0], ctx.sizeDigest)
|
2018-03-28 17:29:41 +03:00
|
|
|
offset += int(ctx.sizeDigest)
|
2018-03-29 23:53:19 +03:00
|
|
|
ctx.clear() # clean ctx
|
2018-03-28 03:17:01 +03:00
|
|
|
copyMem(addr result[0], addr storage[0], KeyLength)
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
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.
|
2018-03-28 03:17:01 +03:00
|
|
|
var
|
2018-03-29 23:53:19 +03:00
|
|
|
encKey: array[aes128.sizeKey, byte]
|
2018-03-28 03:17:01 +03:00
|
|
|
cipher: CTR[aes128]
|
|
|
|
ctx: HMAC[sha256]
|
|
|
|
iv: array[aes128.sizeBlock, byte]
|
|
|
|
secret: SharedSecret
|
|
|
|
material: array[KeyLength, byte]
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
if len(output) < eciesEncryptedLength(len(input)):
|
2018-03-28 03:17:01 +03:00
|
|
|
return(BufferOverrun)
|
2018-03-29 23:53:19 +03:00
|
|
|
if randomBytes(iv) != aes128.sizeBlock:
|
2018-03-28 03:17:01 +03:00
|
|
|
return(RandomError)
|
|
|
|
|
|
|
|
var ephemeral = newKeyPair()
|
|
|
|
var epub = ephemeral.pubkey.getRaw()
|
|
|
|
|
|
|
|
if ecdhAgree(ephemeral.seckey, pubkey, secret) != EccStatus.Success:
|
|
|
|
return(EcdhError)
|
|
|
|
|
|
|
|
material = kdf(secret)
|
2018-03-29 23:53:19 +03:00
|
|
|
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](addr output[0])
|
|
|
|
header.version = 0x04
|
|
|
|
header.pubkey = epub.data
|
|
|
|
header.iv = iv
|
|
|
|
|
|
|
|
var so = eciesDataPos()
|
|
|
|
var eo = so + len(input)
|
|
|
|
cipher.init(encKey, iv)
|
|
|
|
cipher.encrypt(input, toOpenArray(output, so, eo))
|
|
|
|
burnMem(encKey)
|
|
|
|
cipher.clear()
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
so = eciesTagPos(len(input))
|
|
|
|
copyMem(addr output[so], addr tag.data[0], ctx.sizeDigest)
|
|
|
|
ctx.clear()
|
2018-03-28 17:29:41 +03:00
|
|
|
|
2018-03-28 03:17:01 +03:00
|
|
|
result = Success
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
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.
|
2018-03-28 03:17:01 +03:00
|
|
|
var
|
|
|
|
pubkey: PublicKey
|
2018-03-29 23:53:19 +03:00
|
|
|
encKey: array[aes128.sizeKey, byte]
|
2018-03-28 03:17:01 +03:00
|
|
|
cipher: CTR[aes128]
|
|
|
|
ctx: HMAC[sha256]
|
|
|
|
secret: SharedSecret
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
if len(input) == 0:
|
|
|
|
return(IncompleteError)
|
2018-03-28 03:17:01 +03:00
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
var header = cast[ptr EciesHeader](unsafeAddr input[0])
|
|
|
|
if header.version != 0x04:
|
2018-03-28 03:17:01 +03:00
|
|
|
return(WrongHeader)
|
2018-03-29 23:53:19 +03:00
|
|
|
if len(input) <= eciesOverheadLength():
|
|
|
|
return(IncompleteError)
|
|
|
|
if len(input) - eciesOverheadLength() > len(output):
|
|
|
|
return(BufferOverrun)
|
|
|
|
if recoverPublicKey(header.pubkey, pubkey) != EccStatus.Success:
|
2018-03-28 03:17:01 +03:00
|
|
|
return(IncorrectKey)
|
|
|
|
if ecdhAgree(seckey, pubkey, secret) != EccStatus.Success:
|
|
|
|
return(EcdhError)
|
|
|
|
|
|
|
|
var material = kdf(secret)
|
2018-03-29 23:53:19 +03:00
|
|
|
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(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()
|
|
|
|
|
|
|
|
if not equalMem(addr tag.data[0], unsafeAddr input[eciesMacPos(len(input))],
|
|
|
|
sha256.sizeDigest):
|
2018-03-28 03:17:01 +03:00
|
|
|
return(IncorrectTag)
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
cipher.init(encKey, header.iv)
|
|
|
|
burnMem(encKey)
|
|
|
|
cipher.decrypt(toOpenArray(input, eciesDataPos(), eciesDataPos() + datsize),
|
|
|
|
output)
|
|
|
|
cipher.clear()
|
2018-03-28 03:17:01 +03:00
|
|
|
result = Success
|
|
|
|
|
2018-03-29 23:53:19 +03:00
|
|
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
# var
|
|
|
|
# encKey: array[aes128.sizeKey, byte]
|
|
|
|
# cipher: CTR[aes128]
|
|
|
|
# ctx: HMAC[sha256]
|
|
|
|
# iv: array[aes128.sizeBlock, 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):
|
|
|
|
# return(BufferOverrun)
|
|
|
|
# if randomBytes(addr iv[0], len(iv)) != len(iv):
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
# 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))
|