From 775cab414a68843c93c75e357f69cb1c04b32edd Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Tue, 7 Jul 2020 16:48:15 +0300 Subject: [PATCH] Remove SHA1 from crypto and crypto tests. (#251) * Remove SHA1 from crypto and crypto tests. * Simplify RSA comparison procedure. Refactor some procedures in crypto.nim. --- libp2p/crypto/crypto.nim | 278 +++++++++++++++++---------------------- libp2p/crypto/rsa.nim | 11 +- tests/testcrypto.nim | 41 ------ 3 files changed, 124 insertions(+), 206 deletions(-) diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index 05c51a5..66fe81c 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -13,13 +13,13 @@ import rsa, ecnist, ed25519/ed25519, secp, bearssl import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec -import nimcrypto/[rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils] +import nimcrypto/[rijndael, blowfish, twofish, sha2, hash, hmac, utils] import ../utility import stew/results export results -# Export modules of types that are part of public API -export rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils +# This is workaround for Nim's `import` bug +export rijndael, blowfish, twofish, sha2, hash, hmac, utils from strutils import split @@ -37,7 +37,6 @@ type Blowfish DigestSheme* = enum - Sha1, Sha256, Sha512 @@ -184,7 +183,8 @@ proc getKey*(key: PrivateKey): CryptoResult[PublicKey] = else: err(KeyError) -proc toRawBytes*(key: PrivateKey | PublicKey, data: var openarray[byte]): CryptoResult[int] = +proc toRawBytes*(key: PrivateKey | PublicKey, + data: var openarray[byte]): CryptoResult[int] = ## Serialize private key ``key`` (using scheme's own serialization) and store ## it to ``data``. ## @@ -274,7 +274,7 @@ proc getBytes*(sig: Signature): seq[byte] = ## Return signature ``sig`` in binary form. result = sig.data -proc init*(key: var PrivateKey, data: openarray[byte]): bool = +proc init*[T: PrivateKey|PublicKey](key: var T, data: openarray[byte]): bool = ## Initialize private key ``key`` from libp2p's protobuf serialized raw ## binary form. ## @@ -287,54 +287,29 @@ proc init*(key: var PrivateKey, data: openarray[byte]): bool = if pb.getBytes(2, buffer) != 0: if cast[int8](id) in SupportedSchemesInt: var scheme = cast[PKScheme](cast[int8](id)) - var nkey = PrivateKey(scheme: scheme) - if scheme == RSA: + when key is PrivateKey: + var nkey = PrivateKey(scheme: scheme) + else: + var nkey = PublicKey(scheme: scheme) + case scheme: + of PKScheme.RSA: if init(nkey.rsakey, buffer).isOk: key = nkey - result = true - elif scheme == Ed25519: + return true + of PKScheme.Ed25519: if init(nkey.edkey, buffer): key = nkey - result = true - elif scheme == ECDSA: + return true + of PKScheme.ECDSA: if init(nkey.eckey, buffer).isOk: key = nkey - result = true - elif scheme == Secp256k1: + return true + of PKScheme.Secp256k1: if init(nkey.skkey, buffer).isOk: key = nkey - result = true - -proc init*(key: var PublicKey, data: openarray[byte]): bool = - ## Initialize public key ``key`` from libp2p's protobuf serialized raw - ## binary form. - ## - ## Returns ``true`` on success. - var id: uint64 - var buffer: seq[byte] - if len(data) > 0: - var pb = initProtoBuffer(@data) - if pb.getVarintValue(1, id) != 0: - if pb.getBytes(2, buffer) != 0: - if cast[int8](id) in SupportedSchemesInt: - var scheme = cast[PKScheme](cast[int8](id)) - var nkey = PublicKey(scheme: scheme) - if scheme == RSA: - if init(nkey.rsakey, buffer).isOk: - key = nkey - result = true - elif scheme == Ed25519: - if init(nkey.edkey, buffer): - key = nkey - result = true - elif scheme == ECDSA: - if init(nkey.eckey, buffer).isOk: - key = nkey - result = true - elif scheme == Secp256k1: - if init(nkey.skkey, buffer).isOk: - key = nkey - result = true + return true + else: + return false proc init*(sig: var Signature, data: openarray[byte]): bool = ## Initialize signature ``sig`` from raw binary form. @@ -344,18 +319,8 @@ proc init*(sig: var Signature, data: openarray[byte]): bool = sig.data = @data result = true -proc init*(key: var PrivateKey, data: string): bool = - ## Initialize private key ``key`` from libp2p's protobuf serialized - ## hexadecimal string representation. - ## - ## Returns ``true`` on success. - try: - key.init(fromHex(data)) - except ValueError: - false - -proc init*(key: var PublicKey, data: string): bool = - ## Initialize public key ``key`` from libp2p's protobuf serialized +proc init*[T: PrivateKey|PublicKey](key: var T, data: string): bool = + ## Initialize private/public key ``key`` from libp2p's protobuf serialized ## hexadecimal string representation. ## ## Returns ``true`` on success. @@ -374,7 +339,8 @@ proc init*(sig: var Signature, data: string): bool = except ValueError: false -proc init*(t: typedesc[PrivateKey], data: openarray[byte]): CryptoResult[PrivateKey] = +proc init*(t: typedesc[PrivateKey], + data: openarray[byte]): CryptoResult[PrivateKey] = ## Create new private key from libp2p's protobuf serialized binary form. var res: t if not res.init(data): @@ -382,7 +348,8 @@ proc init*(t: typedesc[PrivateKey], data: openarray[byte]): CryptoResult[Private else: ok(res) -proc init*(t: typedesc[PublicKey], data: openarray[byte]): CryptoResult[PublicKey] = +proc init*(t: typedesc[PublicKey], + data: openarray[byte]): CryptoResult[PublicKey] = ## Create new public key from libp2p's protobuf serialized binary form. var res: t if not res.init(data): @@ -390,7 +357,8 @@ proc init*(t: typedesc[PublicKey], data: openarray[byte]): CryptoResult[PublicKe else: ok(res) -proc init*(t: typedesc[Signature], data: openarray[byte]): CryptoResult[Signature] = +proc init*(t: typedesc[Signature], + data: openarray[byte]): CryptoResult[Signature] = ## Create new public key from libp2p's protobuf serialized binary form. var res: t if not res.init(data): @@ -421,117 +389,93 @@ proc init*(t: typedesc[Signature], data: string): CryptoResult[Signature] = except ValueError: err(SigError) -proc `==`*(key1, key2: PublicKey): bool = +proc `==`*(key1, key2: PublicKey): bool {.inline.} = ## Return ``true`` if two public keys ``key1`` and ``key2`` of the same ## scheme and equal. if key1.scheme == key2.scheme: - if key1.scheme == RSA: - result = (key1.rsakey == key2.rsakey) - elif key1.scheme == Ed25519: - result = (key1.edkey == key2.edkey) - elif key1.scheme == ECDSA: - result = (key1.eckey == key2.eckey) + case key1.scheme + of PKScheme.RSA: + (key1.rsakey == key2.rsakey) + of PKScheme.Ed25519: + (key1.edkey == key2.edkey) + of PKScheme.ECDSA: + (key1.eckey == key2.eckey) + of PKScheme.Secp256k1: + (key1.skkey == key2.skkey) + of PKScheme.NoSupport: + false + else: + false proc `==`*(key1, key2: PrivateKey): bool = ## Return ``true`` if two private keys ``key1`` and ``key2`` of the same ## scheme and equal. if key1.scheme == key2.scheme: - if key1.scheme == RSA: - result = (key1.rsakey == key2.rsakey) - elif key1.scheme == Ed25519: - result = (key1.edkey == key2.edkey) - elif key1.scheme == ECDSA: - result = (key1.eckey == key2.eckey) + case key1.scheme + of PKScheme.RSA: + (key1.rsakey == key2.rsakey) + of PKScheme.Ed25519: + (key1.edkey == key2.edkey) + of PKScheme.ECDSA: + (key1.eckey == key2.eckey) + of PKScheme.Secp256k1: + (key1.skkey == key2.skkey) + of PKScheme.NoSupport: + false + else: + false -proc `$`*(key: PrivateKey): string = - ## Get string representation of private key ``key``. - if key.scheme == RSA: - result = $(key.rsakey) - elif key.scheme == Ed25519: - result = "Ed25519 key (" - result.add($(key.edkey)) - result.add(")") - elif key.scheme == ECDSA: - result = "Secp256r1 key (" - result.add($(key.eckey)) - result.add(")") - elif key.scheme == Secp256k1: - result = "Secp256k1 key (" - result.add($(key.skkey)) - result.add(")") +proc `$`*(key: PrivateKey|PublicKey): string = + ## Get string representation of private/public key ``key``. + case key.scheme: + of PKScheme.RSA: + $(key.rsakey) + of PKScheme.Ed25519: + "ed25519 key (" & $key.edkey & ")" + of PKScheme.ECDSA: + "secp256r1 key (" & $key.eckey & ")" + of PKScheme.Secp256k1: + "secp256k1 key (" & $key.skkey & ")" + of PKScheme.NoSupport: + "not supported" -proc `$`*(key: PublicKey): string = - ## Get string representation of public key ``key``. - if key.scheme == RSA: - result = $(key.rsakey) - elif key.scheme == Ed25519: - result = "Ed25519 key (" - result.add($(key.edkey)) - result.add(")") - elif key.scheme == ECDSA: - result = "Secp256r1 key (" - result.add($(key.eckey)) - result.add(")") - elif key.scheme == Secp256k1: - result = "Secp256k1 key (" - result.add($(key.skkey)) - result.add(")") - -func shortLog*(key: PrivateKey): string = - ## Get string representation of private key ``key``. - if key.scheme == RSA: - result = ($key.rsakey).shortLog - elif key.scheme == Ed25519: - result = "Ed25519 key (" - result.add(($key.edkey).shortLog) - result.add(")") - elif key.scheme == ECDSA: - result = "Secp256r1 key (" - result.add(($key.eckey).shortLog) - result.add(")") - elif key.scheme == Secp256k1: - result = "Secp256k1 key (" - result.add(($key.skkey).shortLog) - result.add(")") - -proc shortLog*(key: PublicKey): string = - ## Get string representation of public key ``key``. - if key.scheme == RSA: - result = ($key.rsakey).shortLog - elif key.scheme == Ed25519: - result = "Ed25519 key (" - result.add(($key.edkey).shortLog) - result.add(")") - elif key.scheme == ECDSA: - result = "Secp256r1 key (" - result.add(($key.eckey).shortLog) - result.add(")") - elif key.scheme == Secp256k1: - result = "Secp256k1 key (" - result.add(($key.skkey).shortLog) - result.add(")") +func shortLog*(key: PrivateKey|PublicKey): string = + ## Get short string representation of private/public key ``key``. + case key.scheme: + of PKScheme.RSA: + ($key.rsakey).shortLog + of PKScheme.Ed25519: + "ed25519 key (" & ($key.edkey).shortLog & ")" + of PKScheme.ECDSA: + "secp256r1 key (" & ($key.eckey).shortLog & ")" + of PKScheme.Secp256k1: + "secp256k1 key (" & ($key.skkey).shortLog & ")" + of PKScheme.NoSupport: + "not supported" proc `$`*(sig: Signature): string = ## Get string representation of signature ``sig``. result = toHex(sig.data) -proc sign*(key: PrivateKey, data: openarray[byte]): CryptoResult[Signature] {.gcsafe.} = +proc sign*(key: PrivateKey, + data: openarray[byte]): CryptoResult[Signature] {.gcsafe.} = ## Sign message ``data`` using private key ``key`` and return generated ## signature in raw binary form. var res: Signature - if key.scheme == RSA: + case key.scheme: + of PKScheme.RSA: let sig = ? key.rsakey.sign(data).orError(SigError) res.data = ? sig.getBytes().orError(SigError) ok(res) - elif key.scheme == Ed25519: + of PKScheme.Ed25519: let sig = key.edkey.sign(data) res.data = sig.getBytes() ok(res) - elif key.scheme == ECDSA: + of PKScheme.ECDSA: let sig = ? key.eckey.sign(data).orError(SigError) res.data = ? sig.getBytes().orError(SigError) ok(res) - elif key.scheme == Secp256k1: + of PKScheme.Secp256k1: let sig = key.skkey.sign(data) res.data = sig.getBytes() ok(res) @@ -541,22 +485,33 @@ proc sign*(key: PrivateKey, data: openarray[byte]): CryptoResult[Signature] {.gc proc verify*(sig: Signature, message: openarray[byte], key: PublicKey): bool = ## Verify signature ``sig`` using message ``message`` and public key ``key``. ## Return ``true`` if message signature is valid. - if key.scheme == RSA: + case key.scheme: + of PKScheme.RSA: var signature: RsaSignature if signature.init(sig.data).isOk: - result = signature.verify(message, key.rsakey) - elif key.scheme == Ed25519: + signature.verify(message, key.rsakey) + else: + false + of PKScheme.Ed25519: var signature: EdSignature if signature.init(sig.data): - result = signature.verify(message, key.edkey) - elif key.scheme == ECDSA: + signature.verify(message, key.edkey) + else: + false + of PKScheme.ECDSA: var signature: EcSignature if signature.init(sig.data).isOk: - result = signature.verify(message, key.eckey) - elif key.scheme == Secp256k1: + signature.verify(message, key.eckey) + else: + false + of PKScheme.Secp256k1: var signature: SkSignature if signature.init(sig.data).isOk: - result = signature.verify(message, key.skkey) + signature.verify(message, key.skkey) + else: + false + else: + false template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}= var ctx: hmactype @@ -609,8 +564,6 @@ proc stretchKeys*(cipherType: string, hashType: string, 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 @@ -802,23 +755,28 @@ proc decodeExchange*(message: seq[byte], ## Serialization/Deserialization helpers -proc write*(vb: var VBuffer, pubkey: PublicKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = +proc write*(vb: var VBuffer, pubkey: PublicKey) {. + inline, raises: [Defect, ResultError[CryptoError]].} = ## Write PublicKey value ``pubkey`` to buffer ``vb``. vb.writeSeq(pubkey.getBytes().tryGet()) -proc write*(vb: var VBuffer, seckey: PrivateKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = +proc write*(vb: var VBuffer, seckey: PrivateKey) {. + inline, raises: [Defect, ResultError[CryptoError]].} = ## Write PrivateKey value ``seckey`` to buffer ``vb``. vb.writeSeq(seckey.getBytes().tryGet()) -proc write*(vb: var VBuffer, sig: PrivateKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = +proc write*(vb: var VBuffer, sig: PrivateKey) {. + inline, raises: [Defect, ResultError[CryptoError]].} = ## Write Signature value ``sig`` to buffer ``vb``. vb.writeSeq(sig.getBytes().tryGet()) -proc initProtoField*(index: int, pubkey: PublicKey): ProtoField {.raises: [Defect, ResultError[CryptoError]].} = +proc initProtoField*(index: int, pubkey: PublicKey): ProtoField {. + raises: [Defect, ResultError[CryptoError]].} = ## Initialize ProtoField with PublicKey ``pubkey``. result = initProtoField(index, pubkey.getBytes().tryGet()) -proc initProtoField*(index: int, seckey: PrivateKey): ProtoField {.raises: [Defect, ResultError[CryptoError]].} = +proc initProtoField*(index: int, seckey: PrivateKey): ProtoField {. + raises: [Defect, ResultError[CryptoError]].} = ## Initialize ProtoField with PrivateKey ``seckey``. result = initProtoField(index, seckey.getBytes().tryGet()) diff --git a/libp2p/crypto/rsa.nim b/libp2p/crypto/rsa.nim index 3aa7f71..5f7c5a5 100644 --- a/libp2p/crypto/rsa.nim +++ b/libp2p/crypto/rsa.nim @@ -661,15 +661,16 @@ proc cmp(a: openarray[byte], b: openarray[byte]): bool = let blen = len(b) if alen == blen: if alen == 0: - result = true + true else: var n = alen - var res, diff: int + var res = 0 while n > 0: dec(n) - diff = int(a[n]) - int(b[n]) - res = (res and -not(diff)) or diff - result = (res == 0) + res = res or int(a[n] xor b[n]) + (res == 0) + else: + false proc `==`*(a, b: RsaPrivateKey): bool = ## Compare two RSA private keys for equality. diff --git a/tests/testcrypto.nim b/tests/testcrypto.nim index a44c867..79ac62d 100644 --- a/tests/testcrypto.nim +++ b/tests/testcrypto.nim @@ -243,18 +243,6 @@ const """001CC33294544D898781010258C2FB81F02429D2DD54D0B59B8CD2335F57498F D4E444BEC94DA7BE2BAF3E3796AFA8388F626AEB3178355991985EE5FFC9D1AA CAD9""", - # AES-256 SHA-1 - "85076756644AAC06A47B29E25CB39B3E0C717152EE587F50C5A10281DB7F2FA5", - """256D46C5E5449AA7B9BE985646D5F32E455BB4B7AAF3566507A023B72801A7BC - 5066647E82DE2BC37FE22AB0DE440F77""", - """01FF82C71215CFFD7A42A5CED03BD2256D4A5B6850472A5C5CA90665D510F038 - A21F3A6EA0BB0A64113960C54DDAFC5E7A5F018E4413D7CC93C736A8D30579ED - 5A2B""", - # Edge case (where Go implementation returns 65 bytes of secret) - # Nim implementation has leading `00`. - """00360D9410E58534AC6A89CA5AC17E9455F619DCA71A6C2FB6F3156AE58DDB91 - 6E9A7D223D1D7DD05D5475BFC4C517C85475600AAF6F28703ED1203281369A41 - 9A7C""" ] Ivs = [ @@ -275,15 +263,6 @@ const "A828F6D249F38A917CD297F7BDDE7B70", "54FC8070579A17F6DAD342174062D60A", "D33C7696183DA21C5CD40AB677BECE7C", - - "9EFF93741DC080A15B9E554080AB9869", - "7A007E351C9A5C930D01645D97648F8C", - "934DB2529D1D3AC37BAD56FD1E522196", - "30D19C3C1AB9A3391A5F88E92307261D", - "32ED1A961630D94A279F99757B3131CB", - "003ABE572377D59B74713425854FED29", - "3338850C0A4D7BD53C70E40FA0079AA2", - "62787F194DC218C5B0DAFD806F0D3125" ] CipherKeys = [ @@ -304,15 +283,6 @@ const "FC2797D1040FF162A90275EBA3FCC4330C2BDC28D23DA80B89842C2D7A6EFA06", "B83698789ED8E3B44E48EAAEB291B3003AD95FAF344EBA1B9071F4FB46A4E4E9", "5D90C579971B7B7F9ECDE55EBCE8921B807AAD45D61952228758BA80F4490E8F", - - "1C429A32A2E16168D3E3F942AEEAD708456C6566D800D5B7A6DCE8184739F16D", - "84987E7CC9F71243408454DD0787F438CCB62C79ED56078FD920FFFD7D5C44FF", - "971372E385E0F9FED8F67C922D0F5EB77D7D7818F63B26EF80C4D3C81D9E1B97", - "F20AE0A5387B2D1D38B8B340466D252F894C00C5907EE3A510442E4F38966AB0", - "B58F32D83C7A91B6B1DA731334D70502348CD82EFB8258C0AE316B983F2F1E1E", - "5903FE75A1C328BE6C98EB4A4EFF19C67D3C52C87B3131047F3773201D44BFCE", - "55EAD85B3124C36828ED3A43698952111EECE8C7FB156D71EE3F84E088B4F4CE", - "E4C99C782A88B69E5D83F4DEFDD2AE61A397486E17EC9EAE6EC679A75E47BBCD" ] MacKeys = [ @@ -333,15 +303,6 @@ const "EE66A1579D732E99A8500F48595BF25289E722DB", "E692EC73B0A2E68625221E1D01BA0E6B24BCB43F", "8613E8F86D2DD1CF3CEDC52AD91423F2F31E0003", - - "F8A7EF47F37257B54A5028424E64F172E532E7E7", - "4D3596723AECD3DF21A20E956755782E783C9E4A", - "484860090D99F4B702C809294037E6C7F6E58BBA", - "15163D55C0A32E79E0EDD8E8EDA5AC9564B5488C", - "6116BCB44773E3342AB5671D2AC107D4C9EC0757", - "1CA3FCA023C72B7695481CA815856FEF0C5D7E9E", - "E34004C383C36201DC23E062DAE791C76738C28E", - "FA5CB0689A1DFDBAE8618BC079D70E318377B0DA" ] proc cmp(a, b: openarray[byte]): bool = @@ -459,8 +420,6 @@ suite "Key interface test suite": check testStretcher(0, 4, "AES-128", "SHA256") == true test "Go key stretch function AES256-SHA512 test vectors": check testStretcher(4, 8, "AES-256", "SHA512") == true - test "Go key stretch function AES256-SHA1 test vectors": - check testStretcher(8, 12, "AES-256", "SHA1") == true test "ChaChaPoly": # test data from: