How to save RSA publicKey/privateKey NOT in Keychain - ios

i have a question about saving Keys within iOS applications.
Is there any way to save the public/private Key of an RSA-certificate within an app, not to save/store this in the iOS keychain.
Maybe someone tried this out before?
I found something similar with username and password. Its called "Keychainwrapper". There the app saves the login credentials within the app. Does this work for me with private/public keys?
Hopefully someone can help me.
Best regards,
Andi

Since you have to store only public and private key and not the whole certificate, can not use the internal keychain and the keys are generated on the device it would be sufficient if you save your public and private key in the NSUserDefaults:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
//saving the data
[prefs setObject"<your public key data>" forKey:#"PublicKey"];
[prefs setObject"<your private key data>" forKey:#"PrivateKey"];
//reading the data
NSString *publicKey = [prefs stringForKey:#"PublicKey"];
NSString *privateKey = [prefs stringForKey:#"PrivateKey"];
This store is rather insecure, so I would suggest that you encrypt your data like this: iOS 5: Data encryption AES-256 EncryptWithKey: not found. Be aware, that symmetric encryption is not secure if you store the key in your application! You should use some user input to generate the key.
Hope this helps.

Related

How to set cookies for UIWebView after loaded?

Here is the situation:
there is a webView in my native app, and some operations need to interact with native app.
e.g.: The follow operation, if user has logged in when follow, then everything goes fine.(the webView knows there is a user logged in according to the existed cookies)
but if user has not logged in yet when follow, then it will present the login View Controller(which is native), and after user finish logging in(will response with the new cookie that mark user as logged-in),it's expected that follow operation will continue automatically.
The problem is it seems like the webView doesn't know user has logged in without reloading.
Thanks for any suggestions or corrections.
You can save the cookies using this :
NSData *cookiesData = [NSKeyedArchiver archivedDataWithRootObject: [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject: cookiesData forKey: #"cookies"];
[defaults synchronize];

Trying To Make Sense of RNCryptor

I am working on a project and we need to encrypt some user credentials (username, password, userId, ect.) to pass to our server. We have decided to use AES256 in order to achieve this. Doing some research on this subject it was hard to avoid noticing a project out there, RNCryptor that claims to be an easy-to-use solution to this problem.
So I included the framework into my project and soon realized it was not as straight forward as I thought. I was hoping for a solution to where I could encrypt my credential strings by simply - (1) derive a key that I would like to encrypt my stringed credentials with, (2) pass the key and my string into the appropriate RNCryptor's method, (3) retrieve my encrypted string back from said method.
This would be too good to be true however.
The reality of RNCryptor is that it has methods like this:
[RNEncryptor encryptData:someData
withSettings:kRNCryptorAES256Settings
password:someString
error:&someError];
This is confusing because of the terminology.
WHAT IS PASSWORD?
This is never explained. A password for what? Is this for a user password I want to encrypt, the password key that I want to encrypt with, or the password to login to my computer (sarcasm).
ENCRYPT DATA?
Is this a UTF8 encoded string of what the user credentials that I want to encrypt? That is my best guess but again, not explained in the RNCryptor Github "documentation".
password is used to generate the encryption key, it is an NSString the data is encrypted with. encryptData is the data to encrypt and is an NSData.
Encryption works with data, that an array of 8-bit bytes. You need to convert whatever you have to an NSData. For an NSString there is the method:
NSData *dataToBeEncrypted = [myString dataUsingEncoding:NSUTF8StringEncoding];
and
NSString *myString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
Additionally it requires an encryption key, RNCryptor takes an NSString and derives an encryption key from it.
There are of course options and while most of these handles internally by RNCryptor there still some available to the developer using it.
There two main versions with more options, you are probably best off using the password version.
One taking a NSString password:
+ (NSData *)encryptData:(NSData *)data withSettings:(RNCryptorSettings)settings password:(NSString *)password error:(NSError **)error;
A second taking an NSData encryption key as well as a NSData authentication key.
+ (NSData *)encryptData:(NSData *)data withSettings:(RNCryptorSettings)settings encryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)error;
RNCryptor is you best choice, it handles key derivation from a password, a random IV, authentication of the encrypted data and padding.

Authentication with iOS/Swift

I have a very simple question, I have a node.js/express server that will handle backend authentication part, it is using token not cookies, the server part is working correctly, whenever someone register/login it would return with a JSON web token.
For example:
{
"token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdW"
}
I'm using Alamofire to handle the HTTP request from iOS itself. The real question lies is how do I persist the token in the iOS/Swift itself?
What is the simplest way to do this?
You should use the iOS Keychain to save sensitive information.
You should not use NSUserDefaults to store an authentication token or any other potentially sensitive information. It's unencrypted and easily accessible on a rooted device.
How would you like someone getting your authentication token and making requests to your private API at will (e.g. on the command line using curl)?
I've used the KeychainAccess CocoaPod and its usage is simple:
static let keychain = Keychain(service: "com.example.myapp")
keychain["secret_code"] = secretCode // Save something
let secretCode = keychain["secret_code"] // Retrieve something
The simplest way is to store it in NSUserDefaults like this:
Writing:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Your Variable Value", forKey: "token")
Reading:
let defaults = NSUserDefaults.standardUserDefaults()
if let token = defaults.stringForKey("token") {
print(name)
}
The simplest way may be NSUserDefaults, but the most secure way would be to store the token in the iOS Keychain. Note there are several wrapper libraries (for example) available to make working with the keychain easier in Swift. The API can be a bit intimidating at times.

ios storing login token in KeyChain fails to retrieve, rarely and randomly, but consistently

I'm using the ios keychain (keychainItemWrapper / SSKeychain) to store my app's login token and maintain logged in state. Currently I store a simple NSDictionary in the keychain containing my token, a token expiry and a refresh token. I serialize it to NSData and storing using kSecValueData. I also set the kSecAttrAccount and kSecAttrService, but don't use those for auth.
This works great, about 95% of the time. The problem is that that randomly, unpredictably and sporadically, the keychain does not return data when I request it to retrieve the token. It is usually after a moderate time away from the app, when reopening it. It doesn't have to be from in background, or after any specific delay though.
It fails specifically when asking for my NSData below and returns <> instead of <ABCD EFGH IJKL ....>. I think it is nil. Thus the code thinks the user isn't logged in and drops them immediately on my App's Signup/Login landing page, without logout error, token expiry error, etc. If I minimize the app, then reopen, it almost always gets the correct keychain info and the user is logged in again.
This creates a confusing experience when encountered. It also means the user can't maintain this true 100% logged in state, with occasionally being randomly logged out. I've been unable to predict it or debug it and changing keychain libraries, as shown below, hasn't fixed it for me. It happens for me, and several TestFlight users, and in our production app currently.
Any suggestions how to maintain keychain integrity and loading 100% of time? We're about ready to implement an NSUserDefaults backup storage on the token to use in these cases, something I really don't want to do to store an auth token.
Storing:
// load keychain
KeychainItemWrapper *keychainItem = [KeychainItemWrapper keyChainWrapperForKeyID:kcIdentifier];
NSString *firstLaunch = [keychainItem objectForKey: (__bridge id)(kSecAttrAccount)];
if (firstLaunch == nil){
// initialize if needed
[keychainItem setObject:email forKey: (__bridge id)(kSecAttrAccount)];
[keychainItem setObject:kcIdentifier forKey: (__bridge id)kSecAttrService];
[keychainItem setObject:(id)kSecAttrAccessibleAfterFirstUnlock forKey:(id)kSecAttrAccessible];
}
// serialize "auth" NSDictionary into NSData and store
NSString *error;
NSData *dictionaryData = [NSPropertyListSerialization dataFromPropertyList:auth format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
[keychainItem setObject:dictionaryData forKey:(id)kSecValueData];
Loading:
// after similar KeychainItemWrapper initialization as above
NSData *dictionaryData = [keychainItem objectForKey:(id)kSecValueData];
NSString *error;
NSDictionary *auth = [NSPropertyListSerialization propertyListFromData:dictionaryData mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&error];
NSString *token = auth[#"access_token"];
I have also tried using the SSKeychain library CocoaPod that is widely available, and a wrapper around the keychain logic. It is a cleaner access but fails with the same issue. Here I'm just storing NSString values since there was no direct way to store NSData in the lib.
// store in keychain
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock];
[SSKeychain setPassword:auth[#"access_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN];
[SSKeychain setPassword:auth[#"expires_at"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT];
[SSKeychain setPassword:auth[#"refresh_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN];
// load from keychain
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock];
NSString *token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN];
NSString *expires_at = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT];
NSString *refresh_token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN];
Keychain does have issues at the moment, and for quite a while really. It sounds like you're getting off lightly as usually when it breaks a force-quit of the app is required to bring it back to life.
One thing that helps is to access the keychain just once on the first request and then cache the result in memory, if it's already in memory then just return it from there.
If you can observe a specific error when this happens then trap it and retry or, as is the current case for some unfortunate apps, kill the app. Killing the app is actually the current guidance from Apple if you raise a tech ticket to discuss the issue with them.
The only other real solution is to encrypt the data and store it in a file, but then you have issues with encryption keys so this is little better than obfuscation against a keen attacker.

How to remember username for next time on iPhone app?

I am working on an iPhone/iOS app. It has a login page with two text fields "email" & "Password".Now i want to save email.
i.e When I logged out it should remember the email address so it doesn't have to be input again.
Please tell me how can I save email.
If you don't consider email sensitive. Use NSUserDefaults...
Saving
[[NSUserDefaults standardUserDefaults]setObject:#"example#email.com" forKey:#"email"];
[[NSUserDefaults standardUserDefaults]synchronize];
Retrieving
// getting an NSString
NSString *emailString = [[NSUserDefaults standardUserDefaults] stringForKey:#"email"];\
IMPROVE ANSWER
If you consider email sensitive. Use keychain instead.
To store
KeychainItemWrapper *keychain =
[[KeychainItemWrapper alloc] initWithIdentifier:#"MyAppLoginData" accessGroup:nil];
[keychain setObject:loginStr forKey:(id)kSecAttrAccount];
[keychain setObject:pwdStr forKey:(id)kSecValueData];
To query
NSString *login = [keychain objectForKey:(id)kSecAttrAccount];
NSString *pwd = [keychain objectForKey:(id)kSecValueData];
To Delete:
[keychain resetKeychainItem];
To do this you will first need to add KeychainItemWrapper in you project.
Another important aspects of using keychain to store data is
The data is persistent even after app uninstall-install
Data can be shared across apps too. Read more here
In this case email is a part of user credentials, needed to login. So i would say it is sensitive information. Please do not ever use NSUserDefaults for storing sensitive data, that belongs to user. These defaults are stored as plist in binary format, they are not encrypted. Use Keychain Services API
provided by iOS instead.

Resources