One of my projects requires encrypting data on the iPhone and decrypting it using .Net. This is easy to do with the Common Crypto library in the iPhone SDK and the AesCryptoServiceProvider class in .Net, but the encryption parameters have to be the same for it to work.
I couldn’t figure it out, but the geniuses at StackOverflow did, so I am posting my results here. The zip file includes a basic iPhone app and a .Net console project with helpful classes to do the encryption/decryption and base64 conversion. I didn’t write most of the code – thanks to Blue Beetle for the .Net code and Greg Haygood for the Objective C.
Thanks for posting this code!
This is great, thanks for the example, it works perfectly.
Hi, this is just what i was looking for… but i need decryption in PHP…:(
I’m thinking to buy this: http://www.phpaes.com on their site there’s a demo utility to encrypt or decrypt strings…but i cant get the same result as the iphone program you provided… would you please try, too? maybe im messing with mode and iv..thanks so much
hi, a quick question
i get encrypted data to export as NSString say “u+8tQsPIHhr1Ll5TKBdbdSZmLEX/cD/xYY34kLPIPFc=”
which is good, if I decrypt encrypted data it works but when I take this export string (above) and try to created NSDATA object
NSData* encData = [NSData dataWithBase64EncodedString:”u+8tQsPIHhr1Ll5TKBdbdSZmLEX/cD/xYY34kLPIPFc=”];
then i cannot get encoded string decoded.
Here is full sample:
NSString * _secret = @”My Encryption Key”;
NSString * _key = @”1234123412341234″;
StringEncryption *crypto = [[[StringEncryption alloc] init] autorelease];
NSData *_secretData = [_secret dataUsingEncoding:NSUTF8StringEncoding];
CCOptions padding = kCCOptionPKCS7Padding;
NSData *encryptedData = [crypto encrypt:_secretData key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding:&padding];
NSString* encDataToExport = [encryptedData base64EncodingWithLineLength:0];
// do reverse -> from encrypted data to unencrypted
NSData* encData = [NSData dataWithBase64EncodedString:encDataToExport]; // gives me 427 bytes somehow!!!!!!!!!
NSData* decryptedData = [crypto decrypt:encData key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding:&padding]; // returns nil
NSString* str = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
NSLog(@”str: %@”,str);
I think i am not converting encoded string correctly to base64 data.
What am I missing?
Thank you
Mark
thank you dude!
You got me out of my illiteracy…
@ mark:
had the same problem, there’s a bug in the base 64 file.
Excellent work dude.
Thanks a lot.
Thanks for the Code.
When I use this code on iPhone for hello/hello the encoded string is not QA+Ul+r6Zmr7yHipMcHSbQ==
Can you please verify there is ssome problem with the Base64
Thanks,
locoVJ
Because this was so helpful…
There seems to be a bug in the base64 file. The line with inbuf[3] outbuf[4] should be inbuf[4] outbuf[3].
And you need to use the base64 stuff if you are working off the .NET example.. So something like
NSData * encdata = [NSData dataWithBase64DecodedString:the_encrypted64strfromweb];
NSData* decData = [crypto decrypt:encdata ….
————–
Oh, and just use a 16 character key right off the bat….
Thanks
Many thanks to you and bb – this has saved me loads of time
Thanks for the code. It is very useful for me.
And I would also like to thanks bbb. Otherwise, I cannot still find a way to decrypt the base32 string.
Thank you so much for finding this! I was trying to figure this out over a year ago and eventually had to move on.
Just discovered this post while searching for iphone->.NET crypto interop. Did the base 64 bug get addressed?
Thanks!
you guys are chittah (jaguars) – kudos and many thanks!
by the way guys, I am looking for interoperability between .Net and iPhone for compression mechanism, currently I am trying gZip that available in both platforms, but luck is not my way,
strings which i compressed from both mechanism gives me different decompressed strings
many thanks
Jeet
I am not taking my words back… you guys are great, but I struck at ground 🙁 I was testing both versions in and out.
I am encrypting a string in objective-c and also encrypting the same string in C# using AES and am seeing some strange issues. The first part of the result matches up to a certain point but then it is different. Why?
I am using a source string of “this is going to be test and fingers are crossed” Using a key of “1234567891123456”
The result from Objective C is 5U6TAlyma3GbR5UYqyk7d7mdTY1Jy9obUTwlOaL0/wn72s7IVZQPi1zydeonLSqP
The result from C# is
5U6TAlyma3GbR5UYqyk7d7mdTY1Jy9obUTwlOaL0/wn72s7IVZQPi1zydeonLSqPwifBaSjG51fj6y4S
j7cS7w==
you notice that initial portion of strings are same but then it starting differs.
I’ve not added/modified anything except for those string and key.
Please assist… I am in do/die situation 🙁
thanks
Jeet
Thanks for the code, it gives the clear idea for encrypting data on the iPhone and decrypting it using .Net.
YOU ARE THE MAN !!!!
saved me !
thanks everyone for fixing the Base64 Problem !!!!
Thanks. very nice code. it helps very much…
Just for info, you have a error in the md5data function :
old : NSString* temp = [NSString stringWithFormat:
@”02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”,
New : NSString* temp = [NSString stringWithFormat:
@”%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”,
(miss % on the beginning of the string)
But the code helpes me some, thank
Hey Folks,
Thanks David for posting this, and everyone else for finding and fixing bugs. In case anyone else just downloaded the ZIP file, here are the line numbers to make the changes mentioned in the comments:
Reversed buffer sizes for inbuf and outbuf is in NSData+Base64.m at line 36
The missing % is in StringEncryption.m at line 266
Thanks for the corrections on this. Works good. I also need to have a way to use the same key and encryption technique from javascript. I’ve looked at a few AES javascript samples, but they don’t seem to come up with the same encrypted/decrypted values when I use the key I’ve used with this solution. Anyone have any good javascript that match this one?
Thank you all!! This helps very much!!!
This is great work but i have a question, It only works with keys that are %8 = 0 keys, for example if i have an encryption key _Key=123456789 i will get diffrent results in .net and iphone , if i use a key _Key%8= 0 works perfectly why is that? And how do i fix it if anybody can help i wil greatly appreciated.
Does the code have some bugs in it or am i doing something wrong?
I implemented the encryption codes. sent a message to the web service, when I recived the encrypted message from the web service the iphone is unable to decypt the message. it creates extra characters in the string. This does not happend for all messages.
Please help i really don’t want to create a compatible algorithm from scrach. i am new to encrypting algorithms. i am testing it on the Iphone Simulator and the web service is on a .net dedicated server.
@ jeet
I got the same problem. Did you fix it ? i have no idea what’s wrong and I really need to get an working encryption fast.
Thank you for this article! I was looking for something like this! I’m testing it now on the iPad vs a .NET webservice. I’ve changed the key to 256 bits. Seems to work like a charm!
I checked the problems from Radu and jeet and indeed there seems to be a bug in the code when the text to be encrypted is 16/32/48/etc characters? Seems the ObjC code forgets a part there…
@ Spare I found the error Spare It’s in the padding In the Obj C it uses PKCS7 and zero padding I just used PKCS7 and works just fine now. It took me a week to find it and it was right under my nose. I’ll change the encryption code to 256 bits to. Works great now. Thanks for the code David great job and thanks Spare for answering to my help .
It was the padding, indeed. I figured it out, too, haha. Now the code is completely interoperable between .NET and Objective C 🙂
One thing I’m asking, It’s not really a problem but it annoys me a bit, that every time a same string is entered the same base64 code is generated. I’m looking for a way for it to be completely different each time, even if you enter the same string as input. Is there a way to match this on both sides?
hey it does not work Spare and Radu. how did you set it to PKCS7. it seems to be PKCS7 already?
thanks
I commented the padding section out:
// We don’t want to toss padding on if we don’t need to
/*
if(encryptOrDecrypt == kCCEncrypt) {
….
NSLog(@”Invalid CCOperation parameter [%d] for cipher context.”, *pkcs7 );
}
*/
Hi, thank for your code, its very usefull for me, i found 2 small – but important – bugs.
1; NSData+Base64.m file, initWithBase64EncodedString method here should be: unsigned char inbuf[4], outbuf[3];
2; StringEncryption.m file, DecryptString method here should be:
NSData *data = [crypto decrypt:[NSData dataWithBase64EncodedString:base64StringToDecrypt] key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding: &padding];
After making the changes the iPhone encrypted password still does not match the .net result. Can someone please post the updated objective code or point to the changes please.
Thanks
Thanks for your great work and share.
Mike nailed it… the DecryptString method now works for me. I’m decoding Base64 encoded strings from a .NET web service. Thanks!
I thought I had it all working perfectly but then one one particular encoded string differed between Obj-C and .NET. (Halfway through the Base64 string as people have reported.) I had not added Spare’s change to comment out the padding. That fixed it.
The .net version seems not to be unicode-compatible. for example it can not convert the char ‘ä’ or ‘µ’ properly. Does anyone has a suggestion how to fix this?
Thanks!
Does anyone know how to convert unicode to base64 within the xcode code sample? any help would be appreciated!
Hi All, implemented this algorithm.
I am facing following problem.
1. iphone encrypting always with less number of characters length.
2. .Net encrypting algorithm giving more number of characters in encrypted string than iphone encrypted string. Because of which, .Net service is not able to decrypt iphone encrypted string.
Could you please point me where I am doing wrong here. Thanks in advance.
Hi. By any chance, do you also have a similar code for Java? May I also know what algorithm, mode and padding (e.g. AES/CBC/PKCS7Padding) your code uses? Thank you!
Please disregard my question. If I’m not mistaken it’s using AES/CBC/PKCS7Padding.
Hello, Great post appreciates such valuable information. I am about to use these algorithms within the asp.net web services and the app I am currently developing.
Does anyone know if you require to declare for CCATS for using these libraries or can we just waive the CCATS requirement since we are using IOS inbuilt crypto in this AES?
I am from Australia, and I hear lots of complications on using cryptography in your apps and having to declare information to ENC Encryption etc.
Any information would be highly appreciated! Thanks folks.
Hello – after reading all of the comments and attempting to encrypt/decrypt a string between a .NET app and iOS, I’m getting different results. And neither side can decrypt the encrypted value generated by the other.
I’ve tried updating my project based on all of the comments, but still no luck… If anyone would have the complete list of updates and/or a working copy of this project, I would greatly appreciate it.
Thank you!
Hi,
This is really very great post and very helpful.
I am in need of android version too. If possible please post the code I will be very thankful for you.
Waiting for you response 🙂
Hi,
This is really very great post and very helpful.
I am in need of android version too. If possible please post the code I will be very thankful for you.
Waiting for you response 🙂
guyz, anyone getting different strings on iphone and c# after encryption,please use key of length 16 char while encrypting.
it works….thanx
Hi Guys,
just to clarify things. the .net and iOS source do provide the same crypto-values in most cases. in some like “kochhofstrasse 7” they don’t. as “Spare” reported in a comment above, to fix this
– just comment the section below this comment out: “// We don’t want to toss padding on if we don’t need to”
-use a 16 char key, while encrypting (123456789012345)
-use UTF8 Encoding where its using ASCII (on server and client, to avoid umlaut-problems)
then you should be good to go! good luck!
take care
Tommy
Thanks Mike, after making those changes you mentioned, my code works. You rock!
I’m having problem with the code… does not encrypt the same on iOS as .Net.
Can someone help me, i have done the changes that Mikes says and steal doesn’t works.
Thx
Thanks u all guys, it was 3 days I was searching for a solution!
Mike’s solution didn’t solve my problem, but i tried;
NSData *data = [crypto decrypt:[[NSData alloc] initWithBase64EncodedString:base64StringToDecrypt] key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding: &padding];
There is a class which is overriding NSData. Also people can use (initWithBase64EncodedString) this way. Maybe there are people like me 🙂
Hi,
I just faced a Decrypt problem.
When i define a encrypted string for decrypting. Im getting “Problem with encipherment ccStatus == -4301” (which means “kCCBufferTooSmall”) error in StringEncryption file.
How can i solve it ? Any help ?
This is fantastic, thanks VERY much for sharing. Finding this brought an end to 3 very frustrating days!!
My comments to help fellow travellers: Make sure you implement the changes for the iOS version highlighted by Spare and Terry in SD above.
Also, took me a bit to figure out: to decrypt a string in the iOS version, get the NS data by doing:
NSData *_transferredData = [NSData dataWithBase64EncodedString:strTransferred]; //strTransferred is the string received from .NET
then:
NSData *decryptedTransferredData = [crypto decrypt:_transferredData key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding:&padding];
NSString *decryptedString = [[NSString alloc] initWithData:decryptedTransferredData encoding:NSUTF8StringEncoding];
Cheers!
Hi,
Thanks for posting this. I have a problem coming in the code. I am getting encrypted string from the server and want to decrypt it at iPhone end. Can you please tell me how to use the above code for that?
I am Implementing the AES128 bit encryption/Decryption in iOS application for sending/receiving data from .net server, I almost done but during unit testing I got some issue in encryption string, some encrypted string are not similar as on .net server, Can say 98 percent are correct but in 2 percent issue comes, when I match the both side encrypted string then found at iOS end generated string is little short and .net end it is long string. One more thing i found the iOS string is the substring of .net string. When i tried to decrypt the iOS generated encrypted string, it is not decrypted showing null but when I try to decrypt the .net server generated encrypted string (it was larger than the iOS) I am able to se the decrypted string.
Using the same KEY(16 character long at server and iOS end).
could you please suggest the solution or where I am wrong .
Thanks a lot to all.
Original string: “custId=10&mode=1” KEY= “PasswordPassword”
at iOS encrypted string: r51TbJpBLYDkcPC+Ei6Rmg==
at .net encrpted string: r51TbJpBLYDkcPC+Ei6RmtY2fuzv3RsHzsXt/RpFxAs=
padding for encryption = kCCOptionPKCS7Padding;
I had a similar situation occur. Most encryption/decryption worked from ios to .net.
But there’s a bug with the padding of cipher keys. I’m new cryptography algorithms, so I’ve aged a few years in the past 4-5 days,
The situation cipher key data is exactly the length of the key size. In my case 256 bits and it also was occurring with I was using 128 bit encryption key. The issue is with the following code:
NSLog(@”pkcs7: %d”, *pkcs7);
// We don’t want to toss padding on if we don’t need to
if(encryptOrDecrypt == kCCEncrypt) {
if(*pkcs7 != kCCOptionECBMode) {
if((plainTextBufferSize % kChosenCipherBlockSize) == 0) {
*pkcs7 = 0x0000;
} else {
*pkcs7 = kCCOptionPKCS7Padding;
}
}
} else if(encryptOrDecrypt != kCCDecrypt) {
NSLog(@”Invalid CCOperation parameter [%d] for cipher context.”, *pkcs7 );
}
The condition, ‘if((plainTextBufferSize % kChosenCipherBlockSize) == 0)’ turns off the pkcs7 padding under this circumstance, but only during the encryption process, not during the decryption process. So this causes decryption errors on both .Net and iOS. The .Net code always expects pkcs7 padding to be present, and so does the iOS code upon decryption. And thats why .Net would throw key padding errors. iOS would just return nothing or nil for the decrypted value.
On a side note, In order to use 256 bit keys to work, 1.) the iOS code should be adjusted to use the #define value kCCKeySizeAES256 for the #define value –>> kChosenCipherKeySize.
2. and on the .Net side, in function, ‘GetProvider(byte[] key)’, the result.KeySize needs to change to 256 and then in the function GetKey(byte[] suggestedKey, SymmetricAlgorithm p)’, the loop condition needs to
p.LegalKeySizes[0].MaxSize;
The last caveat is that the plaintext key value must be 32 bytes long. I wasn’t able to get it to work with variable length plaintext encryption value. But it works fine. I no longer get those random Padding invalid errors.
I forgot to mention, that I just commented out that conditional pkcs7 code so that it always uses the pkcs7 padding regardless of the length of the cipher key.
result.Padding = PaddingMode.None; it is not working when csS.FlushFinalBlock(); executed it gives an error.How to resolve it.?
Give me solution.
Hi,
I am trying to port out iPhone app to Android but am stuck where this encryption was used in the iPhone app.
Any info on how to do this in Java/Android ?
I know it’s an old post, but I really appreciate some pointers.
I had a similar situation occur. Most encryption/decryption worked from ios to .net. But there’s a bug with the padding of cipher keys. I’m new cryptography algorithms, so I’ve aged a few years in the past 4-5 days, The situation cipher key data is exactly the length of the key size. In my case 256 bits and it also was occurring with I was using 128 bit encryption key. The issue is with the following code:
NSLog(@”pkcs7: %d”, *pkcs7); // We don’t want to toss padding on if we don’t need to if(encryptOrDecrypt == kCCEncrypt) {
if(*pkcs7 != kCCOptionECBMode) {
if((plainTextBufferSize % kChosenCipherBlockSize) == 0)
{ *pkcs7 = 0×0000; }
else { *pkcs7 = kCCOptionPKCS7Padding; } } }
else if(encryptOrDecrypt != kCCDecrypt)
{ NSLog(@”Invalid CCOperation parameter [%d] for cipher context.”, *pkcs7 ); }
The condition, ‘if((plainTextBufferSize % kChosenCipherBlockSize) == 0)’ turns off the pkcs7 padding under this circumstance, but only during the encryption process, not during the decryption process. So this causes decryption errors on both .Net and iOS. The .Net code always expects pkcs7 padding to be present, and so does the iOS code upon decryption. And thats why .Net would throw key padding errors. iOS would just return nothing or nil for the decrypted value.
On a side note, In order to use 256 bit keys to work,
1.) the iOS code should be adjusted to use the #define value kCCKeySizeAES256 for the #define value –>> kChosenCipherKeySize.
2). and on the .Net side, in function, ‘GetProvider(byte[] key)’, the result.KeySize needs to change to 256 and then in the function GetKey(byte[] suggestedKey, SymmetricAlgorithm p)’, the loop condition needs to p.LegalKeySizes[0].MaxSize;
The last caveat is that the plaintext key value must be 32 bytes long. I wasn’t able to get it to work with variable length plaintext encryption value. But it works fine. I no longer get those random Padding invalid errors.
P.S. I commented out the conditional statement to always use the pkcs7 padding.
Excelent Post and great work!!!! thanks….
Great post. Question: Why is this code nedded,
result.GenerateIV();
result.IV = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
var realKey = GetKey(key, result);
result.Key = realKey;
Is it a bad thing to have a public and a private key? Just asking. I would expected a public key(KEY) and a private key (VI).
I integrated the files stringEncryption.h/.m and NSData+Base64.h/.m to encrypt or decrypt the string parameters from iOS , So its working well for encryption of the string but NOT decrypting the encrypted string.
Thanks David for such a great and really helpful API , actually i integrated it well even i am able to encrypt the plain text from iOS which even able to decrypt from .net with the API of .net you have given, But the text i encrypt from iOS / the encrypted data from .net that i am getting from web service is not get decrypted with the help of decrypt function that is given in the iOS class stringEncryption.m , the cipher data returned from method (NSData *)decrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7 is null each time . what should be the reason, as the key is of 16 byte the IV is also 0 from both the end. Atleast the text i encrypt from iOS should get decrypted from iOS but that also not getting done 🙁 any help will be greatly appreciated , I am struggling to solve the same issue from last 4 days !
Hi,
Have you solve the problem? I have the same issue. Server-side encrypted data is not get decrypt in iOS.
Hi,
Hi,
I have followed Joe Ruggiero’s comments to do 256 bit encryption but it does not work (I have unsuccessfully tried to encrypt/decrypt on IOS). Works fine with 128 bit encryption. Can someone post the 256 bit version of the code? Thank you.
it does work. I’ll dig up what i have and post both the Objective-C code and the c# code, if you need to transmit to a windows server to encrypt/decrypt. My version of the code forces you to pad the 32-bit key to the bounds. i.e. – if your text key is ‘myEncryptKey’, it must be padded to the bounds of the 32bits. You need to pad it. I pad it with “random” characters. And it works like a charm for me. Let dig up the code. As I grayed myself about 6-7 months ago coding/debugging this.
StringEncryption.h
//
// StringEncryption.h
//
// Created by David Davidson on 2/4/09.
//
#import
#import
#define kChosenCipherBlockSize kCCBlockSizeAES128
#define kChosenCipherKeySize kCCKeySizeAES256 //kCCKeySizeAES128
//#define kChosenDigestLength CC_SHA1_DIGEST_LENGTH
@interface StringEncryption : NSObject
+ (NSString *) EncryptString:(NSString *)plainSourceStringToEncrypt withEncryptionKey:(NSString *)nkey;
+ (NSString *) DecryptString:(NSString *) base64StringToDecrypt withEncryptionKey:(NSString *)nkey;
// my additons to the class
+ (NSString *) toHex:(NSString *)str;
+ (NSString *) reverseString:(NSString *)originalString;
+ (NSString *) generatePassCode:(SEL)passcode;
+ (NSString *) generatePassCodeFromString:(NSString *)passcode;
//- (void)testSymmetricEncryption:(UITextView *)tv;
– (NSData *)encrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7;
– (NSData *)decrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7;
– (NSData *)doCipher:(NSData *)plainText key:(NSData *)aSymmetricKey
context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7;
– (NSData*) md5data: ( NSString *) str;
@end
StringEncryption.m
//
// StringEncryption.m
//
// Created by David Davidson on 2/4/09.
//
#import “StringEncryption.h”
#import “NSData+Base64.h”
#if DEBUG
#define LOGGING_FACILITY(X, Y) \
NSAssert(X, Y);
#define LOGGING_FACILITY1(X, Y, Z) \
NSAssert1(X, Y, Z);
#else
#define LOGGING_FACILITY(X, Y) \
if(!(X)) { \
NSLog(Y); \
exit(-1); \
}
#define LOGGING_FACILITY1(X, Y, Z) \
if(!(X)) { \
NSLog(Y, Z); \
exit(-1); \
}
#endif
@implementation StringEncryption
//NSString *_key = @”1234567891123456″;
//CCOptions padding = kCCOptionPKCS7Padding;
+ (NSString *) EncryptString:(NSString *)plainSourceStringToEncrypt withEncryptionKey:(NSString *)nkey
{
StringEncryption *crypto = [[[StringEncryption alloc] init] autorelease];
NSData *_secretData = [plainSourceStringToEncrypt dataUsingEncoding:NSASCIIStringEncoding]; //<<–here
// You can use md5 to make sure key is 16 bits long
//NSData *encryptedData = [crypto encrypt:_secretData key:[crypto md5data:nkey] padding:&padding];
CCOptions padding = kCCOptionPKCS7Padding;
NSData *encryptedData = [crypto encrypt:_secretData key:[nkey dataUsingEncoding:NSUTF8StringEncoding] padding:&padding];
return [encryptedData base64EncodingWithLineLength:0]; //<<–here
}
+ (NSString *)DecryptString:(NSString *)base64StringToDecrypt withEncryptionKey:(NSString *)nkey
{
StringEncryption *crypto = [[[StringEncryption alloc] init] autorelease];
//NSData *data = [crypto decrypt:[base64StringToDecrypt dataUsingEncoding:NSUTF8StringEncoding] key:[_key dataUsingEncoding:NSUTF8StringEncoding] padding: &padding];
//NSData *data = [crypto decrypt:[NSData dataWithBase64EncodedString:base64StringToDecrypt] key:[crypto md5data:nkey] padding: &padding];
CCOptions padding = kCCOptionPKCS7Padding;
NSData *data = [crypto decrypt:[NSData dataWithBase64EncodedString:base64StringToDecrypt] key:[nkey dataUsingEncoding:NSUTF8StringEncoding] padding: &padding];
//NSData *data = [crypto decrypt:[base64StringToDecrypt dataUsingEncoding:NSUTF8StringEncoding] key:[nkey dataUsingEncoding:NSUTF8StringEncoding] padding: &padding];
return [[[NSString alloc] initWithData:[NSData dataWithData:data] encoding:NSUTF8StringEncoding] autorelease];
}
+(NSString *)toHex:(NSString *)str
{
NSString *result = @"";;
for(int i = 0; i < 16; i++)
{
result = [result stringByAppendingFormat:@"%02X", [str characterAtIndex:i]];
}
return result;
}
+(NSString *) generatePassCode:(SEL)fn
{
NSString *passcode = NSStringFromSelector(fn);
return [StringEncryption genPassCode:passcode];
}
+(NSString *) generatePassCodeFromString:(NSString *)passcode
{
return [StringEncryption genPassCode:passcode];
}
+(NSString *) genPassCode:(NSString *)passcode
{
NSArray *passcodeParts = [passcode componentsSeparatedByString:@":"];
passcode = [passcodeParts objectAtIndex:0];
if (passcode.length < kChosenCipherKeySize/*16*/)
{
int x = 9;
for (int i = passcode.length; i < kChosenCipherKeySize/*16*/; i++)
{
//passcode = [passcode stringByAppendingString:@"9"];
passcode = [passcode stringByAppendingFormat:@"%d", x];
x–;
if (x 0)
[reversedStr appendString:
[NSString stringWithFormat:@”%C”, [originalString characterAtIndex:–len]]];
return reversedStr;
}
– (NSData *)encrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7
{
return [self doCipher:plainText key:aSymmetricKey context:kCCEncrypt padding:pkcs7];
}
– (NSData *)decrypt:(NSData *)plainText key:(NSData *)aSymmetricKey padding:(CCOptions *)pkcs7
{
return [self doCipher:plainText key:aSymmetricKey context:kCCDecrypt padding:pkcs7];
}
– (NSData *)doCipher:(NSData *)plainText
key:(NSData *)aSymmetricKey
context:(CCOperation)encryptOrDecrypt
padding:(CCOptions *)pkcs7
{
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = NULL;
// Cipher Text container.
NSData * cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t * bufferPtr = NULL;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t plainTextBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t * ptr;
// Initialization vector; dummy in this case 0’s.
uint8_t iv[kChosenCipherBlockSize];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
//NSString *plainTextStr = [[NSString alloc] initWithData:plainText encoding:NSUTF8StringEncoding];
//NSLog(@”doCipher: plaintext: %@”, plainTextStr);
//[plainTextStr release];
//NSLog(@”doCipher: key length: %d”, [aSymmetricKey length]);
//LOGGING_FACILITY(plainText != nil, @”PlainText object cannot be nil.” );
//LOGGING_FACILITY(aSymmetricKey != nil, @”Symmetric key object cannot be nil.” );
//LOGGING_FACILITY(pkcs7 != NULL, @”CCOptions * pkcs7 cannot be NULL.” );
//LOGGING_FACILITY([aSymmetricKey length] == kChosenCipherKeySize, @”Disjoint choices for key size.” );
plainTextBufferSize = [plainText length];
//LOGGING_FACILITY(plainTextBufferSize > 0, @”Empty plaintext passed in.” );
//NSLog(@”pkcs7: %d”, *pkcs7);
// We don’t want to toss padding on if we don’t need to
/*
if(encryptOrDecrypt == kCCEncrypt) {
if(*pkcs7 != kCCOptionECBMode) {
if((plainTextBufferSize % kChosenCipherBlockSize) == 0) {
*pkcs7 = 0x0000;
} else {
*pkcs7 = kCCOptionPKCS7Padding;
}
}
} else if(encryptOrDecrypt != kCCDecrypt) {
NSLog(@”Invalid CCOperation parameter [%d] for cipher context.”, *pkcs7 );
}
*/
// Create and Initialize the crypto reference.
ccStatus = CCCryptorCreate(encryptOrDecrypt,
kCCAlgorithmAES128,
*pkcs7,
(const void *)[aSymmetricKey bytes],
kChosenCipherKeySize,
(const void *)iv,
&thisEncipher
);
//LOGGING_FACILITY1( ccStatus == kCCSuccess, @”Problem creating the context, ccStatus == %d.”, ccStatus );
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t) );
// Zero out buffer.
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// Initialize some necessary book keeping.
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(thisEncipher,
(const void *) [plainText bytes],
plainTextBufferSize,
ptr,
remainingBytes,
&movedBytes
);
//LOGGING_FACILITY1( ccStatus == kCCSuccess, @”Problem with CCCryptorUpdate, ccStatus == %d.”, ccStatus );
// Handle book keeping.
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
/* From CommonCryptor.h:
@enum CCCryptorStatus
@abstract Return values from CommonCryptor operations.
@constant kCCSuccess Operation completed normally.
@constant kCCParamError Illegal parameter value.
@constant kCCBufferTooSmall Insufficent buffer provided for specified operation.
@constant kCCMemoryFailure Memory allocation failure.
@constant kCCAlignmentError Input size was not aligned properly.
@constant kCCDecodeError Input data did not decode or decrypt properly.
@constant kCCUnimplemented Function not implemented for the current algorithm.
enum {
kCCSuccess = 0,
kCCParamError = -4300,
kCCBufferTooSmall = -4301,
kCCMemoryFailure = -4302,
kCCAlignmentError = -4303,
kCCDecodeError = -4304,
kCCUnimplemented = -4305
};
typedef int32_t CCCryptorStatus;
*/
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher,
ptr,
remainingBytes,
&movedBytes
);
totalBytesWritten += movedBytes;
if(thisEncipher) {
(void) CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
}
//LOGGING_FACILITY1( ccStatus == kCCSuccess, @”Problem with encipherment ccStatus == %d”, ccStatus );
if (ccStatus == kCCSuccess)
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
else
cipherOrPlainText = nil;
if(bufferPtr) free(bufferPtr);
return cipherOrPlainText;
/*
Or the corresponding one-shot call:
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
typeOfSymmetricOpts,
(const void *)[self getSymmetricKeyBytes],
kChosenCipherKeySize,
iv,
(const void *) [plainText bytes],
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes
);
*/
}
// this added by David
– (NSData*) md5data: ( NSString *) str
{
//NSLog(@”Len: %d”, str.length);
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), result );
NSString* temp = [NSString stringWithFormat:
@”%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”
/*@”%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”*/,
result[0], result[1], result[2], result[3], result[4],
result[5], result[6], result[7],
result[8], result[9], result[10], result[11], result[12],
result[13], result[14], result[15] /*,
result[16], result[17], result[18], result[19], result[20],
result[21], result[22], result[23],
result[24], result[25], result[26], result[27], result[28],
result[29], result[30], result[31]*/
];
//NSLog(@”temp: %@”, temp);
NSData *d = [NSData dataWithBytes:[temp UTF8String] length:[temp length]];
//return [NSData dataWithBytes:[temp UTF8String] length:[temp length]];
return d;
}
@end
Hey Joe, there seems to be a problem in your code listing for the StringEncryption.m class. This section here:
int x = 9;
for (int i = passcode.length; i < kChosenCipherKeySize/*16*/; i++)
{
//passcode = [passcode stringByAppendingString:@"9"];
passcode = [passcode stringByAppendingFormat:@"%d", x];
x–;
if (x 0)
[reversedStr appendString:
[NSString stringWithFormat:@"%C", [originalString characterAtIndex:–len]]];
return reversedStr;
}
Doesn't seem to make sense. It looks like it's missing a couple of brackets and some variables. Could you post the complete function? That would help me a whole tonne.
c# Code
I use the following two(2) global variables:
private static int eKeySize = 32; //16
private static int cipherKeySize = eKeySize * 8;
The following routines encrypt/decrypt based on a 32bit key size:
private string EncryptString(string plainSourceStringToEncrypt, string passPhrase)
{
//Set up the encryption objects
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passPhrase)))
{
byte[] sourceBytes = Encoding.ASCII.GetBytes(plainSourceStringToEncrypt);
ICryptoTransform ictE = acsp.CreateEncryptor();
//Set up stream to contain the encryption
MemoryStream msS = new MemoryStream();
//Perform the encrpytion, storing output into the stream
CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write);
csS.Write(sourceBytes, 0, sourceBytes.Length);
csS.FlushFinalBlock();
//sourceBytes are now encrypted as an array of secure bytes
byte[] encryptedBytes = msS.ToArray(); //.ToArray() is important, don’t mess with the buffer
//return the encrypted bytes as a BASE64 encoded string
return Convert.ToBase64String(encryptedBytes);
}
}
///
/// Decrypts a BASE64 encoded string of encrypted data, returns a plain string
///
/// an Aes encrypted AND base64 encoded string
/// The passphrase.
/// returns a plain string
private string DecryptString(string base64StringToDecrypt, string passphrase)
{
try
{
//Set up the encryption objectsr
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passphrase)))
{
byte[] RawBytes = Convert.FromBase64String(base64StringToDecrypt);
ICryptoTransform ictD = acsp.CreateDecryptor();
//RawBytes now contains original byte array, still in Encrypted state
//Decrypt into stream
MemoryStream msD = new MemoryStream(RawBytes, 0, RawBytes.Length);
CryptoStream csD = new CryptoStream(msD, ictD, CryptoStreamMode.Read);
//csD now contains original byte array, fully decrypted
//return the content of msD as a regular string
return (new StreamReader(csD)).ReadToEnd();
}
}
catch (Exception e)
{
throw new Exception(“Unable to Decrypt Data: [” + base64StringToDecrypt + “] –> ” + e.Message);
}
}
private AesCryptoServiceProvider GetProvider(byte[] key)
{
AesCryptoServiceProvider result = new AesCryptoServiceProvider();
result.BlockSize = 128;
result.KeySize = cipherKeySize; // 256;
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7;
result.GenerateIV();
result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] RealKey = GetKey(key, result);
result.Key = RealKey;
// result.IV = RealKey;
return result;
}
private byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p)
{
byte[] kRaw = suggestedKey;
List kList = new List();
for (int i = 0; i < cipherKeySize /* p.LegalKeySizes[0].MaxSize*//*MinSize*/; i += 8)
{
kList.Add(kRaw[(i / 8) % kRaw.Length]);
}
byte[] k = kList.ToArray();
return k;
}
}
}
I hope this helps.
Thx a lot. Regards.
The method for encryption and decryption would be much better if you have included a salt in the plaintext so that the cypertext is always random. This is not so hard modification, but necessary to prevent men in the middle attacks.
Otherwise useful code to start with!
Thanks a lot for posting this code. I have one doubt , how I can get NSString instead of NSData when a text is encrypted???
Or how I can send these encrypted NSData to .Net method?
Can anyone Help me????
The link is not working. Can you provide a new one? Thank you.
i want same for android and cordova
Hi All,
we have RijndaelManaged algorithm written in .net. same thing I wanted to convert in objective c . Please help me on this.
Please find the c charp code.
private string EncryptKey(string key)
{
byte[] objIV = null;
byte[] objSecretKey = null;
string strSecretKey = GetConfigValue(MyPatients.Utils.Constants.SECRET_KEY);
string strIVKey = GetConfigValue(MyPatients.Utils.Constants.IV_KEY);
string strEncrypted = null;
if ((strSecretKey.Length > 0))
{
objSecretKey = HexToByte(strSecretKey);
}
if ((strIVKey.Length > 0))
{
objIV = HexToByte(strIVKey);
}
byte[] aibUrlArray = System.Text.Encoding.UTF8.GetBytes(key);
byte[] EncryptedStringArray = null;
// instantiate a Rijndael Object
RijndaelManaged objRijndael = new RijndaelManaged();
// initializing the Rijndael Encryptor
objRijndael.Mode = CipherMode.CBC;
objRijndael.Padding = PaddingMode.PKCS7;
objRijndael.KeySize = 256;
objRijndael.BlockSize = 128;
// Creating an encryptor
ICryptoTransform objEncryptor = objRijndael.CreateEncryptor(objSecretKey, objIV);
// Creating a memory string
System.IO.MemoryStream objMemoryStream = new System.IO.MemoryStream();
CryptoStream objCryptoStream = new CryptoStream(objMemoryStream, objEncryptor, CryptoStreamMode.Write);
objCryptoStream.Write(aibUrlArray, 0, aibUrlArray.Length);
objCryptoStream.FlushFinalBlock();
// Encrypted data to the array
EncryptedStringArray = objMemoryStream.ToArray();
// Create the encrypted string:
strEncrypted = ByteToHex(EncryptedStringArray);
return strEncrypted;
}
Thanks in advance.
I tried to download the zip but it is giving me error.