@@ -198,4 +198,95 @@ public class PlayKeychain: NSObject {
198198
199199 return errSecItemNotFound
200200 }
201+
202+ @objc static public func keyCreateRandomKey( _ parameters: NSDictionary ,
203+ error: UnsafeMutablePointer < Unmanaged < CFError > ? > ? )
204+ -> Unmanaged < SecKey > ? {
205+ // Check if kSecAttrIsPermanent is set to 1 in kSecPrivateKeyAttrs.
206+ // If it is, set it to 0 before fowarding the call to SecKeyCreateRandomKey,
207+ // and then add the key to the keychain db with the original attributes (with kSecAttrIsPermanent set to 1)
208+ var privateKeyAttrs = parameters [ kSecPrivateKeyAttrs as String ] as? [ String : Any ] ?? [ : ]
209+ let isPermanent = privateKeyAttrs [ kSecAttrIsPermanent as String ] as? Bool ?? false
210+ if isPermanent {
211+ privateKeyAttrs [ kSecAttrIsPermanent as String ] = false
212+ }
213+ var parametersCopy = parameters as! [ String : Any ] // swiftlint:disable:this force_cast
214+ parametersCopy [ kSecPrivateKeyAttrs as String ] = privateKeyAttrs
215+ var error : Unmanaged < CFError > ?
216+ guard let key = SecKeyCreateRandomKey ( parametersCopy as CFDictionary , & error) else {
217+ debugLogger ( " Failed to create random key: \( error!. takeRetainedValue ( ) ) " )
218+ return nil
219+ }
220+ if isPermanent {
221+ // Add the key to the keychain db with the original attributes
222+ var keychainDict = [ String: Any] ( )
223+ keychainDict [ kSecClass as String ] = kSecClassKey
224+ keychainDict [ kSecAttrKeyType as String ] = parameters [ kSecAttrKeyType as String ]
225+ keychainDict [ kSecAttrKeyClass as String ] = parameters [ kSecAttrKeyClass as String ]
226+ keychainDict [ " type " ] = parameters [ kSecAttrKeyType as String ]
227+ keychainDict [ " kcls " ] = parameters [ kSecAttrKeyClass as String ]
228+ keychainDict [ " v_Data " ] = SecKeyCopyExternalRepresentation ( key, nil ) as? Data
229+ keychainDict [ " r_Attributes " ] = 1
230+ guard playChainDB. insert ( keychainDict as NSDictionary ) != nil else {
231+ debugLogger ( " Failed to write keychain file " )
232+ return nil
233+ }
234+ }
235+ return Unmanaged . passRetained ( key)
236+ }
237+
238+ @objc static public func keyGeneratePair( _ parameters: NSDictionary ,
239+ publicKey: UnsafeMutablePointer < Unmanaged < SecKey > ? > ? ,
240+ privateKey: UnsafeMutablePointer < Unmanaged < SecKey > ? > ? ) -> OSStatus {
241+ // Same as above but we need to disable kSecAttrIsPermanent for both the public and private key.
242+ var privateKeyAttrs = parameters [ kSecPrivateKeyAttrs as String ] as? [ String : Any ] ?? [ : ]
243+ let isPrivatePermanent = privateKeyAttrs [ kSecAttrIsPermanent as String ] as? Bool ?? false
244+ if isPrivatePermanent {
245+ privateKeyAttrs [ kSecAttrIsPermanent as String ] = false
246+ }
247+ var publicKeyAttrs = parameters [ kSecPublicKeyAttrs as String ] as? [ String : Any ] ?? [ : ]
248+ let isPublicPermanent = ( publicKeyAttrs [ kSecAttrIsPermanent as String ] as? Bool ) ?? false
249+ if isPublicPermanent {
250+ publicKeyAttrs [ kSecAttrIsPermanent as String ] = false
251+ }
252+ var parametersCopy = parameters as! [ String : Any ] // swiftlint:disable:this force_cast
253+ parametersCopy [ kSecPrivateKeyAttrs as String ] = privateKeyAttrs
254+ parametersCopy [ kSecPublicKeyAttrs as String ] = publicKeyAttrs
255+ var newPublicKey : SecKey ?
256+ var newPrivateKey : SecKey ?
257+ guard SecKeyGeneratePair ( parametersCopy as CFDictionary , & newPublicKey, & newPrivateKey) != 0 else {
258+ debugLogger ( " Failed to generate key pair. " )
259+ return errSecMissingEntitlement
260+ }
261+ if isPrivatePermanent {
262+ // Add the keys to the keychain db with the original attributes
263+ let publicKeyRef = newPublicKey
264+ let privateKeyRef = newPrivateKey
265+ var publicKeyDict = [ String: Any] ( )
266+ publicKeyDict [ kSecClass as String ] = kSecClassKey
267+ publicKeyDict [ kSecAttrKeyType as String ] = parameters [ kSecAttrKeyType as String ]
268+ publicKeyDict [ kSecAttrKeyClass as String ] = kSecAttrKeyClassPublic
269+ publicKeyDict [ " type " ] = parameters [ kSecAttrKeyType as String ]
270+ publicKeyDict [ " kcls " ] = kSecAttrKeyClassPublic
271+ publicKeyDict [ " v_Data " ] = SecKeyCopyExternalRepresentation ( publicKeyRef!, nil ) as? Data
272+ publicKeyDict [ " r_Attributes " ] = 1
273+ guard playChainDB. insert ( publicKeyDict as NSDictionary ) != nil else {
274+ debugLogger ( " Failed to write public key to keychain db " )
275+ return errSecMissingEntitlement
276+ }
277+ var privateKeyDict = [ String: Any] ( )
278+ privateKeyDict [ kSecClass as String ] = kSecClassKey
279+ privateKeyDict [ kSecAttrKeyType as String ] = parameters [ kSecAttrKeyType as String ]
280+ privateKeyDict [ kSecAttrKeyClass as String ] = kSecAttrKeyClassPrivate
281+ privateKeyDict [ " type " ] = parameters [ kSecAttrKeyType as String ]
282+ privateKeyDict [ " kcls " ] = kSecAttrKeyClassPrivate
283+ privateKeyDict [ " v_Data " ] = SecKeyCopyExternalRepresentation ( privateKeyRef!, nil ) as? Data
284+ privateKeyDict [ " r_Attributes " ] = 1
285+ guard playChainDB. insert ( privateKeyDict as NSDictionary ) != nil else {
286+ debugLogger ( " Failed to write private key to keychain db " )
287+ return errSecMissingEntitlement
288+ }
289+ }
290+ return errSecSuccess
291+ }
201292}
0 commit comments