RSASecKeyTests.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //
  2. // CryptoSwift
  3. //
  4. // Copyright (C) 2014-2021 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
  5. // This software is provided 'as-is', without any express or implied warranty.
  6. //
  7. // In no event will the authors be held liable for any damages arising from the use of this software.
  8. //
  9. // 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:
  10. //
  11. // - 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.
  12. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  13. // - This notice may not be removed or altered from any source or binary distribution.
  14. //
  15. #if canImport(Security)
  16. import Security
  17. import XCTest
  18. @testable import CryptoSwift
  19. final class RSASecKeyTests: XCTestCase {
  20. // MARK: SecKey <-> RSA Interoperability
  21. /// From CryptoSwift RSA -> External Representation -> SecKey
  22. ///
  23. /// This test enforces that
  24. /// 1) We can export the raw external representation of a CryptoSwift RSA Public Key
  25. /// 2) And that we can import / create an RSA SecKey from that raw external representation
  26. /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift`
  27. func testRSAExternalRepresentationPublic() throws {
  28. // Generate a CryptoSwift RSA Key
  29. let rsaCryptoSwift = try RSA(keySize: 1024)
  30. // Get the key's rawExternalRepresentation
  31. let rsaCryptoSwiftRawRep = try rsaCryptoSwift.publicKeyDER()
  32. // We should be able to instantiate an RSA SecKey from this data
  33. let attributes: [String: Any] = [
  34. kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
  35. kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
  36. kSecAttrKeySizeInBits as String: 1024,
  37. kSecAttrIsPermanent as String: false
  38. ]
  39. var error: Unmanaged<CFError>?
  40. guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else {
  41. XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)")
  42. return
  43. }
  44. // Get the SecKey's external representation
  45. var externalRepError: Unmanaged<CFError>?
  46. guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
  47. XCTFail("Failed to copy external representation for RSA SecKey")
  48. return
  49. }
  50. // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match
  51. XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep))
  52. XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.publicKeyExternalRepresentation())
  53. }
  54. /// From CryptoSwift RSA -> External Representation -> SecKey
  55. ///
  56. /// This test enforces that
  57. /// 1) We can export the raw external representation of a CryptoSwift RSA Private Key
  58. /// 2) And that we can import / create an RSA SecKey from that raw external representation
  59. /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift`
  60. func testRSAExternalRepresentationPrivate() throws {
  61. // Generate a CryptoSwift RSA Key
  62. let rsaCryptoSwift = try RSA(keySize: 1024)
  63. // Get the key's rawExternalRepresentation
  64. let rsaCryptoSwiftRawRep = try rsaCryptoSwift.privateKeyDER()
  65. // We should be able to instantiate an RSA SecKey from this data
  66. let attributes: [String: Any] = [
  67. kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
  68. kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
  69. kSecAttrKeySizeInBits as String: 1024,
  70. kSecAttrIsPermanent as String: false
  71. ]
  72. var error: Unmanaged<CFError>?
  73. guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else {
  74. XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)")
  75. return
  76. }
  77. // Get the SecKey's external representation
  78. var externalRepError: Unmanaged<CFError>?
  79. guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
  80. XCTFail("Failed to copy external representation for RSA SecKey")
  81. return
  82. }
  83. // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match
  84. XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep))
  85. XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation())
  86. }
  87. /// From SecKey -> External Representation -> CryptoSwift RSA
  88. ///
  89. /// This test enforces that
  90. /// 1) Given the raw external representation of a Public RSA SecKey, we can import that same key into CryptoSwift
  91. /// 2) When we export the raw external representation of the RSA Key we get the exact same data
  92. /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift`
  93. func testSecKeyExternalRepresentationPublic() throws {
  94. // Generate a SecKey RSA Key
  95. let parameters: [CFString: Any] = [
  96. kSecAttrKeyType: kSecAttrKeyTypeRSA,
  97. kSecAttrKeySizeInBits: 1024
  98. ]
  99. var error: Unmanaged<CFError>?
  100. // Generate the RSA SecKey
  101. guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else {
  102. XCTFail("Key Generation Error: \(error.debugDescription)")
  103. return
  104. }
  105. // Extract the public key from the private RSA SecKey
  106. guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else {
  107. XCTFail("Public Key Extraction Error")
  108. return
  109. }
  110. // Let's grab the external representation of the public key
  111. var externalRepError: Unmanaged<CFError>?
  112. guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &externalRepError) as? Data else {
  113. XCTFail("Failed to copy external representation for RSA SecKey")
  114. return
  115. }
  116. // Ensure we can import the private RSA key into CryptoSwift
  117. let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep)
  118. XCTAssertNil(rsaCryptoSwift.d)
  119. XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation())
  120. }
  121. /// From SecKey -> External Representation -> CryptoSwift RSA
  122. ///
  123. /// This test enforces that
  124. /// 1) Given the raw external representation of a Private RSA SecKey, we can import that same key into CryptoSwift
  125. /// 2) When we export the raw external representation of the RSA Key we get the exact same data
  126. /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift`
  127. func testSecKeyExternalRepresentationPrivate() throws {
  128. // Generate a SecKey RSA Key
  129. let parameters: [CFString: Any] = [
  130. kSecAttrKeyType: kSecAttrKeyTypeRSA,
  131. kSecAttrKeySizeInBits: 1024
  132. ]
  133. var error: Unmanaged<CFError>?
  134. // Generate the RSA SecKey
  135. guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else {
  136. XCTFail("Key Generation Error: \(error.debugDescription)")
  137. return
  138. }
  139. // Let's grab the external representation
  140. var externalRepError: Unmanaged<CFError>?
  141. guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
  142. XCTFail("Failed to copy external representation for RSA SecKey")
  143. return
  144. }
  145. // Ensure we can import the private RSA key into CryptoSwift
  146. let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep)
  147. XCTAssertNotNil(rsaCryptoSwift.d)
  148. XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation())
  149. }
  150. /// This test generates X RSA keys and tests them between `Security` and `CryptoSwift` for interoperability
  151. ///
  152. /// For each key generated, this test enforces that
  153. /// 1) We can import the raw external representation (generated by the `Security` framework) of the RSA Key into `CryptoSwift`
  154. /// 2) When signing messages using a deterministic variant, we get the same output from both `Security` and `CryptoSwift`
  155. /// 3) We can verify a signature generated from `CryptoSwift` with `Security` and vice versa
  156. /// 4) We can encrypt and decrypt a message generated from `CryptoSwift` with `Security` and vice versa
  157. func testRSASecKeys() throws {
  158. let tests = 3
  159. let messageToSign: String = "RSA Keys!"
  160. for _ in 0..<tests {
  161. // Generate a SecKey RSA Key
  162. let parameters: [CFString: Any] = [
  163. kSecAttrKeyType: kSecAttrKeyTypeRSA,
  164. kSecAttrKeySizeInBits: 1024
  165. ]
  166. var error: Unmanaged<CFError>?
  167. // Generate the RSA SecKey
  168. guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else {
  169. XCTFail("Key Generation Error: \(error.debugDescription)")
  170. break
  171. }
  172. // Let's grab the external representation
  173. var externalRepError: Unmanaged<CFError>?
  174. guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
  175. XCTFail("Failed to copy external representation for RSA SecKey")
  176. break
  177. }
  178. // Ensure we can import the private RSA key into CryptoSwift
  179. let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep)
  180. // Sign the message with both keys and ensure they're the same (the pkcs1v15 signature variant is deterministic)
  181. let csSignature = try rsaCryptoSwift.sign(messageToSign.bytes, variant: .message_pkcs1v15_SHA256)
  182. let skSignature = try secKeySign(messageToSign.bytes, variant: .rsaSignatureMessagePKCS1v15SHA256, withKey: rsaSecKey)
  183. XCTAssertEqual(csSignature, skSignature.bytes, "Signatures don't match!")
  184. // Ensure we can verify each signature using the opposite library
  185. XCTAssertTrue(try rsaCryptoSwift.verify(signature: skSignature.bytes, for: messageToSign.bytes, variant: .message_pkcs1v15_SHA256))
  186. XCTAssertTrue(try self.secKeyVerify(csSignature, forBytes: messageToSign.bytes, usingVariant: .rsaSignatureMessagePKCS1v15SHA256, withKey: rsaSecKey))
  187. // Encrypt with SecKey
  188. let skEncryption = try secKeyEncrypt(messageToSign.bytes, usingVariant: .rsaEncryptionRaw, withKey: rsaSecKey)
  189. // Decrypt with CryptoSwift Key
  190. XCTAssertEqual(try rsaCryptoSwift.decrypt(skEncryption.bytes, variant: .raw), messageToSign.bytes, "CryptoSwift Decryption of SecKey Encryption Failed")
  191. // Encrypt with CryptoSwift
  192. let csEncryption = try rsaCryptoSwift.encrypt(messageToSign.bytes, variant: .raw)
  193. // Decrypt with SecKey
  194. XCTAssertEqual(try self.secKeyDecrypt(csEncryption, usingVariant: .rsaEncryptionRaw, withKey: rsaSecKey).bytes, messageToSign.bytes, "SecKey Decryption of CryptoSwift Encryption Failed")
  195. XCTAssertEqual(csEncryption, skEncryption.bytes, "Encrypted Data Does Not Match")
  196. // Encrypt with SecKey
  197. let skEncryption2 = try secKeyEncrypt(messageToSign.bytes, usingVariant: .rsaEncryptionPKCS1, withKey: rsaSecKey)
  198. // Decrypt with CryptoSwift Key
  199. XCTAssertEqual(try rsaCryptoSwift.decrypt(skEncryption2.bytes, variant: .pksc1v15), messageToSign.bytes, "CryptoSwift Decryption of SecKey Encryption Failed")
  200. // Encrypt with CryptoSwift
  201. let csEncryption2 = try rsaCryptoSwift.encrypt(messageToSign.bytes, variant: .pksc1v15)
  202. // Decrypt with SecKey
  203. XCTAssertEqual(try self.secKeyDecrypt(csEncryption2, usingVariant: .rsaEncryptionPKCS1, withKey: rsaSecKey).bytes, messageToSign.bytes, "SecKey Decryption of CryptoSwift Encryption Failed")
  204. }
  205. }
  206. private func secKeySign(_ bytes: Array<UInt8>, variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data {
  207. var error: Unmanaged<CFError>?
  208. // Sign the data
  209. guard let signature = SecKeyCreateSignature(
  210. key,
  211. variant,
  212. Data(bytes) as CFData,
  213. &error
  214. ) as Data?
  215. else { throw NSError(domain: "Failed to sign bytes: \(bytes)", code: 0) }
  216. return signature
  217. }
  218. private func secKeyVerify(_ signature: Array<UInt8>, forBytes bytes: Array<UInt8>, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Bool {
  219. let pubKey = SecKeyCopyPublicKey(key)!
  220. var error: Unmanaged<CFError>?
  221. // Perform the signature verification
  222. let result = SecKeyVerifySignature(
  223. pubKey,
  224. variant,
  225. Data(bytes) as CFData,
  226. Data(signature) as CFData,
  227. &error
  228. )
  229. // Throw the error if we encountered one...
  230. if let error = error { throw error.takeRetainedValue() as Error }
  231. // return the result of the verification
  232. return result
  233. }
  234. private func secKeyEncrypt(_ bytes: Array<UInt8>, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data {
  235. let pubKey = SecKeyCopyPublicKey(key)!
  236. var error: Unmanaged<CFError>?
  237. guard let encryptedData = SecKeyCreateEncryptedData(pubKey, variant, Data(bytes) as CFData, &error) else {
  238. throw NSError(domain: "Error Encrypting Data: \(error.debugDescription)", code: 0, userInfo: nil)
  239. }
  240. // Throw the error if we encountered one...
  241. if let error = error { throw error.takeRetainedValue() as Error }
  242. // return the result of the encryption
  243. return encryptedData as Data
  244. }
  245. private func secKeyDecrypt(_ bytes: Array<UInt8>, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data {
  246. var error: Unmanaged<CFError>?
  247. guard let decryptedData = SecKeyCreateDecryptedData(key, variant, Data(bytes) as CFData, &error) else {
  248. throw NSError(domain: "Error Decrypting Data: \(error.debugDescription)", code: 0, userInfo: nil)
  249. }
  250. return (decryptedData as Data).drop { $0 == 0x00 }
  251. }
  252. }
  253. extension RSASecKeyTests {
  254. static func allTests() -> [(String, (RSASecKeyTests) -> () throws -> Void)] {
  255. let tests = [
  256. ("testRSAExternalRepresentationPublic", testRSAExternalRepresentationPublic),
  257. ("testRSAExternalRepresentationPrivate", testRSAExternalRepresentationPrivate),
  258. ("testSecKeyExternalRepresentationPublic", testSecKeyExternalRepresentationPublic),
  259. ("testSecKeyExternalRepresentationPrivate", testSecKeyExternalRepresentationPrivate),
  260. ("testRSASecKeys", testRSASecKeys)
  261. ]
  262. return tests
  263. }
  264. }
  265. // - MARK: Test Fixture Generation Code
  266. extension RSASecKeyTests {
  267. /// This 'Test' generates an RSA Key and uses that key to sign and encrypt a series of messages that we can test against.
  268. ///
  269. /// It prints a `Fixture` object that can be copy and pasted / used in other tests.
  270. func testCreateTestFixture() throws {
  271. let keySize = 1024
  272. let messages = [
  273. "",
  274. "👋",
  275. "RSA Keys",
  276. "CryptoSwift RSA Keys!",
  277. "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐"
  278. ]
  279. print(messages.map { $0.bytes.count })
  280. /// Generate a SecKey RSA Key
  281. let parameters: [CFString: Any] = [
  282. kSecAttrKeyType: kSecAttrKeyTypeRSA,
  283. kSecAttrKeySizeInBits: keySize
  284. ]
  285. var error: Unmanaged<CFError>?
  286. // Generate the RSA SecKey
  287. guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else {
  288. XCTFail("Key Generation Error: \(error.debugDescription)")
  289. return
  290. }
  291. // Extract the public key from the private RSA SecKey
  292. guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else {
  293. XCTFail("Public Key Extraction Error")
  294. return
  295. }
  296. /// Let's grab the external representation of the public key
  297. var publicExternalRepError: Unmanaged<CFError>?
  298. guard let publicRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &publicExternalRepError) as? Data else {
  299. XCTFail("Failed to copy external representation for RSA SecKey")
  300. return
  301. }
  302. /// Let's grab the external representation of the private key
  303. var privateExternalRepError: Unmanaged<CFError>?
  304. guard let privateRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &privateExternalRepError) as? Data else {
  305. XCTFail("Failed to copy external representation for RSA SecKey")
  306. return
  307. }
  308. var template = RSASecKeyTests.FixtureTemplate
  309. template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: "\(keySize)")
  310. template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(publicRSASecKeyRawRep.base64EncodedString())")
  311. template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(privateRSASecKeyRawRep.base64EncodedString())")
  312. var messageEntries: [String] = []
  313. for message in messages {
  314. var messageTemplate = RSASecKeyTests.MessageTemplate
  315. messageTemplate = messageTemplate.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message)
  316. let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: rsaSecKeyPublic)
  317. messageTemplate = messageTemplate.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t\t "))
  318. let signedMessages = try sign(message: message.data(using: .utf8)!, using: rsaSecKey)
  319. messageTemplate = messageTemplate.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t\t "))
  320. messageEntries.append(messageTemplate)
  321. }
  322. template = template.replacingOccurrences(of: "{{MESSAGE_TEMPLATES}}", with: "\(messageEntries.joined(separator: ",\n\t"))")
  323. print("\n**************************")
  324. print(" Test Fixture Output ")
  325. print("**************************\n")
  326. print(template)
  327. print("\n**************************")
  328. }
  329. private static let FixtureTemplate = """
  330. static let RSA_{{KEY_SIZE}} = Fixture(
  331. keySize: {{KEY_SIZE}},
  332. publicDER: \"\"\"
  333. {{PUBLIC_DER}}
  334. \"\"\",
  335. privateDER: \"\"\"
  336. {{PRIVATE_DER}}
  337. \"\"\",
  338. messages: [
  339. {{MESSAGE_TEMPLATES}}
  340. ]
  341. )
  342. """
  343. private static let MessageTemplate = """
  344. "{{PLAINTEXT_MESSAGE}}": (
  345. encryptedMessage: [
  346. {{ENCRYPTED_MESSAGES}}
  347. ],
  348. signedMessage: [
  349. {{SIGNED_MESSAGES}}
  350. ]
  351. )
  352. """
  353. private func initSecKey(rawRepresentation unsafe: Data) throws -> SecKey {
  354. let attributes: [String: Any] = [
  355. kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
  356. kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
  357. kSecAttrKeySizeInBits as String: 1024,
  358. kSecAttrIsPermanent as String: false
  359. ]
  360. var error: Unmanaged<CFError>?
  361. guard let secKey = SecKeyCreateWithData(unsafe as CFData, attributes as CFDictionary, &error) else {
  362. throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil)
  363. }
  364. return secKey
  365. }
  366. // We don't support PSS yet so we skip these variants
  367. private func sign(message: Data, using key: SecKey) throws -> [String] {
  368. let algorithms: [SecKeyAlgorithm] = [
  369. .rsaSignatureRaw,
  370. //.rsaSignatureDigestPSSSHA1,
  371. //.rsaSignatureDigestPSSSHA224,
  372. //.rsaSignatureDigestPSSSHA256,
  373. //.rsaSignatureDigestPSSSHA384,
  374. //.rsaSignatureDigestPSSSHA512,
  375. .rsaSignatureDigestPKCS1v15Raw,
  376. .rsaSignatureDigestPKCS1v15SHA1,
  377. .rsaSignatureDigestPKCS1v15SHA224,
  378. .rsaSignatureDigestPKCS1v15SHA256,
  379. .rsaSignatureDigestPKCS1v15SHA384,
  380. .rsaSignatureDigestPKCS1v15SHA512,
  381. //.rsaSignatureMessagePSSSHA1,
  382. //.rsaSignatureMessagePSSSHA224,
  383. //.rsaSignatureMessagePSSSHA256,
  384. //.rsaSignatureMessagePSSSHA384,
  385. //.rsaSignatureMessagePSSSHA512,
  386. .rsaSignatureMessagePKCS1v15SHA1,
  387. .rsaSignatureMessagePKCS1v15SHA224,
  388. .rsaSignatureMessagePKCS1v15SHA256,
  389. .rsaSignatureMessagePKCS1v15SHA384,
  390. .rsaSignatureMessagePKCS1v15SHA512,
  391. ]
  392. var sigs: [String] = []
  393. for algo in algorithms {
  394. var error: Unmanaged<CFError>?
  395. // Sign the data
  396. guard let signature = SecKeyCreateSignature(
  397. key,
  398. algo,
  399. message as CFData,
  400. &error
  401. ) as Data?
  402. else {
  403. print("\"\(algo.rawValue)\": \"nil\",")
  404. sigs.append("\"\(algo.rawValue)\": \"\"")
  405. continue
  406. }
  407. // Throw the error if we encountered one
  408. if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue }
  409. // Append the signature
  410. sigs.append("\"\(algo.rawValue)\": \"\(signature.base64EncodedString())\"")
  411. }
  412. return sigs
  413. }
  414. private func encrypt(data: Data, with key: SecKey) throws -> [String] {
  415. let algorithms: [SecKeyAlgorithm] = [
  416. .rsaEncryptionRaw,
  417. .rsaEncryptionPKCS1
  418. ]
  419. var encryptions: [String] = []
  420. for algo in algorithms {
  421. var error: Unmanaged<CFError>?
  422. guard let encryptedData = SecKeyCreateEncryptedData(key, algo, data as CFData, &error) as? Data else {
  423. print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\",")
  424. encryptions.append("\"\(algo.rawValue)\": \"\"")
  425. continue
  426. }
  427. encryptions.append("\"\(algo.rawValue)\": \"\(encryptedData.base64EncodedString())\"")
  428. }
  429. return encryptions
  430. }
  431. }
  432. #endif