diff --git a/Tests/CryptoSwiftTests/RSASecKeyTests.swift b/Tests/CryptoSwiftTests/RSASecKeyTests.swift new file mode 100644 index 0000000..8c39b06 --- /dev/null +++ b/Tests/CryptoSwiftTests/RSASecKeyTests.swift @@ -0,0 +1,174 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2021 Marcin Krzyżanowski +// 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. +// + +#if canImport(Security) + + import Security + import XCTest + @testable import CryptoSwift + + final class RSASecKeyTests: XCTestCase { + + // MARK: SecKey <-> RSA Interoperability + + /// From RSA -> External Representation -> SecKey + func testRSAExternalRepresentationPrivate() throws { + + /// Generate a CryptoSwift RSA Key + let rsaCryptoSwift = try RSA(keySize: 1024) + + /// Get the key's rawExternalRepresentation + let rsaCryptoSwiftRawRep = try rsaCryptoSwift.privateKeyDER() + + /// We should be able to instantiate an RSA SecKey from this data + let attributes: [String: Any] = [ + kSecAttrKeyType as String: kSecAttrKeyTypeRSA, + kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, + kSecAttrKeySizeInBits as String: 1024, + kSecAttrIsPermanent as String: false + ] + var error: Unmanaged? + guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else { + XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)") + return + } + + /// Get the SecKey's external representation + var externalRepError: Unmanaged? + guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match + XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep)) + XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) + } + + /// From RSA -> External Representation -> SecKey + func testRSAExternalRepresentationPublic() throws { + + /// Generate a CryptoSwift RSA Key + let rsaCryptoSwift = try RSA(keySize: 1024) + + /// Get the key's rawExternalRepresentation + let rsaCryptoSwiftRawRep = try rsaCryptoSwift.publicKeyDER() + + /// We should be able to instantiate an RSA SecKey from this data + let attributes: [String: Any] = [ + kSecAttrKeyType as String: kSecAttrKeyTypeRSA, + kSecAttrKeyClass as String: kSecAttrKeyClassPublic, + kSecAttrKeySizeInBits as String: 1024, + kSecAttrIsPermanent as String: false + ] + var error: Unmanaged? + guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else { + XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)") + return + } + + /// Get the SecKey's external representation + var externalRepError: Unmanaged? + guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match + XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep)) + XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.publicKeyExternalRepresentation()) + } + + /// SecKey -> External Representation -> CryptoSwift RSA + func testSecKeyExternalRepresentationPrivate() throws { + /// Generate a SecKey RSA Key + let parameters: [CFString: Any] = [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeySizeInBits: 1024 + ] + + var error: Unmanaged? + + // Generate the RSA SecKey + guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { + XCTFail("Key Generation Error: \(error.debugDescription)") + return + } + + /// Lets grab the external representation + var externalRepError: Unmanaged? + guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + // Ensure we can import the private RSA key into CryptoSwift + let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep) + + XCTAssertNotNil(rsaCryptoSwift.d) + XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) + } + + /// SecKey -> External Representation -> CryptoSwift RSA + func testSecKeyExternalRepresentationPublic() throws { + /// Generate a SecKey RSA Key + let parameters: [CFString: Any] = [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeySizeInBits: 1024 + ] + + var error: Unmanaged? + + // Generate the RSA SecKey + guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { + XCTFail("Key Generation Error: \(error.debugDescription)") + return + } + + // Extract the public key from the private RSA SecKey + guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else { + XCTFail("Public Key Extraction Error") + return + } + + /// Lets grab the external representation of the public key + var externalRepError: Unmanaged? + guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &externalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + // Ensure we can import the private RSA key into CryptoSwift + let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep) + + XCTAssertNil(rsaCryptoSwift.d) + XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) + } + } + + extension RSASecKeyTests { + static func allTests() -> [(String, (RSASecKeyTests) -> () throws -> Void)] { + let tests = [ + ("testRSAExternalRepresentationPrivate", testRSAExternalRepresentationPrivate), + ("testRSAExternalRepresentationPublic", testRSAExternalRepresentationPublic), + ("testSecKeyExternalRepresentationPrivate", testSecKeyExternalRepresentationPrivate), + ("testSecKeyExternalRepresentationPublic", testSecKeyExternalRepresentationPublic) + ] + + return tests + } + } + +#endif