Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share between an iOS extension and its containing app with the keychain?

Tags:

I understand I can share data between my share extension and its containing app by enabling app groups and using NSUserDefaults (see Sharing data between an iOS 8 share extension and main app).

However, the data I am storing is sensitive, so I hoped to use the keychain. So the user would enter account information in the containing app, and then the share extension would read that data to perform the intended sharing action.

Does anyone know if this is possible? My first crack at it suggests that the extension and the containing app have separate keychains (saving the data with a key in the containing app returns null when attempting to return data for that key in the extension).

Thanks!

P.S. Using Lockbox for Keychain access, but I could ditch it if it's too much of an abstraction to make it work. https://github.com/granoff/Lockbox

like image 934
Jim Biancolo Avatar asked Nov 01 '14 22:11

Jim Biancolo


People also ask

What is keychain sharing in iOS?

Keychain sharing is used when we want to share some data securely between two or more applications from the same developer. Suppose we want to share some critical data(like username and password) between two apps.

How do I turn on keychain sharing in iOS?

In Xcode, go to Project settings > Capabilities. Enable Keychain Sharing. Add a keychain group identifier. Use the same identifier for all of the apps you want to share state.

What is the extension of apps in iOS?

An . ipa file is an iOS and iPadOS application archive file which stores an iOS/iPadOS app.

Is iOS keychain secure?

Everything stored in iCloud Keychain is secure—it's protected by industry-standard encryption. Your iCloud Keychain can't be set up on another Mac or iOS or iPadOS device unless you approve it.


1 Answers

To make the Keychain shared in Xcode 8.

1) In your App target in Capabilities find and turn on "Keychain Sharing", add a Keychain Group key (a reverse-domain style string like com.myappdomain.myappname)

2) Do exactly the same for the extension target. Make sure the Keychain Group key is the same for both - the app and the extension.

Add and retrieve data from Keychain in your usual way, no special changes required in the code. For example, here's how I put data into Keychain in the main app (a little old-fashioned but still works in Swift 3):

let login = loginString let domain = domainString let passwordData: Data = passwordString.data(using: String.Encoding.utf8, allowLossyConversion: false)! let keychainQuery: [NSString: NSObject] = [     kSecClass: kSecClassGenericPassword,     kSecAttrAccount: login as NSObject,  // login and domain strings help identify     kSecAttrService: domain as NSObject, // the required record in the Keychain     kSecValueData: passwordData as NSObject] SecItemDelete(keychainQuery as CFDictionary) //Deletes the item just in case it already exists let keychainSaveStatus: OSStatus = SecItemAdd(keychainQuery as CFDictionary, nil) 

And then retrieve it in the extension:

let keychainQuery: [NSString: NSObject] = [     kSecClass: kSecClassGenericPassword,     kSecAttrAccount: login as NSObject,     kSecAttrService: domain as NSObject,     kSecReturnData: kCFBooleanTrue,     kSecMatchLimit: kSecMatchLimitOne] var rawResult: AnyObject? let keychain_get_status: OSStatus = SecItemCopyMatching(keychainQuery as CFDictionary, &rawResult)  if (keychain_get_status == errSecSuccess) {     if let retrievedData = rawResult as? Data,         let password = String(data: retrievedData, encoding: String.Encoding.utf8) {        // "password" contains the password string now     } } 

Note that you will still need to pass "login" and "domain" over to the extension in order to identify the correct record. This can be done via NSUserDefaults. See this answer on how to do this.

like image 54
Vitalii Avatar answered Oct 01 '22 03:10

Vitalii