PRNG in iOS KeyChain - ios

My boss is asking me, which PRGN (Pseudo Random Number Generator) is using our iOS App for encrypting and decrypting data.
We are using the native KeyChain services for storing the data and I don't know what to answer since we are using the KeyChainItemWrapper for accessing the single items i.e. password, ports, etc. in our App and there is not too much reference about this.
I already debugged the app to see if I find something but I couldn't find something yet.
Any help would be appreciated,
thanks

If you need random bytes as opposed to a a random number:
randomBytes: returns count random bytes in *bytes, allocated by the caller.
Returns 0 on success or -1 if something went wrong, check errno to find out the real error.
#import <Security/Security.h>
+ (NSData *)randomBytes:(size_t)count
{
NSMutableData *data = [NSMutableData dataWithLength:count];
SecRandomCopyBytes( kSecRandomDefault,
data.length,
data.mutableBytes);
return data;
}
Be sure to add the Security framework.

Related

OBJ-C wipe NSData content before nullifying it

For security reasons we need Always to wipe sensitive data from memory.
Usually it is not something that i see done in IOS but for apps and need extended security it is very important.
The Data that Usually needs to be wiped if NSData and NSString objects (pointing to nil does not wipe the data and it is a security breach)
I've managed to wipe my NSStrings with the code below (When password is NSString):
unsigned char *charPass;
if (password != nil) {
charPass = (unsigned char*) CFStringGetCStringPtr((CFStringRef) password, CFStringGetSystemEncoding());
memset(charPass, 0, [password length]);
password = nil;
}
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
When password is NSData It suppose to be even more strait forward and the code bellow suppose to work:
memset([password bytes], 0, [password length]);
But this gives me a compilation error:
No matching function for call to 'memset'
I can't find a workaround to point to the password address and wipe the bytes over there like I did with the string (bytes method should let me do just that from what I understand but it doesn't compile for some reason that I cant figure out)
Any one has an idea for this?
10x
Your string deallocator is fragile. You write:
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
This is documented behaviour as CFString (and hence NSString) does not guarantee you direct access to its internal buffer. You don't say what how you handle this situation, but if you don't erase the memory you presumably have a security problem.
In the case you do get a valid pointer back you are using the wrong byte count. The call [password length] returns:
The number of UTF-16 code units in the receiver.
which is not the same as the number of bytes. However CFStringGetCStringPtr returns:
A pointer to a C string or NULL if the internal storage of theString does not allow this to be returned efficiently.
If you have a C string you can use C library function strlen() to find its length.
To address the case when CFStringGetCStringPtr returns NULL you could create the string yourself as a CFString and supply a custom CFAllocater. You shouldn't need to write a complete allocator yourself, instead you could build one based on the system one. You can get the default allocators CFAllocatorContext which will return you the function pointers the system uses. You can then create a new CFAllocator based of a CFAllocatorContext which is a copy of the default one except you've changed the deallocate and reallocate pointers to functions which you have implemented in terms of the default allocate, reallocate and deallocate but also call memset appropriately to clear out memory.
Once you've done that doing your security wipe comes down to making sure these custom created CFString objects, aka NSString objects, are deallocated before your app quits.
You can find out about CFAllocator, CFAllocatorContext etc. in Memory Management Programming Guide for Core Foundation.
Which brings us to your actual question, how to zero an NSData. Here you are in luck an NSData object is a CFData object, and CFData's CFDataGetBytePtr, unlike CFStringGetCStringPtr, is guaranteed to return a pointer to the actual bytes, straight from the documentation:
This function is guaranteed to return a pointer to a CFData object's internal bytes. CFData, unlike CFString, does not hide its internal storage.
So code following your pattern for CFString will work here. Note that using NSData's bytes is not guaranteed in the documentation to call CFDataGetBytePtr, it could for example call CFDataGetBytes and return a copy of the bytes, use the CFData functions.
HTH
While I cannot speak for the actual safety of doing this, your problem is that NSData's bytes method returns a const void *
https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc
You can cast it to a void * if you want by
memset((void *)[password bytes], 0, [password length]);
If you use a NSMutableData, you won't have to do this.

sqlite3_prepare_v2 exc_bad_access in iOS 10

I have use sqlite in my iOS project for database. In iOS 9 all things are working perfectly. Now i have update new Xcode. But app is crashes many times at 'sqlite3_prepare_v2'.
Also, i am not closing database overtime. And open it only once.
I have added DB open in below code b'acs in debug i got DB close. But still got crash.
crash
Can anyone help me ?
Thanks in advance
I think issue is in line 2592.
Do not treat key as string when passing it to sqlite3_key(...)
Not sure how you generate key but if first byte is set '\0' then strlen return 0
(which may happen pretty often if you use some autogenerated helper based on NSData random bytes)
sqlite3_key definition:
SQLITE_API int SQLITE_STDCALL sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
It expects nKey bytes where "\0" is allowed too
Instead try:
NSData *passBytes = [g_sqlite_key dataUsingEncoding:NSUTF8StringEncoding];
int status = sqlite3_key(contactDB, passBytes.bytes, passBytes.length);
if (status != SQLITE_OK) {
// handle error and return
}
// continue...

