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