Add more primitives for SecIO.
Fix SIGSEGV inside of rsa.nim and ecnist.nim.
This commit is contained in:
parent
f2b10776db
commit
7138f7e94d
|
@ -8,14 +8,15 @@
|
|||
## those terms.
|
||||
|
||||
## This module implements Public Key and Private Key interface for libp2p.
|
||||
import strutils
|
||||
import rsa, ecnist, ed25519/ed25519, secp
|
||||
import ../protobuf/minprotobuf, ../vbuffer
|
||||
import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec
|
||||
import nimcrypto/[rijndael, blowfish, sha, sha2, hash, hmac, utils]
|
||||
|
||||
# This is workaround for Nim's `import` bug
|
||||
export rijndael, blowfish, sha, sha2, hash, hmac, utils
|
||||
|
||||
from strutils import split
|
||||
|
||||
type
|
||||
PKScheme* = enum
|
||||
RSA = 0,
|
||||
|
@ -463,7 +464,7 @@ proc verify*(sig: Signature, message: openarray[byte],
|
|||
if signature.init(sig.data):
|
||||
result = signature.verify(message, key.skkey)
|
||||
|
||||
template makeSecret(buffer, hmactype, secret, seed) =
|
||||
template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}=
|
||||
var ctx: hmactype
|
||||
var j = 0
|
||||
# We need to strip leading zeros, because Go bigint serialization do it.
|
||||
|
@ -489,16 +490,16 @@ template makeSecret(buffer, hmactype, secret, seed) =
|
|||
ctx.update(a.data)
|
||||
a = ctx.finish()
|
||||
|
||||
proc stretchKeys*(cipherScheme: CipherScheme, hashScheme: DigestSheme,
|
||||
secret: openarray[byte]): Secret =
|
||||
proc stretchKeys*(cipherType: string, hashType: string,
|
||||
sharedSecret: seq[byte]): Secret =
|
||||
## Expand shared secret to cryptographic keys.
|
||||
if cipherScheme == Aes128:
|
||||
if cipherType == "AES-128":
|
||||
result.ivsize = aes128.sizeBlock
|
||||
result.keysize = aes128.sizeKey
|
||||
elif cipherScheme == Aes256:
|
||||
elif cipherType == "AES-256":
|
||||
result.ivsize = aes256.sizeBlock
|
||||
result.keysize = aes256.sizeKey
|
||||
elif cipherScheme == Blowfish:
|
||||
elif cipherType == "BLOWFISH":
|
||||
result.ivsize = 8
|
||||
result.keysize = 32
|
||||
|
||||
|
@ -507,12 +508,12 @@ proc stretchKeys*(cipherScheme: CipherScheme, hashScheme: DigestSheme,
|
|||
let length = result.ivsize + result.keysize + result.macsize
|
||||
result.data = newSeq[byte](2 * length)
|
||||
|
||||
if hashScheme == Sha256:
|
||||
makeSecret(result.data, HMAC[sha256], secret, seed)
|
||||
elif hashScheme == Sha512:
|
||||
makeSecret(result.data, HMAC[sha512], secret, seed)
|
||||
elif hashScheme == Sha1:
|
||||
makeSecret(result.data, HMAC[sha1], secret, seed)
|
||||
if hashType == "SHA256":
|
||||
makeSecret(result.data, HMAC[sha256], sharedSecret, seed)
|
||||
elif hashType == "SHA512":
|
||||
makeSecret(result.data, HMAC[sha512], sharedSecret, seed)
|
||||
elif hashType == "SHA1":
|
||||
makeSecret(result.data, HMAC[sha1], sharedSecret, seed)
|
||||
|
||||
template goffset*(secret, id, o: untyped): untyped =
|
||||
id * (len(secret.data) shr 1) + o
|
||||
|
@ -561,11 +562,27 @@ proc ephemeral*(scheme: ECDHEScheme): KeyPair =
|
|||
result.seckey.eckey = keypair.seckey
|
||||
result.pubkey.eckey = keypair.pubkey
|
||||
|
||||
proc ephemeral*(scheme: string): KeyPair {.inline.} =
|
||||
## Generate ephemeral keys used to perform ECDHE using string encoding.
|
||||
##
|
||||
## Currently supported encoding strings are P-256, P-384, P-521, if encoding
|
||||
## string is not supported P-521 key will be generated.
|
||||
if scheme == "P-256":
|
||||
result = ephemeral(Secp256r1)
|
||||
elif scheme == "P-384":
|
||||
result = ephemeral(Secp384r1)
|
||||
elif scheme == "P-521":
|
||||
result = ephemeral(Secp521r1)
|
||||
else:
|
||||
result = ephemeral(Secp521r1)
|
||||
|
||||
proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey,
|
||||
data: var openarray[byte]): int =
|
||||
## Calculate shared secret using remote ephemeral public key
|
||||
## ``remoteEPublic`` and local ephemeral private key ``localEPrivate`` and
|
||||
## store shared secret to ``data``
|
||||
## store shared secret to ``data``.
|
||||
##
|
||||
## Note this procedure supports only ECDSA keys.
|
||||
##
|
||||
## Returns number of bytes (octets) used to store shared secret data, or
|
||||
## ``0`` on error.
|
||||
|
@ -573,6 +590,19 @@ proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey,
|
|||
if localEPrivate.scheme == remoteEPublic.scheme:
|
||||
result = toSecret(remoteEPublic.eckey, localEPrivate.eckey, data)
|
||||
|
||||
proc getSecret*(remoteEPublic: PublicKey,
|
||||
localEPrivate: PrivateKey): seq[byte] =
|
||||
## Calculate shared secret using remote ephemeral public key
|
||||
## ``remoteEPublic`` and local ephemeral private key ``localEPrivate`` and
|
||||
## store shared secret to ``data``.
|
||||
##
|
||||
## Note this procedure supports only ECDSA keys.
|
||||
##
|
||||
## Returns shared secret on success.
|
||||
if remoteEPublic.scheme == ECDSA:
|
||||
if localEPrivate.scheme == remoteEPublic.scheme:
|
||||
result = getSecret(remoteEPublic.eckey, localEPrivate.eckey)
|
||||
|
||||
proc getOrder*(remotePubkey, localNonce: openarray[byte],
|
||||
localPubkey, remoteNonce: openarray[byte]): int =
|
||||
## Compare values and calculate `order` parameter.
|
||||
|
@ -585,10 +615,16 @@ proc getOrder*(remotePubkey, localNonce: openarray[byte],
|
|||
ctx.update(localPubkey)
|
||||
ctx.update(remoteNonce)
|
||||
var digest2 = ctx.finish()
|
||||
var diff = 0
|
||||
for i in 0 ..< len(digest1.data):
|
||||
diff = int(digest1.data[i]) - int(digest2.data[i])
|
||||
result = (result and -not(diff)) or diff
|
||||
var mh1 = MultiHash.init(multiCodec("sha2-256"), digest1)
|
||||
var mh2 = MultiHash.init(multiCodec("sha2-256"), digest2)
|
||||
for i in 0 ..< len(mh1.data.buffer):
|
||||
result = int(mh1.data.buffer[i]) - int(mh2.data.buffer[i])
|
||||
if result != 0:
|
||||
if result > 0:
|
||||
result = -1
|
||||
elif result > 0:
|
||||
result = 1
|
||||
break
|
||||
|
||||
proc selectBest*(order: int, p1, p2: string): string =
|
||||
## Determines which algorithm to use from list `p1` and `p2`.
|
||||
|
@ -610,10 +646,14 @@ proc selectBest*(order: int, p1, p2: string): string =
|
|||
for selement in s:
|
||||
if felement == selement:
|
||||
result = felement
|
||||
break
|
||||
return
|
||||
|
||||
proc createProposal*(nonce, pubkey: openarray[byte],
|
||||
exchanges, ciphers, hashes: string): seq[byte] =
|
||||
## Create SecIO proposal message using random ``nonce``, local public key
|
||||
## ``pubkey``, comma-delimieted list of supported exchange schemes
|
||||
## ``exchanges``, comma-delimeted list of supported ciphers ``ciphers`` and
|
||||
## comma-delimeted list of supported hashes ``hashes``.
|
||||
var msg = initProtoBuffer({WithUint32BeLength})
|
||||
msg.write(initProtoField(1, nonce))
|
||||
msg.write(initProtoField(2, pubkey))
|
||||
|
@ -623,13 +663,42 @@ proc createProposal*(nonce, pubkey: openarray[byte],
|
|||
msg.finish()
|
||||
shallowCopy(result, msg.buffer)
|
||||
|
||||
proc decodeProposal*(message: seq[byte], nonce, pubkey: var seq[byte],
|
||||
exchanges, ciphers, hashes: var string): bool =
|
||||
## Parse incoming proposal message and decode remote random nonce ``nonce``,
|
||||
## remote public key ``pubkey``, comma-delimieted list of supported exchange
|
||||
## schemes ``exchanges``, comma-delimeted list of supported ciphers
|
||||
## ``ciphers`` and comma-delimeted list of supported hashes ``hashes``.
|
||||
##
|
||||
## Procedure returns ``true`` on success and ``false`` on error.
|
||||
var pb = initProtoBuffer(message)
|
||||
if pb.getLengthValue(1, nonce) != -1 and
|
||||
pb.getLengthValue(2, pubkey) != -1 and
|
||||
pb.getLengthValue(3, exchanges) != -1 and
|
||||
pb.getLengthValue(4, ciphers) != -1 and
|
||||
pb.getLengthValue(5, hashes) != -1:
|
||||
result = true
|
||||
|
||||
proc createExchange*(epubkey, signature: openarray[byte]): seq[byte] =
|
||||
## Create SecIO exchange message using ephemeral public key ``epubkey`` and
|
||||
## signature of proposal blocks ``signature``.
|
||||
var msg = initProtoBuffer({WithUint32BeLength})
|
||||
msg.write(initProtoField(1, epubkey))
|
||||
msg.write(initProtoField(2, signature))
|
||||
msg.finish()
|
||||
shallowCopy(result, msg.buffer)
|
||||
|
||||
proc decodeExchange*(message: seq[byte],
|
||||
pubkey, signature: var seq[byte]): bool =
|
||||
## Parse incoming exchange message and decode remote ephemeral public key
|
||||
## ``pubkey`` and signature ``signature``.
|
||||
##
|
||||
## Procedure returns ``true`` on success and ``false`` on error.
|
||||
var pb = initProtoBuffer(message)
|
||||
if pb.getLengthValue(1, pubkey) != -1 and
|
||||
pb.getLengthValue(2, signature) != -1:
|
||||
result = true
|
||||
|
||||
## Serialization/Deserialization helpers
|
||||
|
||||
proc write*(vb: var VBuffer, pubkey: PublicKey) {.inline.} =
|
||||
|
|
|
@ -141,36 +141,48 @@ template getPublicKeyLength*(curve: EcCurveKind): int =
|
|||
of Secp521r1:
|
||||
PubKey521Length
|
||||
|
||||
template getPrivateKeyLength*(curve: EcCurveKind): int =
|
||||
case curve
|
||||
of Secp256r1:
|
||||
SecKey256Length
|
||||
of Secp384r1:
|
||||
SecKey384Length
|
||||
of Secp521r1:
|
||||
SecKey521Length
|
||||
|
||||
proc copy*[T: EcPKI](dst: var T, src: T): bool =
|
||||
## Copy EC `private key`, `public key` or `signature` ``src`` to ``dst``.
|
||||
##
|
||||
## Returns ``true`` on success, ``false`` otherwise.
|
||||
dst = new T
|
||||
when T is EcPrivateKey:
|
||||
let length = src.key.xlen
|
||||
if length > 0 and len(src.buffer) > 0:
|
||||
let offset = getOffset(src)
|
||||
if offset >= 0:
|
||||
dst.buffer = src.buffer
|
||||
dst.key.curve = src.key.curve
|
||||
dst.key.xlen = length
|
||||
dst.key.x = cast[ptr cuchar](addr dst.buffer[offset])
|
||||
result = true
|
||||
elif T is EcPublicKey:
|
||||
let length = src.key.qlen
|
||||
if length > 0 and len(src.buffer) > 0:
|
||||
let offset = getOffset(src)
|
||||
if offset >= 0:
|
||||
dst.buffer = src.buffer
|
||||
dst.key.curve = src.key.curve
|
||||
dst.key.qlen = length
|
||||
dst.key.q = cast[ptr cuchar](addr dst.buffer[offset])
|
||||
result = true
|
||||
if isNil(src):
|
||||
result = false
|
||||
else:
|
||||
let length = len(src.buffer)
|
||||
if length > 0:
|
||||
dst.buffer = src.buffer
|
||||
result = true
|
||||
dst = new T
|
||||
when T is EcPrivateKey:
|
||||
let length = src.key.xlen
|
||||
if length > 0 and len(src.buffer) > 0:
|
||||
let offset = getOffset(src)
|
||||
if offset >= 0:
|
||||
dst.buffer = src.buffer
|
||||
dst.key.curve = src.key.curve
|
||||
dst.key.xlen = length
|
||||
dst.key.x = cast[ptr cuchar](addr dst.buffer[offset])
|
||||
result = true
|
||||
elif T is EcPublicKey:
|
||||
let length = src.key.qlen
|
||||
if length > 0 and len(src.buffer) > 0:
|
||||
let offset = getOffset(src)
|
||||
if offset >= 0:
|
||||
dst.buffer = src.buffer
|
||||
dst.key.curve = src.key.curve
|
||||
dst.key.qlen = length
|
||||
dst.key.q = cast[ptr cuchar](addr dst.buffer[offset])
|
||||
result = true
|
||||
else:
|
||||
let length = len(src.buffer)
|
||||
if length > 0:
|
||||
dst.buffer = src.buffer
|
||||
result = true
|
||||
|
||||
proc copy*[T: EcPKI](src: T): T {.inline.} =
|
||||
## Returns copy of EC `private key`, `public key` or `signature`
|
||||
|
@ -180,6 +192,7 @@ proc copy*[T: EcPKI](src: T): T {.inline.} =
|
|||
|
||||
proc clear*[T: EcPKI|EcKeyPair](pki: var T) =
|
||||
## Wipe and clear EC `private key`, `public key` or `signature` object.
|
||||
doAssert(not isNil(pki))
|
||||
when T is EcPrivateKey:
|
||||
burnMem(pki.buffer)
|
||||
pki.buffer.setLen(0)
|
||||
|
@ -228,6 +241,7 @@ proc random*(t: typedesc[EcPrivateKey], kind: EcCurveKind): EcPrivateKey =
|
|||
|
||||
proc getKey*(seckey: EcPrivateKey): EcPublicKey =
|
||||
## Calculate and return EC public key from private key ``seckey``.
|
||||
doAssert(not isNil(seckey))
|
||||
var ecimp = brEcGetDefault()
|
||||
if seckey.key.curve in EcSupportedCurvesCint:
|
||||
var length = getPublicKeyLength(cast[EcCurveKind](seckey.key.curve))
|
||||
|
@ -250,8 +264,9 @@ proc random*(t: typedesc[EcKeyPair], kind: EcCurveKind): EcKeyPair {.inline.} =
|
|||
|
||||
proc `$`*(seckey: EcPrivateKey): string =
|
||||
## Return string representation of EC private key.
|
||||
if seckey.key.curve == 0 or seckey.key.xlen == 0 or len(seckey.buffer) == 0:
|
||||
result = "Empty key"
|
||||
if isNil(seckey) or seckey.key.curve == 0 or seckey.key.xlen == 0 or
|
||||
len(seckey.buffer) == 0:
|
||||
result = "Empty or uninitialized ECNIST key"
|
||||
else:
|
||||
if seckey.key.curve notin EcSupportedCurvesCint:
|
||||
result = "Unknown key"
|
||||
|
@ -265,8 +280,9 @@ proc `$`*(seckey: EcPrivateKey): string =
|
|||
|
||||
proc `$`*(pubkey: EcPublicKey): string =
|
||||
## Return string representation of EC public key.
|
||||
if pubkey.key.curve == 0 or pubkey.key.qlen == 0 or len(pubkey.buffer) == 0:
|
||||
result = "Empty key"
|
||||
if isNil(pubkey) or pubkey.key.curve == 0 or pubkey.key.qlen == 0 or
|
||||
len(pubkey.buffer) == 0:
|
||||
result = "Empty or uninitialized ECNIST key"
|
||||
else:
|
||||
if pubkey.key.curve notin EcSupportedCurvesCint:
|
||||
result = "Unknown key"
|
||||
|
@ -280,7 +296,45 @@ proc `$`*(pubkey: EcPublicKey): string =
|
|||
|
||||
proc `$`*(sig: EcSignature): string =
|
||||
## Return hexadecimal string representation of EC signature.
|
||||
result = toHex(sig.buffer)
|
||||
if isNil(sig) or len(sig.buffer) == 0:
|
||||
result = "Empty or uninitialized ECNIST signature"
|
||||
else:
|
||||
result = toHex(sig.buffer)
|
||||
|
||||
proc toRawBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int =
|
||||
## Serialize EC private key ``seckey`` to raw binary form and store it
|
||||
## to ``data``.
|
||||
##
|
||||
## Returns number of bytes (octets) needed to store EC private key, or `0`
|
||||
## if private key is not in supported curve.
|
||||
doAssert(not isNil(seckey))
|
||||
if seckey.key.curve in EcSupportedCurvesCint:
|
||||
result = getPrivateKeyLength(cast[EcCurveKind](seckey.key.curve))
|
||||
if len(data) >= result:
|
||||
copyMem(addr data[0], unsafeAddr seckey.buffer[0], result)
|
||||
|
||||
proc toRawBytes*(pubkey: EcPublicKey, data: var openarray[byte]): int =
|
||||
## Serialize EC public key ``pubkey`` to uncompressed form specified in
|
||||
## section 4.3.6 of ANSI X9.62.
|
||||
##
|
||||
## Returns number of bytes (octets) needed to store EC public key, or `0`
|
||||
## if public key is not in supported curve.
|
||||
doAssert(not isNil(pubkey))
|
||||
if pubkey.key.curve in EcSupportedCurvesCint:
|
||||
result = getPublicKeyLength(cast[EcCurveKind](pubkey.key.curve))
|
||||
if len(data) >= result:
|
||||
copyMem(addr data[0], unsafeAddr pubkey.buffer[0], result)
|
||||
|
||||
proc toRawBytes*(sig: EcSignature, data: var openarray[byte]): int =
|
||||
## Serialize EC signature ``sig`` to raw binary form and store it to ``data``.
|
||||
##
|
||||
## Returns number of bytes (octets) needed to store EC signature, or `0`
|
||||
## if signature is not in supported curve.
|
||||
doAssert(not isNil(sig))
|
||||
result = len(sig.buffer)
|
||||
if len(data) >= len(sig.buffer):
|
||||
if len(sig.buffer) > 0:
|
||||
copyMem(addr data[0], unsafeAddr sig.buffer[0], len(sig.buffer))
|
||||
|
||||
proc toBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int =
|
||||
## Serialize EC private key ``seckey`` to ASN.1 DER binary form and store it
|
||||
|
@ -288,6 +342,7 @@ proc toBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store EC private key,
|
||||
## or `0` if private key is not in supported curve.
|
||||
doAssert(not isNil(seckey))
|
||||
if seckey.key.curve in EcSupportedCurvesCint:
|
||||
var offset, length: int
|
||||
var pubkey = seckey.getKey()
|
||||
|
@ -327,6 +382,7 @@ proc toBytes*(pubkey: EcPublicKey, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store EC public key,
|
||||
## or `0` if public key is not in supported curve.
|
||||
doAssert(not isNil(pubkey))
|
||||
if pubkey.key.curve in EcSupportedCurvesCint:
|
||||
var b = Asn1Buffer.init()
|
||||
var p = Asn1Composite.init(Asn1Tag.Sequence)
|
||||
|
@ -357,12 +413,14 @@ proc toBytes*(sig: EcSignature, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store EC signature,
|
||||
## or `0` if signature is not in supported curve.
|
||||
doAssert(not isNil(sig))
|
||||
result = len(sig.buffer)
|
||||
if len(data) >= result:
|
||||
copyMem(addr data[0], unsafeAddr sig.buffer[0], result)
|
||||
|
||||
proc getBytes*(seckey: EcPrivateKey): seq[byte] =
|
||||
## Serialize EC private key ``seckey`` to ASN.1 DER binary form and return it.
|
||||
doAssert(not isNil(seckey))
|
||||
if seckey.key.curve in EcSupportedCurvesCint:
|
||||
result = newSeq[byte]()
|
||||
let length = seckey.toBytes(result)
|
||||
|
@ -373,6 +431,7 @@ proc getBytes*(seckey: EcPrivateKey): seq[byte] =
|
|||
|
||||
proc getBytes*(pubkey: EcPublicKey): seq[byte] =
|
||||
## Serialize EC public key ``pubkey`` to ASN.1 DER binary form and return it.
|
||||
doAssert(not isNil(pubkey))
|
||||
if pubkey.key.curve in EcSupportedCurvesCint:
|
||||
result = newSeq[byte]()
|
||||
let length = pubkey.toBytes(result)
|
||||
|
@ -383,6 +442,37 @@ proc getBytes*(pubkey: EcPublicKey): seq[byte] =
|
|||
|
||||
proc getBytes*(sig: EcSignature): seq[byte] =
|
||||
## Serialize EC signature ``sig`` to ASN.1 DER binary form and return it.
|
||||
doAssert(not isNil(sig))
|
||||
result = newSeq[byte]()
|
||||
let length = sig.toBytes(result)
|
||||
result.setLen(length)
|
||||
discard sig.toBytes(result)
|
||||
|
||||
proc getRawBytes*(seckey: EcPrivateKey): seq[byte] =
|
||||
## Serialize EC private key ``seckey`` to raw binary form and return it.
|
||||
doAssert(not isNil(seckey))
|
||||
if seckey.key.curve in EcSupportedCurvesCint:
|
||||
result = newSeq[byte]()
|
||||
let length = seckey.toRawBytes(result)
|
||||
result.setLen(length)
|
||||
discard seckey.toRawBytes(result)
|
||||
else:
|
||||
raise newException(EcKeyIncorrectError, "Incorrect private key")
|
||||
|
||||
proc getRawBytes*(pubkey: EcPublicKey): seq[byte] =
|
||||
## Serialize EC public key ``pubkey`` to raw binary form and return it.
|
||||
doAssert(not isNil(pubkey))
|
||||
if pubkey.key.curve in EcSupportedCurvesCint:
|
||||
result = newSeq[byte]()
|
||||
let length = pubkey.toRawBytes(result)
|
||||
result.setLen(length)
|
||||
discard pubkey.toRawBytes(result)
|
||||
else:
|
||||
raise newException(EcKeyIncorrectError, "Incorrect public key")
|
||||
|
||||
proc getRawBytes*(sig: EcSignature): seq[byte] =
|
||||
## Serialize EC signature ``sig`` to raw binary form and return it.
|
||||
doAssert(not isNil(sig))
|
||||
result = newSeq[byte]()
|
||||
let length = sig.toBytes(result)
|
||||
result.setLen(length)
|
||||
|
@ -390,33 +480,54 @@ proc getBytes*(sig: EcSignature): seq[byte] =
|
|||
|
||||
proc `==`*(pubkey1, pubkey2: EcPublicKey): bool =
|
||||
## Returns ``true`` if both keys ``pubkey1`` and ``pubkey2`` are equal.
|
||||
if pubkey1.key.curve != pubkey2.key.curve:
|
||||
return false
|
||||
if pubkey1.key.qlen != pubkey2.key.qlen:
|
||||
return false
|
||||
let op1 = pubkey1.getOffset()
|
||||
let op2 = pubkey2.getOffset()
|
||||
if op1 == -1 or op2 == -1:
|
||||
return false
|
||||
result = equalMem(unsafeAddr pubkey1.buffer[op1],
|
||||
unsafeAddr pubkey2.buffer[op2], pubkey1.key.qlen)
|
||||
if isNil(pubkey1) and isNil(pubkey2):
|
||||
result = true
|
||||
elif isNil(pubkey1) and (not isNil(pubkey2)):
|
||||
result = false
|
||||
elif isNil(pubkey2) and (not isNil(pubkey1)):
|
||||
result = false
|
||||
else:
|
||||
if pubkey1.key.curve != pubkey2.key.curve:
|
||||
return false
|
||||
if pubkey1.key.qlen != pubkey2.key.qlen:
|
||||
return false
|
||||
let op1 = pubkey1.getOffset()
|
||||
let op2 = pubkey2.getOffset()
|
||||
if op1 == -1 or op2 == -1:
|
||||
return false
|
||||
result = equalMem(unsafeAddr pubkey1.buffer[op1],
|
||||
unsafeAddr pubkey2.buffer[op2], pubkey1.key.qlen)
|
||||
|
||||
proc `==`*(seckey1, seckey2: EcPrivateKey): bool =
|
||||
## Returns ``true`` if both keys ``seckey1`` and ``seckey2`` are equal.
|
||||
if seckey1.key.curve != seckey2.key.curve:
|
||||
return false
|
||||
if seckey1.key.xlen != seckey2.key.xlen:
|
||||
return false
|
||||
let op1 = seckey1.getOffset()
|
||||
let op2 = seckey2.getOffset()
|
||||
if op1 == -1 or op2 == -1:
|
||||
return false
|
||||
result = equalMem(unsafeAddr seckey1.buffer[op1],
|
||||
unsafeAddr seckey2.buffer[op2], seckey1.key.xlen)
|
||||
if isNil(seckey1) and isNil(seckey2):
|
||||
result = true
|
||||
elif isNil(seckey1) and (not isNil(seckey2)):
|
||||
result = false
|
||||
elif isNil(seckey2) and (not isNil(seckey1)):
|
||||
result = false
|
||||
else:
|
||||
if seckey1.key.curve != seckey2.key.curve:
|
||||
return false
|
||||
if seckey1.key.xlen != seckey2.key.xlen:
|
||||
return false
|
||||
let op1 = seckey1.getOffset()
|
||||
let op2 = seckey2.getOffset()
|
||||
if op1 == -1 or op2 == -1:
|
||||
return false
|
||||
result = equalMem(unsafeAddr seckey1.buffer[op1],
|
||||
unsafeAddr seckey2.buffer[op2], seckey1.key.xlen)
|
||||
|
||||
proc `==`*(sig1, sig2: EcSignature): bool =
|
||||
## Return ``true`` if both signatures ``sig1`` and ``sig2`` are equal.
|
||||
result = (sig1.buffer == sig2.buffer)
|
||||
if isNil(sig1) and isNil(sig2):
|
||||
result = true
|
||||
elif isNil(sig1) and (not isNil(sig2)):
|
||||
result = false
|
||||
elif isNil(sig2) and (not isNil(sig1)):
|
||||
result = false
|
||||
else:
|
||||
result = (sig1.buffer == sig2.buffer)
|
||||
|
||||
proc init*(key: var EcPrivateKey, data: openarray[byte]): Asn1Status =
|
||||
## Initialize EC `private key` or `signature` ``key`` from ASN.1 DER binary
|
||||
|
@ -698,6 +809,7 @@ proc scalarMul*(pub: EcPublicKey, sec: EcPrivateKey): EcPublicKey =
|
|||
## Return scalar multiplication of ``pub`` and ``sec``.
|
||||
##
|
||||
## Returns point in curve as ``pub * sec`` or ``nil`` otherwise.
|
||||
doAssert((not isNil(pub)) and (not isNil(sec)))
|
||||
var impl = brEcGetDefault()
|
||||
if sec.key.curve in EcSupportedCurvesCint:
|
||||
if pub.key.curve == sec.key.curve:
|
||||
|
@ -726,6 +838,7 @@ proc toSecret*(pubkey: EcPublicKey, seckey: EcPrivateKey,
|
|||
##
|
||||
## ``data`` array length must be at least 32 bytes for `secp256r1`, 48 bytes
|
||||
## for `secp384r1` and 66 bytes for `secp521r1`.
|
||||
doAssert((not isNil(pubkey)) and (not isNil(seckey)))
|
||||
var mult = scalarMul(pubkey, seckey)
|
||||
var length = 0
|
||||
if not isNil(mult):
|
||||
|
@ -745,6 +858,7 @@ proc getSecret*(pubkey: EcPublicKey, seckey: EcPrivateKey): seq[byte] =
|
|||
## shared secret.
|
||||
##
|
||||
## If error happens length of result array will be ``0``.
|
||||
doAssert((not isNil(pubkey)) and (not isNil(seckey)))
|
||||
var data: array[Secret521Length, byte]
|
||||
let res = toSecret(pubkey, seckey, data)
|
||||
if res > 0:
|
||||
|
@ -754,6 +868,7 @@ proc getSecret*(pubkey: EcPublicKey, seckey: EcPrivateKey): seq[byte] =
|
|||
proc sign*[T: byte|char](seckey: EcPrivateKey,
|
||||
message: openarray[T]): EcSignature =
|
||||
## Get ECDSA signature of data ``message`` using private key ``seckey``.
|
||||
doAssert(not isNil(seckey))
|
||||
var hc: BrHashCompatContext
|
||||
var hash: array[32, byte]
|
||||
var impl = brEcGetDefault()
|
||||
|
@ -785,6 +900,7 @@ proc verify*[T: byte|char](sig: EcSignature, message: openarray[T],
|
|||
##
|
||||
## Return ``true`` if message verification succeeded, ``false`` if
|
||||
## verification failed.
|
||||
doAssert((not isNil(sig)) and (not isNil(pubkey)))
|
||||
var hc: BrHashCompatContext
|
||||
var hash: array[32, byte]
|
||||
var impl = brEcGetDefault()
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
## This module uses unmodified parts of code from
|
||||
## BearSSL library <https://bearssl.org/>
|
||||
## Copyright(C) 2018 Thomas Pornin <pornin@bolet.org>.
|
||||
|
||||
import nimcrypto/utils
|
||||
import common, minasn1
|
||||
export Asn1Status
|
||||
|
@ -160,6 +159,7 @@ proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize,
|
|||
|
||||
proc copy*[T: RsaPKI](key: T): T =
|
||||
## Create copy of RSA private key, public key or signature.
|
||||
doAssert(not isNil(key))
|
||||
when T is RsaPrivateKey:
|
||||
if len(key.buffer) > 0:
|
||||
let length = key.seck.plen + key.seck.qlen + key.seck.dplen +
|
||||
|
@ -220,6 +220,7 @@ proc copy*[T: RsaPKI](key: T): T =
|
|||
|
||||
proc getKey*(key: RsaPrivateKey): RsaPublicKey =
|
||||
## Get RSA public key from RSA private key.
|
||||
doAssert(not isNil(key))
|
||||
let length = key.pubk.nlen + key.pubk.elen
|
||||
result = new RsaPublicKey
|
||||
result.buffer = newSeq[byte](length)
|
||||
|
@ -241,6 +242,7 @@ proc pubkey*(pair: RsaKeyPair): RsaPublicKey {.inline.} =
|
|||
|
||||
proc clear*[T: RsaPKI|RsaKeyPair](pki: var T) =
|
||||
## Wipe and clear EC private key, public key or scalar object.
|
||||
doAssert(not isNil(pki))
|
||||
when T is RsaPrivateKey:
|
||||
burnMem(pki.buffer)
|
||||
pki.buffer.setLen(0)
|
||||
|
@ -276,6 +278,7 @@ proc toBytes*(key: RsaPrivateKey, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store RSA private key,
|
||||
## or `0` if private key is is incorrect.
|
||||
doAssert(not isNil(key))
|
||||
if len(key.buffer) > 0:
|
||||
var b = Asn1Buffer.init()
|
||||
var p = Asn1Composite.init(Asn1Tag.Sequence)
|
||||
|
@ -308,6 +311,7 @@ proc toBytes*(key: RsaPublicKey, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store RSA public key,
|
||||
## or `0` if public key is incorrect.
|
||||
doAssert(not isNil(key))
|
||||
if len(key.buffer) > 0:
|
||||
var b = Asn1Buffer.init()
|
||||
var p = Asn1Composite.init(Asn1Tag.Sequence)
|
||||
|
@ -337,6 +341,7 @@ proc toBytes*(sig: RsaSignature, data: var openarray[byte]): int =
|
|||
##
|
||||
## Procedure returns number of bytes (octets) needed to store RSA public key,
|
||||
## or `0` if public key is incorrect.
|
||||
doAssert(not isNil(sig))
|
||||
result = len(sig.buffer)
|
||||
if len(data) >= result:
|
||||
copyMem(addr data[0], addr sig.buffer[0], result)
|
||||
|
@ -344,6 +349,7 @@ proc toBytes*(sig: RsaSignature, data: var openarray[byte]): int =
|
|||
proc getBytes*(key: RsaPrivateKey): seq[byte] =
|
||||
## Serialize RSA private key ``key`` to ASN.1 DER binary form and
|
||||
## return it.
|
||||
doAssert(not isNil(key))
|
||||
result = newSeq[byte](4096)
|
||||
let length = key.toBytes(result)
|
||||
if length > 0:
|
||||
|
@ -354,6 +360,7 @@ proc getBytes*(key: RsaPrivateKey): seq[byte] =
|
|||
proc getBytes*(key: RsaPublicKey): seq[byte] =
|
||||
## Serialize RSA public key ``key`` to ASN.1 DER binary form and
|
||||
## return it.
|
||||
doAssert(not isNil(key))
|
||||
result = newSeq[byte](4096)
|
||||
let length = key.toBytes(result)
|
||||
if length > 0:
|
||||
|
@ -363,6 +370,7 @@ proc getBytes*(key: RsaPublicKey): seq[byte] =
|
|||
|
||||
proc getBytes*(sig: RsaSignature): seq[byte] =
|
||||
## Serialize RSA signature ``sig`` to raw binary form and return it.
|
||||
doAssert(not isNil(sig))
|
||||
result = newSeq[byte](4096)
|
||||
let length = sig.toBytes(result)
|
||||
if length > 0:
|
||||
|
@ -592,8 +600,8 @@ proc init*[T: RsaPKI](t: typedesc[T], data: string): T {.inline.} =
|
|||
|
||||
proc `$`*(key: RsaPrivateKey): string =
|
||||
## Return string representation of RSA private key.
|
||||
if len(key.buffer) == 0:
|
||||
result = "Empty RSA key"
|
||||
if isNil(key) or len(key.buffer) == 0:
|
||||
result = "Empty or uninitialized RSA key"
|
||||
else:
|
||||
result = "RSA key ("
|
||||
result.add($key.seck.nBitlen)
|
||||
|
@ -618,8 +626,8 @@ proc `$`*(key: RsaPrivateKey): string =
|
|||
|
||||
proc `$`*(key: RsaPublicKey): string =
|
||||
## Return string representation of RSA public key.
|
||||
if len(key.buffer) == 0:
|
||||
result = "Empty RSA key"
|
||||
if isNil(key) or len(key.buffer) == 0:
|
||||
result = "Empty or uninitialized RSA key"
|
||||
else:
|
||||
let nbitlen = key.key.nlen shl 3
|
||||
result = "RSA key ("
|
||||
|
@ -632,8 +640,8 @@ proc `$`*(key: RsaPublicKey): string =
|
|||
|
||||
proc `$`*(sig: RsaSignature): string =
|
||||
## Return string representation of RSA signature.
|
||||
if len(sig.buffer) == 0:
|
||||
result = "Empty RSA signature"
|
||||
if isNil(sig) or len(sig.buffer) == 0:
|
||||
result = "Empty or uninitialized RSA signature"
|
||||
else:
|
||||
result = "RSA signature ("
|
||||
result.add(toHex(sig.buffer))
|
||||
|
@ -656,44 +664,69 @@ proc cmp(a: openarray[byte], b: openarray[byte]): bool =
|
|||
|
||||
proc `==`*(a, b: RsaPrivateKey): bool =
|
||||
## Compare two RSA private keys for equality.
|
||||
if a.seck.nBitlen == b.seck.nBitlen:
|
||||
if cast[int](a.seck.nBitlen) > 0:
|
||||
let r1 = cmp(getArray(a.buffer, a.seck.p, a.seck.plen),
|
||||
getArray(b.buffer, b.seck.p, b.seck.plen))
|
||||
let r2 = cmp(getArray(a.buffer, a.seck.q, a.seck.qlen),
|
||||
getArray(b.buffer, b.seck.q, b.seck.qlen))
|
||||
let r3 = cmp(getArray(a.buffer, a.seck.dp, a.seck.dplen),
|
||||
getArray(b.buffer, b.seck.dp, b.seck.dplen))
|
||||
let r4 = cmp(getArray(a.buffer, a.seck.dq, a.seck.dqlen),
|
||||
getArray(b.buffer, b.seck.dq, b.seck.dqlen))
|
||||
let r5 = cmp(getArray(a.buffer, a.seck.iq, a.seck.iqlen),
|
||||
getArray(b.buffer, b.seck.iq, b.seck.iqlen))
|
||||
let r6 = cmp(getArray(a.buffer, a.pexp, a.pexplen),
|
||||
getArray(b.buffer, b.pexp, b.pexplen))
|
||||
let r7 = cmp(getArray(a.buffer, a.pubk.n, a.pubk.nlen),
|
||||
getArray(b.buffer, b.pubk.n, b.pubk.nlen))
|
||||
let r8 = cmp(getArray(a.buffer, a.pubk.e, a.pubk.elen),
|
||||
getArray(b.buffer, b.pubk.e, b.pubk.elen))
|
||||
result = r1 and r2 and r3 and r4 and r5 and r6 and r7 and r8
|
||||
else:
|
||||
result = true
|
||||
##
|
||||
## Result is true if ``a`` and ``b`` are both ``nil`` or ``a`` and ``b`` are
|
||||
## equal by value.
|
||||
if isNil(a) and isNil(b):
|
||||
result = true
|
||||
elif isNil(a) and (not isNil(b)):
|
||||
result = false
|
||||
elif isNil(b) and (not isNil(a)):
|
||||
result = false
|
||||
else:
|
||||
if a.seck.nBitlen == b.seck.nBitlen:
|
||||
if cast[int](a.seck.nBitlen) > 0:
|
||||
let r1 = cmp(getArray(a.buffer, a.seck.p, a.seck.plen),
|
||||
getArray(b.buffer, b.seck.p, b.seck.plen))
|
||||
let r2 = cmp(getArray(a.buffer, a.seck.q, a.seck.qlen),
|
||||
getArray(b.buffer, b.seck.q, b.seck.qlen))
|
||||
let r3 = cmp(getArray(a.buffer, a.seck.dp, a.seck.dplen),
|
||||
getArray(b.buffer, b.seck.dp, b.seck.dplen))
|
||||
let r4 = cmp(getArray(a.buffer, a.seck.dq, a.seck.dqlen),
|
||||
getArray(b.buffer, b.seck.dq, b.seck.dqlen))
|
||||
let r5 = cmp(getArray(a.buffer, a.seck.iq, a.seck.iqlen),
|
||||
getArray(b.buffer, b.seck.iq, b.seck.iqlen))
|
||||
let r6 = cmp(getArray(a.buffer, a.pexp, a.pexplen),
|
||||
getArray(b.buffer, b.pexp, b.pexplen))
|
||||
let r7 = cmp(getArray(a.buffer, a.pubk.n, a.pubk.nlen),
|
||||
getArray(b.buffer, b.pubk.n, b.pubk.nlen))
|
||||
let r8 = cmp(getArray(a.buffer, a.pubk.e, a.pubk.elen),
|
||||
getArray(b.buffer, b.pubk.e, b.pubk.elen))
|
||||
result = r1 and r2 and r3 and r4 and r5 and r6 and r7 and r8
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc `==`*(a, b: RsaSignature): bool =
|
||||
## Compare two RSA signatures for equality.
|
||||
result = (a.buffer == b.buffer)
|
||||
if isNil(a) and isNil(b):
|
||||
result = true
|
||||
elif isNil(a) and (not isNil(b)):
|
||||
result = false
|
||||
elif isNil(b) and (not isNil(a)):
|
||||
result = false
|
||||
else:
|
||||
result = (a.buffer == b.buffer)
|
||||
|
||||
proc `==`*(a, b: RsaPublicKey): bool =
|
||||
## Compare two RSA public keys for equality.
|
||||
let r1 = cmp(getArray(a.buffer, a.key.n, a.key.nlen),
|
||||
getArray(b.buffer, b.key.n, b.key.nlen))
|
||||
let r2 = cmp(getArray(a.buffer, a.key.e, a.key.elen),
|
||||
getArray(b.buffer, b.key.e, b.key.elen))
|
||||
result = r1 and r2
|
||||
if isNil(a) and isNil(b):
|
||||
result = true
|
||||
elif isNil(a) and (not isNil(b)):
|
||||
result = false
|
||||
elif isNil(b) and (not isNil(a)):
|
||||
result = false
|
||||
else:
|
||||
let r1 = cmp(getArray(a.buffer, a.key.n, a.key.nlen),
|
||||
getArray(b.buffer, b.key.n, b.key.nlen))
|
||||
let r2 = cmp(getArray(a.buffer, a.key.e, a.key.elen),
|
||||
getArray(b.buffer, b.key.e, b.key.elen))
|
||||
result = r1 and r2
|
||||
|
||||
proc sign*[T: byte|char](key: RsaPrivateKey,
|
||||
message: openarray[T]): RsaSignature =
|
||||
## Get RSA PKCS1.5 signature of data ``message`` using SHA256 and private
|
||||
## key ``key``.
|
||||
doAssert(not isNil(key))
|
||||
var hc: BrHashCompatContext
|
||||
var hash: array[32, byte]
|
||||
var impl = BrRsaPkcs1SignGetDefault()
|
||||
|
@ -720,6 +753,7 @@ proc verify*[T: byte|char](sig: RsaSignature, message: openarray[T],
|
|||
##
|
||||
## Return ``true`` if message verification succeeded, ``false`` if
|
||||
## verification failed.
|
||||
doAssert((not isNil(sig)) and (not isNil(pubkey)))
|
||||
if len(sig.buffer) > 0:
|
||||
var hc: BrHashCompatContext
|
||||
var hash: array[32, byte]
|
||||
|
|
|
@ -345,7 +345,7 @@ const
|
|||
proc cmp(a, b: openarray[byte]): bool =
|
||||
result = (@a == @b)
|
||||
|
||||
proc testStretcher(s, e: int, cs: CipherScheme, ds: DigestSheme): bool =
|
||||
proc testStretcher(s, e: int, cs: string, ds: string): bool =
|
||||
for i in s..<e:
|
||||
var sharedsecret = fromHex(stripSpaces(Secrets[i]))
|
||||
var secret = stretchKeys(cs, ds, sharedsecret)
|
||||
|
@ -452,8 +452,8 @@ suite "Key interface test suite":
|
|||
recsig2.verify(bmsg, recpub2) == true
|
||||
|
||||
test "Go key stretch function AES128-SHA256 test vectors":
|
||||
check testStretcher(0, 4, Aes128, Sha256) == true
|
||||
check testStretcher(0, 4, "AES-128", "SHA256") == true
|
||||
test "Go key stretch function AES256-SHA512 test vectors":
|
||||
check testStretcher(4, 8, Aes256, Sha512) == true
|
||||
check testStretcher(4, 8, "AES-256", "SHA512") == true
|
||||
test "Go key stretch function AES256-SHA1 test vectors":
|
||||
check testStretcher(8, 12, Aes256, Sha1) == true
|
||||
check testStretcher(8, 12, "AES-256", "SHA1") == true
|
||||
|
|
Loading…
Reference in New Issue