Browse Source

Add unit tests for SHA3 signature verification

Katrin Annuk 2 years ago
parent
commit
5175133f53

+ 5 - 1
CryptoSwift.xcodeproj/project.pbxproj

@@ -3,7 +3,7 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 52;
+	objectVersion = 54;
 	objects = {
 
 /* Begin PBXBuildFile section */
@@ -14,6 +14,7 @@
 		1467460F2017BB3600DF04ED /* AEAD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1467460E2017BB3600DF04ED /* AEAD.swift */; };
 		35F3E51C23BF9A6700A024A1 /* OCB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35F3E51B23BF9A6700A024A1 /* OCB.swift */; };
 		42012783267A6F1C00F82506 /* ISO10126Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42012782267A6F1C00F82506 /* ISO10126Padding.swift */; };
+		5431FD5B2B021476001DEE77 /* SignatureVerificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */; };
 		674A736F1BF5D85B00866C5B /* RabbitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674A736E1BF5D85B00866C5B /* RabbitTests.swift */; };
 		6A7CDEED26CD1E4C00FFB1AF /* RSATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */; };
 		6AC893F626DB950F00F7E787 /* Addition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E026DB950C00F7E787 /* Addition.swift */; };
@@ -240,6 +241,7 @@
 		35F3E51B23BF9A6700A024A1 /* OCB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCB.swift; sourceTree = "<group>"; };
 		35F3E51D23BF9AD300A024A1 /* AESOCBTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESOCBTests.swift; sourceTree = "<group>"; };
 		42012782267A6F1C00F82506 /* ISO10126Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ISO10126Padding.swift; sourceTree = "<group>"; };
+		5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignatureVerificationTests.swift; sourceTree = "<group>"; };
 		674A736E1BF5D85B00866C5B /* RabbitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RabbitTests.swift; sourceTree = "<group>"; };
 		6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSATests.swift; sourceTree = "<group>"; };
 		6AC893E026DB950C00F7E787 /* Addition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Addition.swift; sourceTree = "<group>"; };
@@ -581,6 +583,7 @@
 				75482EA31CB310B7001F66A5 /* PBKDF.swift */,
 				7576F6F6207290F8006688F8 /* PBKDFPerf.swift */,
 				6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */,
+				5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */,
 				75C2E76C1D55F097003D2BCA /* Access.swift */,
 				756BFDCA1A82B87300B9D9A4 /* Bridging.h */,
 			);
@@ -1106,6 +1109,7 @@
 				757DA2531A4ED0A4002BA3EF /* PaddingTests.swift in Sources */,
 				14156CE52011422400DDCFBC /* ChaCha20Poly1305Tests.swift in Sources */,
 				757DA2551A4ED408002BA3EF /* AESTests.swift in Sources */,
