AES interoperability between .Net and iPhone

Posted by & filed under code.

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.

Download zip.

80 Responses to “AES interoperability between .Net and iPhone”

  1. checcco

    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

    Reply
  2. Mark

    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

    Reply
  3. locoVJ

    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

    Reply
  4. bbb

    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

    Reply
  5. Ben

    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.

    Reply
  6. Rpmobile

    Just discovered this post while searching for iphone->.NET crypto interop. Did the base 64 bug get addressed?

    Thanks!

    Reply
  7. jeet

    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

    Reply
  8. 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

    Reply
  9. Guna

    Thanks for the code, it gives the clear idea for encrypting data on the iPhone and decrypting it using .Net.

    Reply
  10. Karloz

    YOU ARE THE MAN !!!!

    saved me !

    thanks everyone for fixing the Base64 Problem !!!!

    Reply
  11. Ken

    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

    Reply
  12. Terry in SD

    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

    Reply
  13. Myke Koscielski

    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?

    Reply
  14. Radu

    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.

    Reply
  15. Radu

    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.

    Reply
  16. Radu

    @ 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.

    Reply
  17. Spare

    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!

    Reply
  18. Spare

    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…

    Reply
  19. Spare

    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?

    Reply
  20. joshua

    hey it does not work Spare and Radu. how did you set it to PKCS7. it seems to be PKCS7 already?
    thanks

    Reply
  21. Spare

    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 );
    }
    */

    Reply
  22. mike

    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];

    Reply
  23. pk

    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

    Reply
  24. Ken

    Mike nailed it… the DecryptString method now works for me. I’m decoding Base64 encoded strings from a .NET web service. Thanks!

    Reply
  25. Ken

    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.

    Reply
  26. Dan D.

    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!

    Reply
  27. Dan D.

    Does anyone know how to convert unicode to base64 within the xcode code sample? any help would be appreciated!

    Reply
  28. Vittal

    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.

    Reply
  29. Arci

    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!

    Reply
  30. Arci

    Please disregard my question. If I’m not mistaken it’s using AES/CBC/PKCS7Padding.

    Reply
  31. andsakk

    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.

    Reply
  32. Kyle

    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!

    Reply
  33. Sachin

    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 :)

    Reply
  34. Sachin

    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 :)

    Reply
  35. virat

    guyz, anyone getting different strings on iphone and c# after encryption,please use key of length 16 char while encrypting.
    it works….thanx

    Reply
  36. Tommy

    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

    Reply
  37. Shannon

    Thanks Mike, after making those changes you mentioned, my code works. You rock!

    Reply
  38. Felipe

    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

    Reply
  39. Mesut

    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 :)

    Reply
  40. Mecha

    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 ?

    Reply
  41. Adrian

    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!

    Reply
  42. Rachit

    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?

    Reply
  43. Aj

    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;

    Reply
    • Joe Ruggiero

      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.

      Reply
      • Joe Ruggiero

        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.

        Reply
  44. bhargav

    result.Padding = PaddingMode.None; it is not working when csS.FlushFinalBlock(); executed it gives an error.How to resolve it.?
    Give me solution.

    Reply
  45. Eelco

    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.

    Reply
  46. Joe

    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.

    Reply
  47. Bo

    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).

    Reply
  48. iShwar

    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.

    Reply
  49. iShwar

    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 !

    Reply
    • Murat

      Hi,

      Have you solve the problem? I have the same issue. Server-side encrypted data is not get decrypt in iOS.

      Reply
  50. marcel

    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.

    Reply
    • Joe Ruggiero

      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.

      Reply
    • Joe Ruggiero

      StringEncryption.h

      //
      // StringEncryption.h
      //
      // Created by DAVID VEKSLER 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

      Reply
  51. Joe Ruggiero

    StringEncryption.m

    //
    // StringEncryption.m
    //
    // Created by DAVID VEKSLER 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, 0×0, (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 = 0×0000;
    } 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, 0×0, 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

    Reply
  52. Joe Ruggiero

    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;
    }
    }
    }

    Reply
  53. Lyubomir

    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!

    Reply

Leave a Reply