iOS: Storing Non-User password

I need to store third-party username/password in my iOS application, what is the best and most secure way to do this? When my app first runs, it will need to talk to Google's Picasa to download private pictures to use for the app. To talk to Picasa, I have to provide my username/password and storing in the code is not secure at all.
I've search the web, I see Keychain came up a lot, but how exactly do I pre-load my password into keychain?
Is there a configuration file in xCode somewhere to store passwords needed for web-services?
Thanks
Think that you need to store the password in encrypted form. Pick some encrypting algorithm, generate the encrypted details. And in code have some method to decrypt it when needed.
You just don't want someone who would read your code as plain text to see the password.
Think that something as simple as splitting the password into separate strings and later joining them could be enough.
Here for example You have encrypted in code "My1Password":
#define R1 #"My"
#define R2 #"Password"
+ (NSString *)generatePass{ return [NSString stringWithFormat:#"%#%#%#, R1, #(1), R2]; }
This is a response to krzysztof above:
I'm in a catch-22 situation here as I can't seem to grasp the concept of feeding the password as parameter to another function. Aside from avoid others reading the source code in plain text, can't hackers obtain the binary file and reverse engineer to read the password in the source code (R1 & R2 in this case)???
Back to encryption, lets take the following line of code which Encrypt/Decrypt data:
NSData *encryptedImage = [RNEncryptor encryptData:imageData withSettings:kRNCryptorAES256Settings password:#"A_SECRET_PASSWORD" error:nil];
NSData *decryptedData = [RNDecryptor decryptData:data withSettings:kRNCryptorAES256Settings password:#"A_SECRET_PASSWORD" error:nil];
This is where I'm stuck... where do I store A_SECRET_PASSWORD?

What is the correct way to clear sensitive data from memory in iOS?

I want to clear sensitive data from memory in my iOS app.
In Windows I used to use SecureZeroMemory. Now, in iOS, I use plain old memset, but I'm a little worried the compiler might optimize it:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/771-BSI.html
code snippet:
NSData *someSensitiveData;
memset((void *)someSensitiveData.bytes, 0, someSensitiveData.length);
Paraphrasing 771-BSI (link see OP):
A way to avoid having the memset call optimized out by the compiler is to access the buffer again after the memset call in a way that would force the compiler not to optimize the location. This can be achieved by
*(volatile char*)buffer = *(volatile char*)buffer;
after the memset() call.
In fact, you could write a secure_memset() function
void* secure_memset(void *v, int c, size_t n) {
volatile char *p = v;
while (n--) *p++ = c;
return v;
}
(Code taken from 771-BSI. Thanks to Daniel Trebbien for pointing out for a possible defect of the previous code proposal.)
Why does volatile prevent optimization? See https://stackoverflow.com/a/3604588/220060
UPDATE Please also read Sensitive Data In Memory because if you have an adversary on your iOS system, your are already more or less screwed even before he tries to read that memory. In a summary SecureZeroMemory() or secure_memset() do not really help.
The problem is NSData is immutable and you do not have control over what happens. If the buffer is controlled by you, you could use dataWithBytesNoCopy:length: and NSData will act as a wrapper. When finished you could memset your buffer.

PGP decryption on iOS

I'm trying to implement decryption of a PGP file on an iPad. I set up some test .txt files which I then encrypted via PGP desktop.
I've imported the private key of the certificate used to encrypt the document, using SecPKCS12Import, then SecIdentityCopyPrivateKey() from the resulting SecIdentityRef.
If I test encrypting and decrypting a simple string in Objective C, using the public and private key of the cert, that works perfectly.
Now that I'm trialling the actual PGP decryption, I'm a bit stumped... Reading the text from the .pgp file, I get:
-----BEGIN PGP MESSAGE-----
Version: 10.1.1.10
qANQR1DBwEwDraQm2Kxa5GkBB/4yLebeLk10C2DVvHpQL20E0DThhgQlTasXo+YJ
pLp5Ig2hHu4Xx0m74D3vfyWpA2XQA02TMAHO9lhNfkE234c/ds05D1UyQkJEoqW+
joEcbRT5rlGN3qrMf1FXv8/01EHH0dgeD6mAkkDeDEorIirYHCF6+QVkedaphZLs
c63GmcikzkWZT/vv20ICL3Ys0DaC3P9zu0T1GtjkmQ062kaTab/VBJnQrsY/y1JU
ypmbW9bbFeZMcAqXHMqpjw49K5UluIJaDbRNAjIvHTFLNuOYWVJM6FcMs5p6xqvZ
ltizeKAjr1B1h4DvbQaqdO6/OAb+dGr7fJoIHEszDsJbW1cc0lUBitrxKHrPGovF
1uEW+3glA3SopveWB4GkKzcYlbqT5y1p/gQNwY8yuZr/6iF1hyF9mx/hU/+xjOMB
og3sGX4npcQegsAMw2y+zz9kJ9a6jlteNufi
=d2Fq
-----END PGP MESSAGE-----
I know that I need to get the random one-time key, that PGP used to encrypt the file, from the data in the file. I know that to do that, I need to use SecKeyDecrypt with the private key, to obtain the one-time AES key. Once I have that key, I can then decrypt the rest of the data.
The part I'm having problems with is which part of the data to feed into SecKeyDecrypt. How is the PGP file setup - is the first 128 chars the AES key? Unless my understanding is wrong, I need to get that out separately from the data.
If I run, say, the first 128 chars as a void through the SecKeyDecrypt function: (after stripping the BEGIN PGP MESSAGE lines)
size_t dataLength = [theKey length];
size_t outputLength = MAX(128, SecKeyGetBlockSize(privateKeyRef));
void *outputBuf = malloc(outputLength);
OSStatus err;
err = SecKeyDecrypt(privateKeyRef, kSecPaddingNone,//PKCS1,
(uint8_t *)theKey, dataLength,
outputBuf, &outputLength);
if (err) {
NSLog(#"something went wrong...err = %ld", err);
}
I get this:
MRªh6∞bJ˘e£t*˝ã=ŒA¢Òt‘ŸY±éÿAÃîâG
Îfi≠$b≈tâç`yxk=uHªqu-,–dïn^™È\›5±tb.‡€Kñ⁄≤sΩw–ïʃkafS˘À*Æô竡rAyv)fi]wOrµKz^ªq“à∑öΓı*r<+l˝Äo∑›g≠¶/÷eÔ&€PÒRåêM¶Ñ|Q$á6În^võ¬∏·h(ƒß•R≤(flò(*•Aa
I don't know what encoding this is, but trying to get it from the outputBuf into a string never works 100%. It seems to get modified no matter what encoding I pass it. If I pass it to NSData first, I can get the original string back.
NSData *keyData = [NSData dataWithBytesNoCopy:outputBuf length:outputLength];
NSString *keyFromData = [[NSString alloc] initWithBytes:[keyData bytes] length:[keyData length] encoding:NSASCIIStringEncoding];
I then try to pass that key to an AES256DecryptWithKey class, providing it with the remaining data from the PGP file, after the first 128 chars.
NSData *cipherText = [[NSData alloc]initWithData:[[bodyPart objectAtIndex:1] dataUsingEncoding:NSUTF8StringEncoding]];
NSData *plain = [[NSData alloc] initWithData:[cipherText AES256DecryptWithKey:keyFromData]];
NSLog(#"after decrypting = %#", [[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding]);
Problem:
The resulting data 'plain' prints as <> i.e. empty. My problem is I don't even think I know how to grab the key from the PGP file.
Can anyone explain to me the PGP file setup? What part is the 'key' if it is in fact separate from the data at all? Is it always the same length/ same position? If it's NOT separate then I don't know how I'd be able to grab it at all. I think the rest would work fine. I'm not getting any errors or crashes, it's just NOT the right key and/or data I'm passing for AES decryption, I suspect probably a combination of string encoding error and not grabbing the right amount for the AES key/ right combination.
Note -
I created 3 different text files and ran them through the PGP process. Inspecting them, they all started with the same 24 characters (qANQR1DBwEwDraQm2Kxa5GkB). Even if I pass these 24 through the decryption, it doesn't work, and I was under the impression that the AES key PGP used was different for every single document. Did I get that wrong?
Thanks for any step in the right direction!
Edited to add:
Just noticed partly my mistake - AES of 128 requires 16 bits, so either way I am taking the wrong amount by using 128 characters, stupid mistake, think I've been looking at this too long... Swapped it out and didn't work. Any decryption I do is resulting in the '⁄Ĉ¢ï¡0M¶È2Cˆ¿©gUú¨6iîΩ`&<%Jœv£¯nRb∆:(–%' type result, which to me implies I've done something wrong OR need to do something further with encoding.
Read RFC 4880. That file is an ASCII-Armored collection of PGP packets. There are 1 or more packets that contain the symmetric key needed to decrypt the actual message, each of the symmetric key packets is encrypted with the public key of a recipient. Only people who possess the right private key can decrypt the symmetric key packet and then use that symmetric key to decrypt the rest of the message.
The AES key is indeed different.
It is randomly selected, and the encrypted with the public key system (RSA, typically).
Pub key has costs and limitations that make it unattractive to use for bulk.
You might want to look at the NetPGP, which is C code under the
BSD license, which means you can incorporate it or modify it
without encumbering your app or upsetting Apple in any way.
(Of course, contributions of source code or money would be
appreciated by the project. I'm not affiliated with them.)
The OpenPGP standard is a lot of work to implement.
Even once an implementation works, there are countless
ways in which it can be insecure.

Resources