+				5431FD5B2B021476001DEE77 /* SignatureVerificationTests.swift in Sources */,
 				7594CCBC217A76DC0055C95D /* AESCCMTests.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 19 - 4
Sources/CryptoSwift/RSA/RSA+Signature.swift

@@ -121,6 +121,12 @@ extension RSA {
     case message_pkcs1v15_SHA512_224
     /// Hashes the raw message using SHA512-256 before signing the data
     case message_pkcs1v15_SHA512_256
+    /// Hashes the raw message using SHA3_256 before signing the data
+    case message_pkcs1v15_SHA3_256
+    /// Hashes the raw message using SHA3_384 before signing the data
+    case message_pkcs1v15_SHA3_384
+    /// Hashes the raw message using SHA3_512 before signing the data
+    case message_pkcs1v15_SHA3_512
     /// This variant isn't supported yet
     case digest_pkcs1v15_RAW
     /// This variant expects that the data to be signed is a valid MD5 Hash Digest
@@ -157,9 +163,9 @@ extension RSA {
       case .message_pkcs1v15_SHA224, .digest_pkcs1v15_SHA224: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04)
       case .message_pkcs1v15_SHA512_224, .digest_pkcs1v15_SHA512_224: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05)
       case .message_pkcs1v15_SHA512_256, .digest_pkcs1v15_SHA512_256: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06)
-      case .digest_pkcs1v15_SHA3_256: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08)
-      case .digest_pkcs1v15_SHA3_384: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09)
-      case .digest_pkcs1v15_SHA3_512: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A)
+      case .message_pkcs1v15_SHA3_256, .digest_pkcs1v15_SHA3_256: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08)
+      case .message_pkcs1v15_SHA3_384, .digest_pkcs1v15_SHA3_384: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09)
+      case .message_pkcs1v15_SHA3_512, .digest_pkcs1v15_SHA3_512: return Array<UInt8>(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A)
       }
     }
     
@@ -181,6 +187,12 @@ extension RSA {
         return Digest.sha2(bytes, variant: .sha224)
       case .message_pkcs1v15_SHA512_256:
         return Digest.sha2(bytes, variant: .sha256)
+      case .message_pkcs1v15_SHA3_256:
+        return Digest.sha3(bytes, variant: .sha256)
+      case .message_pkcs1v15_SHA3_384:
+        return Digest.sha3(bytes, variant: .sha384)
+      case .message_pkcs1v15_SHA3_512:
+        return Digest.sha3(bytes, variant: .sha512)
       case .raw,
           .digest_pkcs1v15_RAW,
           .digest_pkcs1v15_MD5,
@@ -225,7 +237,10 @@ extension RSA {
           .message_pkcs1v15_SHA384,
           .message_pkcs1v15_SHA512,
           .message_pkcs1v15_SHA512_224,
-          .message_pkcs1v15_SHA512_256:
+          .message_pkcs1v15_SHA512_256,
+          .message_pkcs1v15_SHA3_256,
+          .message_pkcs1v15_SHA3_384,
+          .message_pkcs1v15_SHA3_512:
         return true
       }
     }

+ 6 - 0
Tests/CryptoSwiftTests/RSATests.swift

@@ -341,6 +341,9 @@ final class RSATests: XCTestCase {
     XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512))
     XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512_224))
     XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512_256))
+    XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_256))
+    XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_384))
+    XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_512))
 
     // But if we hash the message first, then the signature works as expected...
     XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA1))
@@ -350,6 +353,9 @@ final class RSATests: XCTestCase {
     XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512))
     XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512_224))
     XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512_256))
+    XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_256))
+    XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_384))
+    XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_512))
   }
 
   /// This test uses the Fixtures (generated using Apple's `Security` framework) to test the entirety of an RSA keys functionality

+ 124 - 0
Tests/CryptoSwiftTests/SignatureVerificationTests.swift

@@ -0,0 +1,124 @@
+////  CryptoSwift
+//
+//  Copyright (C) 2014-2023 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
+//  This software is provided 'as-is', without any express or implied warranty.
+//
+//  In no event will the authors be held liable for any damages arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+//  - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+//  - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+//  - This notice may not be removed or altered from any source or binary distribution.
+//
+
+import Foundation
+import XCTest
+@testable import CryptoSwift
+
+final class SignatureVerificationTests: XCTestCase {
+    
+  func testVerifySHA3Variants() {
+      let testVectors: [SignatureVerificationTests.TestVector] = [
+        SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_256,
+        SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_384,
+        SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_512,
+        SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_256,
+        SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_384,
+        SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_512
+      ]
+      
+    for testVector in testVectors {
+      do {
+        guard
+          let publicDerData = Data(base64Encoded: testVector.publicDER)
+        else {
+          XCTFail("Corrupted data - publicDER")
+          continue
+        }
+        
+        let rsa = try RSA(publicDER: publicDerData.bytes)
+        
+        guard
+          let signedMessageData = Data(base64Encoded: testVector.signedMessage)
+        else {
+          XCTFail("Corrupted data - signedMessage")
+          continue
+        }
+        
+        let result = try rsa.verify(signature: signedMessageData.bytes,
+                                    for: testVector.originalMessage.bytes,
+                                    variant: testVector.variant)
+        XCTAssertTrue(result, "Verification failed for test vector with id `\(testVector.id)`")
+        
+      } catch let error {
+        XCTFail("Failed with error \(error)")
+      }
+    }
+  }
+
+}
+
+extension SignatureVerificationTests {
+  struct TestVector {
+    
+    /// String to identify test vector. Used for logging purposes
+    let id: String
+    /// Public DER for RSA key
+    let publicDER: String
+    /// RSA signature variant
+    let variant: RSA.SignatureVariant
+    /// Original message that was signed
+    let originalMessage: String
+    /// Signed message
+    let signedMessage: String
+  }
+  
+  static let testVectorMessage_pkcs1v15_SHA3_256 = TestVector(
+    id: "1",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .message_pkcs1v15_SHA3_256,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "IOIA/8NgoLVwtfto5Lnea7GLBXMddCAgQFBt38HVJpbEtuEcmu8uFs4sJuAHalH1iIe/cGPrwASRM94fSDKzuQ7XNX2Dwt8DBzu9BlAtEWq9GUSL/6DED0xJfqrl6G5rh+RRk9YYIk3TeI9H4HzsmIDFjp5hxFu0SedoR5DzEVM="
+  )
+  
+  static let testVectorMessage_pkcs1v15_SHA3_384 = TestVector(
+    id: "2",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .message_pkcs1v15_SHA3_384,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "J1qAdFj7iwlW6Mhyf5MfG2CN7BeUjKCFeCunBs2Hginwpcz/YfJgzNpGA93T+RBR4kLVuhs3OVILhwaMnTbgsMVNz0xLoZ5oegRADXDT1Ln3WuTUuqQH+RiMSILelgaHsU4fjj7jCC8wLFA2DtYm7aje1HF3ZRc/9SQSTREM5Gw="
+  )
+  
+  static let testVectorMessage_pkcs1v15_SHA3_512 = TestVector(
+    id: "3",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .message_pkcs1v15_SHA3_512,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "KMmRIptAPCZV7I/6gRN6wUQekRm+sxXWtoAyxC7PPiSBNd9XJTVVrEUnEfpnupI6uum+r9YxAT5Ha0S5XrYlojHZFLW3gZHLAKmRBushg8YRfqK68cDLYBshuqBlf5nuQZDU+7LTBh6Jnup2rGbQj1Bra9X9Hl9uZmoPY8Uoh/g="
+  )
+  
+  static let testVectorDigest_pkcs1v15_SHA3_256 = TestVector(
+    id: "4",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .digest_pkcs1v15_SHA3_256,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "Oj3CBwMQIEGrQwFuqIXklqOJG6pdaS5Kjal+sAKoMvEzXCB0h8K8w9YNt/XIOD9fJXdUaG0XR6RB8eEQxh/u6pYZPVUwssyA//FUjWLgKOecNkaca+EK98iIkivjVdEGK7yVhcQHJF19EfpZahVWWlEUCT02g8niomkWUHWIlo8="
+  )
+  
+  static let testVectorDigest_pkcs1v15_SHA3_384 = TestVector(
+    id: "5",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .digest_pkcs1v15_SHA3_384,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "ZCn19KmnT/QdzcNm077uopZeIxkR5EECX0po2QypPTYorYa9dGTm3nKR0mMr/G2C7ukrR2a8j5WPf4hXi1rlzOoFNufpbyQB33I9INleN7FjASmoxFcw6TyFNeMPN+TwKj9MVTEkZ7HtPL0bBsD8E08eRCDwk3UYdUjcvZcOdzw="
+  )
+  
+  static let testVectorDigest_pkcs1v15_SHA3_512 = TestVector(
+    id: "6",
+    publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=",
+    variant: .digest_pkcs1v15_SHA3_512,
+    originalMessage: "CryptoSwift Test",
+    signedMessage: "bk1/rtzt64ZApavxPrUEnsG/tN7nN6ITV3NKY0IR1i/3S4bkxIMulRsBPINpksTAafxrSm6EsLAmOPrqjwGycqRjSRi8/S6roUE/TIno2dGfO5e4eVKCQtD6I+CHA0Xji3X1k627vaYZqpTMFuMk8serfjMTHFe46s6S+f/64as="
+  )
+}