iOS: Storing Non-User password - ios

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?

Related

How to avoid hardcoding keys for encryption (Objective C)?

In my Objective C code, I have a consumer key and secret hardcoded in my code to be used in SHA-1 encryption. What I would like to know is whether I could avoid hardcoding to improve security. I have found the following so far,
Finding 1
https://www.owasp.org/index.php/Technical_Risks_of_Reverse_Engineering_and_Unauthorized_Code_Modification#Cryptographic_Key_Replacement
Steps explained are as follows,
Damage static keys that are declared in source code. Such keys should be damaged while on disk to prevent an adversary from analyzing and intercepting the original key;
Next, the application should repair the key just before the code requiring the key uses it;
Immediately before use of the key, the application should perform a checksum of the key’s value to verify that the non-damaged key matches the value that the code declares at build time; and
Finally, the application should immediately re-damage the key in memory after the application has finished using it for that particular call.
Finding 2
https://github.com/UrbanApps/UAObfuscatedString
Can somebody help me please?
Sample code:
+ (NSString *) getOauthHeaderForRequestString:(NSString *)requestString {
NSString *oauthConsumerKey = #"<consumer key which I want avoid hardcoding>";
NSString *oauthConsumerSecret = #"<consumer secret which I want to avoid hardcoding>";
NSString *oauthSignatureMethod = #"HMAC-SHA1";
NSString *oauthVersion = #"1.0";
NSString *oauthNonce = [self generateNonce];
NSString *oauthtimestamp = [NSString stringWithFormat:#"%d", (int)[[NSDate date] timeIntervalSince1970]];
NSArray * params = [NSArray arrayWithObjects:
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_consumer_key", oauthConsumerKey],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_nonce", oauthNonce],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_signature_method", oauthSignatureMethod],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_timestamp", oauthtimestamp],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_version", oauthVersion],
[NSString stringWithFormat:#"%#%%3D%#", #"request", [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]],
nil];
params = [params sortedArrayUsingSelector:#selector(compare:)];
NSString *parameters = [params componentsJoinedByString:#"%26"];
NSString *postURL = #"<my post url>";
NSArray * baseComponents = [NSArray arrayWithObjects:
#"POST",
[self encodeString:postURL],
parameters,
nil];
NSString * baseString = [baseComponents componentsJoinedByString:#"&"];
NSArray *signingKeyComponents = [NSArray arrayWithObjects:oauthConsumerSecret, #"", nil];
NSString *signingKey = [signingKeyComponents componentsJoinedByString:#"&"];
NSData *signingKeyData = [signingKey dataUsingEncoding:NSUTF8StringEncoding];
NSData *baseData = [baseString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[20] = {0};
CCHmac(kCCHmacAlgSHA1, signingKeyData.bytes, signingKeyData.length, baseData.bytes, baseData.length, digest);
NSData *signatureData = [NSData dataWithBytes:digest length:20];
NSString *oauthSignature = [self base64forData:signatureData];
// final request build
NSString *oauthHeader = #"OAuth ";
oauthHeader = [oauthHeader stringByAppendingFormat:#"oauth_consumer_key=\"%#\"",oauthConsumerKey];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_nonce=\"%#\"",oauthNonce];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_signature=\"%#\"",[self encodeString:oauthSignature]];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_signature_method=\"%#\"",oauthSignatureMethod];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_timestamp=\"%#\"",oauthtimestamp];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_version=\"1.0\""];
return oauthHeader;
}
I've written about the challenges of solving this problem before, but I wanted to demonstrate a little bit using your UAObfuscatedString idea, since I think this is the kind of solution most people are looking for, but is worse than nothing. It's important to note: I'm not particularly good at this. I'm not a seasoned reverse engineer and commercial systems are way beyond my skillset. I'm just a guy with Hopper and literally five minutes of reverse engineering work (I ran a timer; 5:35s, including upgrading Hopper because I hadn't run it in a few months).
So, I wrote an iOS program with UAObfuscatedString. I used Swift because Swift is generally a little harder to reverse engineer than ObjC. ObjC is a reverse engineer's dream.
let identifier = "c".o.m.dot.u.r.b.a.n.a.p.p.s.dot.e.x.a.m.p.l.e
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print(identifier)
return true
}
I then archived it, so it's optimized code, etc. etc. just like you'd send to the App Store. I then loaded it up in to Hopper and looked at the app delegate's init. That's where constants are initialized, based on the assumption that most people stick this stuff in their app delegate. Obviously if I see a class named KeyStorage or SecretStuffHelper, I'd look there first....
void * -[_TtC13ObfuscateTest11AppDelegate init](void * self, void * _cmd) {
*(r31 + 0xffffffffffffffe0) = r20;
*(0xfffffffffffffff0 + r31) = r19;
*(r31 + 0xfffffffffffffff0) = r29;
*(r31 + 0x0) = r30;
r0 = sub_100005e14();
return r0;
}
Hmm, it calls this anonymous function sub_100005e14(). Let's see what that does.
...
0000000100005e38 adr x0, #0x100006859 ; "c"
...
0000000100005e48 bl imp___stubs___T0SS18UAObfuscatedStringE1oSSfg
...
0000000100005e50 bl imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100005e74 bl imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100005e98 bl imp___stubs___T0SS18UAObfuscatedStringE1uSSfg
...
0000000100005ebc bl imp___stubs___T0SS18UAObfuscatedStringE1rSSfg
...
0000000100005ee0 bl imp___stubs___T0SS18UAObfuscatedStringE1bSSfg
...
0000000100005f04 bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f28 bl imp___stubs___T0SS18UAObfuscatedStringE1nSSfg
...
0000000100005f4c bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f70 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005f94 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005fb8 bl imp___stubs___T0SS18UAObfuscatedStringE1sSSfg
...
0000000100005fdc bl imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100006000 bl imp___stubs___T0SS18UAObfuscatedStringE1eSSfg
...
0000000100006024 bl imp___stubs___T0SS18UAObfuscatedStringE1xSSfg
...
0000000100006048 bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
000000010000606c bl imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100006090 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
00000001000060b4 bl imp___stubs___T0SS18UAObfuscatedStringE1lSSfg
...
00000001000060d8 bl imp___stubs___T0SS18UAObfuscatedStringE1eSSfg
I'm not sure why the Swift demangler isn't working here, but anyway, we can easily see the pattern:
_T0SS18UAObfuscatedStringE1oSSfg => o
_T0SS18UAObfuscatedStringE1mSSfg => m
_T0SS18UAObfuscatedStringE3dotSSfg => dot => .
_T0SS18UAObfuscatedStringE1uSSfg => u
...
Realizing there are these USObfuscatedString methods, I search for that and find everywhere in the app that uses obfuscated strings. If I was willing to up my game a little and spend a day or so playing with it, I could probably write a tool to automatically extract every UAObfuscatedString just using otool and the binary.
And this is the deep lesson. You've just labeled all the strings you want to hide. Once I realize that UAObfuscatedString is a thing, you just made it easier for me to find your sensitive information. It is literally worse than nothing. Your only hope here is that the attacker doesn't know this exists. That's the problem with obfuscation, and what separates obfuscation from security.
I want also to emphasize that I spent 5 minutes and 35 seconds attacking this program. Yes, I knew basically what kind of thing I was looking for, but I also have no skills at this. If UAObfuscatedString were to become popular, I assure you that the auto-detect/de-obfuscate tool would become part of every script-kiddie's toolbox ("script-kiddie" is what security folks call attackers who do not know what they're doing, and just use automated tools that others have written).
The lesson here is that if you want to obfuscate, you're better off making up some random approach yourself. It won't be effective, but it probably won't be actively harmful to your goal in the way that most FOSS solutions are. "Free and open source" can be very good for security, but are the worst possible thing for obscurity.
If hiding information is really important to your business plan and you can't change your business plan, then you should expect to spend a lot of money on this problem and hire a team of people dedicated to constantly evolving your obfuscation system to keep ahead of attackers who will adapt to whatever you build.
So I recommend use yours second finding
https://github.com/UrbanApps/UAObfuscatedString
and add the regenerated strings to the keychain at the first application launch
so all methods could use values from keychain later in you code.
also I recommend build a singleton that will provide access to such values too keep all in one for time you want to change or update this solution
In general I wrote may api keys just inline in code, sometime declare them split it into two parts for safety. I am using a brain factor;)
let's say you API key xxx-xxxx-xxxx
I code the string xxx-xxxx-xFFF which as you see has same length as right key, somewhere in other method I cut las FFF and append right xxx postfix.
If you have a paranoia you could do it in different classes that defined in same file for convenience but stays alphabetically different places like AStoredKeys TheRightPostfixes that somehow hides your approach from disassemblers.
Honestly there is not much you can do. Literals are probably the best choice, but consider that you really don't know who will have a device and what they are doing with it. It's safe to assume that any talented engineer will be able to get to the keys and code on the device. Even if you protect your keys, there are apps, like screen scrapers and other things than can really get information. Obfuscation is not a good long term practice and good engineers can figure their way around this... it just slows them down. You do have control over your server, so focus on keeping that solid.
In general instead of thinking of securing your keys, think more about limiting information and access.
In regards to data, minimize private data to be received. For example, credit card numbers are never displayed and only the last 4 digits are stored. Or in the case of a banking app, only account balances are displayed, and they also offer two factor authentication (with an image for example). If a device is compromised, while it would suck to have a person's balance known, it's not the end of the world.
This also tends to be good corporate practice as it keeps you safe from any allegations. A person can't allege that information was compromised if you don't have it in the first place.
With access, limit what an app is capable of doing. Firewall it in a sense. Or provide other authentication steps, like SMS verification, two factor authentication. You can also let the server do the secure tasks for you. In the case of banking again, instead of allowing unlimited transfers, limit the number of transfers or the amount. Limit the accounts to which it can be transferred.
You could keep the password separately, in a file on an encrypted disc, or encrypted USB stick. Your code would just retrieve the appropriate file from secure storage. All an attacker would see in your code is the name of the password file.
If that is not practical, then you could XOR encrypt the password in your code. Your application will contain text strings like: "Please enter your password." That doesn't look like a key, but you could use that string as the XOR key to encrypt/decrypt the password. This is more vulnerable as an attacker would see the XOR key you are using in your code and be able to decrypt for herself.
Whatever method you use, do remember to overwrite the variable that holds the actual password before it goes out of scope.

Decrypting with AES256CBC Library doesn't return same value?

I'm trying to implement aes256 security to both Android, iOS and Web. In iOS part I'm using this library. But when I try to decrypt text with same password on this website or any other website or with googles aes.js file in html project. They don't give same result.
What am I missing? Thank you.
let str = "emre"
let password = "2ABdhQTy1GAWiwfvsKfJyeZVfrHeloQI"
let encrypted = AES256CBC.encryptString(str, password: password)
print(encrypted!)
let decrypted = AES256CBC.decryptString(encrypted!, password: "2ABdhQTy1GAWiwfvsKfJyeZVfrHeloQI")
print(decrypted!)
The AES256CBC.encryptString(..) methode you use, generates an IV and prepend the encrypted data with it. The AES256CBC.decryptString(..) methode then
obtains the IV from the encrypted data before decrypting the message.
Take a look in the encryptString methody you are using. See the IV it's creating? The IV is a random bit of data given as input to AES encryp/decrypt when running in CBC mode. The IV is often pre-prended to the encrypted data (as this library did here), but this is not standardized across different libraries.
If you wan't to use this library together with other implementations, you need to handle this part yourself.
Also, the online web page you link, don't seem to support CBC mode, so try use another one, like this.

Data encryption with AES

I'm building an app that will communicate with a server (php), and this communication (probably will be with json) i want to encrypt. After a lot of searching and reading i found the AESCrypt-Objc project.
While testing the encryption (i'm using a web tool AES Encryption test) i found that in the encryption result i'm missing 16 byte of data.
Here's the example i'm using
In the AES project:
String to be encrypted: "The quick brown fox jumped over the lazy dog".
Password: "12345678901234561234567890123456"
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9>
My Code:
self.strnToBeEnc = #"The quick brown fox jumped over the lazy dog";
self.appKey = #"12345678901234561234567890123456";
NSData *data2 = [self.strnToBeEnc dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#", data2);
NSData *s2 = [data2 AES256EncryptedDataUsingKey:self.appKey error:nil];
NSLog(#"%#", s2);
WEB Tool:
Same string and password
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9 ca2ed34a 48f85af2 909654d5 b0de0fb7>
As you can see i'm missing some bytes...:)
I've tried adding to the buffer in the algorithm, but with no success.
Any advice?
Thanks
(if the question is not Detailed enough please let me know)
I know you were trying to avoid this but I think you might need to spend some time in the source code of AESCrypt-Objc as I suspect it is somehow not encrypting the last block.
Step into the code and see if you actually get to the CCCryptorFinal call, and note its results. This can be found in the AESCrypt-ObjC/NSData+CommonCrypto.m _runCryptor:result: . Another thing to look into is the default padding type they are using which appears to be kCCOptionPKCS7Padding this will also have an effect on your ending bytes.
Do your testing first with non-arbitrary length bytes that are multiples of the AES block size, then once you have validated that move on to the variable length ones you have here.

iOS AES encryption wrong result

Here is how I encrypt the string:
+ (NSString *)encrypt:(NSString *)message password:(NSString *)password {
NSData *encryptedData = [[message dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptedDataUsingKey:[password dataUsingEncoding:NSUTF8StringEncoding] error:nil];
NSString *base64EncodedString = [NSString base64StringFromData:encryptedData length:[encryptedData length]];
return base64EncodedString;
}
The plain text is:
{"roomID":"{\"array\":[\"949156\",\"949157\"]}","duration":15,"link":"","type":"text","thumbnailBlobID":"","posy":103.6809424405021,"text":"Aa","className":"Message","originalBlobID":"","datetime":"20140319214528457","selfDestructive":0,"userID":"949157","posx":1.347154229880634,"status":"normal","entityID":"20140319214528457and949157and{\"array\":[\"949156\",\"949157\"]}"}
This is what I get
gXqxfDhImRD7S20lUdYuCPAlXfqRnG6xk4w4K5Op/WnYMh6VgJUUqMifK2vHkUpAbnZ+wKdSWjfzU1PuOwvJ4dJ9EiHwjeyyorezFNG6eylYcOvMWNeU6+5Z9XxfcFngqhmxM6k1lf7bkttTu0FnEHad/czFgiMVTy60DJpFMLSODkKEVezqQB9s/f3Qy/B6+sF5Hs5E0FDn7kU6Jtm6mLkFjGzDCXTdFXNjdussbkTL8C1gcOnn4hrNkqQKb82MgqqYf8sVgs4FVIjsmoJd0ALY8y/5QbBkgc6ZyB4aOQPPx/u4HS3F7HXHkIkkAjZS/hiHQBRyfwCvi2uwFedno5twYogNW56pSMQqBeJBxBAhPMpXzb51853GLP4bCotGtOyEfU96x5kWHDOR5QA2WhYZkB3AALDJ2kfqzWR8iOKHo3zE6DCQ7aH0RwEFlNPi8vsNwvUqtQ7nUODA5lUMYah6W2rfDh/em8BD8dGF5J6IUTIlSerx8wWPA9bn/SxO
From website http://aesencryption.net (256 bit)
(Which i assume to be the correct answer
5MdV0TelF++/8Cy9bnkeah0nQ5JbC04CEdCcHfdlavQtZaxg3ZSXklp9yXbeP05hcIeQDgFcMr9NlD6aKhjBL3Xh70ksYqc6Xv5BZvCbXrvO4ufAf4gjmDRQr9DYSbjFct6N82fFGDtrcuFm36Zv+QAQtR/scT86A++Vn/EBlPwFb7ZmxlMPkJWjQ98ObreXHeKkZ8f2npMKfJ0i36nIZ8CZeL0EYeg/njo9ykPTfm9wfKieqlIICn1qNZAXE//P9hTleW/GNs5+ET2gxNSCmdO+ByUB9Q3sZ/+57qXbsfCxHr8dsuBrsbRI+cVIXyquQL1IC/zuz3G3fcyoiLrD/PnFtV5z5XR0hpUiU8JjovjYwyXaBfyTBnO71zxmdoZdsyPwA1LQO0pedn8UsICT2KbfBKwuumW2CJPexbnMmVzpIJ/VPISikdg18V3rdJqiPMIb4Zq2PGKO0Wtq1dCTMusTv/ZnqxgVQFQlUivgBqtnOLCDaMAGL636NXda95V2
There is no single standard way to apply AES, or standard data format for the output. AES requires a number of helpers when used on data that is not exactly 16-bytes long, and they can be configured in different ways. I have no idea how the aesencryption.net tool is applying these helpers; it doesn't say. If AES256EncryptedDataUsingKey: is the particular piece of code I assume it, it applies them very poorly (it's very similar to the code I discuss in Properly Encrypting With AES With CommonCrypto). I would not be surprised if aesencryption.net does something different.
If you have a piece of plaintext and a key, and you pass it to an encryptor twice and get the same answer back, then your encryptor is broken. A correct AES encryptor (for almost any common use of AES) should always return different results for the same plaintext+key (otherwise an attacker can determine that two plaintexts are equal, which breaks the security proof of AES). In the most common case, this is achieved by having a unique initialization vector (IV). For password-based AES, you also include a random salt. So even if these were good implementations of AES, you wouldn't expect your results to match.
Is it possible that the escape characters (the back slashes) are being interpreted differently in code versus via the web? The bottom line here is I would (in code) decode what you just encoded and you should come out with the same as what you put in. This is probably the test you want to conduct. Hope this helps. Also see comment below from #RobNapier

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