From a46905442266dbf9830978aa3c23cab33b0fd4cb Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 17 Apr 2023 12:23:36 +0200 Subject: [PATCH 1/2] Make NIST PublicKey's conform to Equatable --- Sources/Crypto/Key Agreement/ECDH.swift | 24 ++++++ Sources/Crypto/Key Agreement/ECDH.swift.gyb | 4 + Sources/Crypto/Keys/EC/NISTCurvesKeys.swift | 2 +- .../ECDSA/ECDSASignatureTests.swift | 85 ++++++++++++++++++- 4 files changed, 113 insertions(+), 2 deletions(-) diff --git a/Sources/Crypto/Key Agreement/ECDH.swift b/Sources/Crypto/Key Agreement/ECDH.swift index acb8e75c3..7472b29c8 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift +++ b/Sources/Crypto/Key Agreement/ECDH.swift @@ -88,6 +88,10 @@ extension P256 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { @@ -222,6 +226,10 @@ extension P256 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { @@ -356,6 +364,10 @@ extension P384 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { @@ -490,6 +502,10 @@ extension P384 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { @@ -624,6 +640,10 @@ extension P521 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { @@ -758,6 +778,10 @@ extension P521 { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { diff --git a/Sources/Crypto/Key Agreement/ECDH.swift.gyb b/Sources/Crypto/Key Agreement/ECDH.swift.gyb index 57b7094ec..72fa13ac2 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift.gyb +++ b/Sources/Crypto/Key Agreement/ECDH.swift.gyb @@ -94,6 +94,10 @@ extension ${CURVE} { let pemDocument = ASN1.PEMDocument(type: "PUBLIC KEY", derBytes: self.derRepresentation) return pemDocument.pemString } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: NISTECPrivateKey { diff --git a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift index 730001a25..73227c53f 100644 --- a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift +++ b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift @@ -32,7 +32,7 @@ protocol ECPrivateKey { var publicKey: PublicKey { get } } -protocol NISTECPublicKey: ECPublicKey { +protocol NISTECPublicKey: ECPublicKey, Equatable { init(compactRepresentation: Bytes) throws init(compressedRepresentation: Bytes) throws init(x963Representation: Bytes) throws diff --git a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift index 5b2af0401..450ec0836 100644 --- a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift +++ b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift @@ -453,6 +453,89 @@ class SignatureTests: XCTestCase { let compressedX963Positive = Data(base64Encoded: "A+QHCXtGd5WWSQgp37FBPXMy+nnSwFK79QQD0ZeNMv7L")! XCTAssertThrowsError(try P256.Signing.PublicKey(x963Representation: compressedX963Positive)) } - + + func testP256SigningPublicKeyEquatable() throws { + // Equality + let publicKey = P256.Signing.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P256.Signing.PrivateKey().publicKey + ) + } + } + + func testP256KeyAgreementPublicKeyEquatable() throws { + // Equality + let publicKey = P256.KeyAgreement.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P256.KeyAgreement.PrivateKey().publicKey + ) + } + } + + func testP384SigningPublicKeyEquatable() throws { + // Equality + let publicKey = P384.Signing.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P384.Signing.PrivateKey().publicKey + ) + } + } + + func testP384KeyAgreementPublicKeyEquatable() throws { + // Equality + let publicKey = P384.KeyAgreement.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P384.KeyAgreement.PrivateKey().publicKey + ) + } + } + + func testP521SigningPublicKeyEquatable() throws { + // Equality + let publicKey = P521.Signing.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P521.Signing.PrivateKey().publicKey + ) + } + } + + func testP521KeyAgreementPublicKeyEquatable() throws { + // Equality + let publicKey = P521.KeyAgreement.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + + // Inequality + for _ in 0..<32 { + XCTAssertNotEqual( + publicKey, + P521.KeyAgreement.PrivateKey().publicKey + ) + } + } } #endif // (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) && CRYPTO_IN_SWIFTPM From da73315b70609e966e50c97178eba7bcc769386d Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 18 Apr 2023 12:47:57 +0200 Subject: [PATCH 2/2] Make all NIST PublicKey's conform to Hashable --- Sources/Crypto/Key Agreement/ECDH.swift | 24 +++++++++ Sources/Crypto/Key Agreement/ECDH.swift.gyb | 4 ++ Sources/Crypto/Keys/EC/NISTCurvesKeys.swift | 2 +- .../ECDSA/ECDSASignatureTests.swift | 49 +++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Sources/Crypto/Key Agreement/ECDH.swift b/Sources/Crypto/Key Agreement/ECDH.swift index 7472b29c8..e329917f2 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift +++ b/Sources/Crypto/Key Agreement/ECDH.swift @@ -92,6 +92,10 @@ extension P256 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { @@ -230,6 +234,10 @@ extension P256 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { @@ -368,6 +376,10 @@ extension P384 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { @@ -506,6 +518,10 @@ extension P384 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { @@ -644,6 +660,10 @@ extension P521 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { @@ -782,6 +802,10 @@ extension P521 { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { diff --git a/Sources/Crypto/Key Agreement/ECDH.swift.gyb b/Sources/Crypto/Key Agreement/ECDH.swift.gyb index 72fa13ac2..199ea5b9f 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift.gyb +++ b/Sources/Crypto/Key Agreement/ECDH.swift.gyb @@ -98,6 +98,10 @@ extension ${CURVE} { public static func ==(lhs: Self, rhs: Self) -> Bool { lhs.rawRepresentation == rhs.rawRepresentation } + + public func hash(into hasher: inout Hasher) { + hasher.combine(rawRepresentation) + } } public struct PrivateKey: NISTECPrivateKey { diff --git a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift index 73227c53f..41e7ff165 100644 --- a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift +++ b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift @@ -32,7 +32,7 @@ protocol ECPrivateKey { var publicKey: PublicKey { get } } -protocol NISTECPublicKey: ECPublicKey, Equatable { +protocol NISTECPublicKey: ECPublicKey, Hashable { init(compactRepresentation: Bytes) throws init(compressedRepresentation: Bytes) throws init(x963Representation: Bytes) throws diff --git a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift index 450ec0836..8c70c3f2e 100644 --- a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift +++ b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift @@ -537,5 +537,54 @@ class SignatureTests: XCTestCase { ) } } + + func testP256SigningPublicKeyHashable() throws { + let expectedCount = 64 + let set = Set((0..