RSASecKeyTests.swift 20 KB

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