3

I am building a iPhone app which uses a c# web service. My iPhone app takes in some data and encrypts it and passes it to the web service. How do I decrypt the data in C#?

My iPhone app contains the following code:

NSString *pString = @"Some string to be encoded";
NSString *key = @"My encryption key";

NSData *pData = [pString dataUsingEncoding:NSUTF8StringEncoding];

pData = [pData AES256EncryptWithKey:key];
NSString *pID = [pData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

EDIT: The data is already stored in the web service so I can't readily change the encryption approach. The C# application is not on the server so there is no possibility of compromising the key.

I have tried the following C# code to decrypt the data:

    static string DecryptString(string encryptedText, string key)
    {
        byte[] encryptedString = Convert.FromBase64String(encryptedText);
        byte[] encryptionKey = Encoding.UTF8.GetBytes(key.Substring(0, 32));

        using (var provider = new AesCryptoServiceProvider())
        {
            provider.Mode = CipherMode.CBC;
            provider.Padding = PaddingMode.PKCS7;
            provider.Key = encryptionKey;
            using (var ms = new MemoryStream(encryptedString))
            {
                // Read the first 16 bytes which is the IV.
                byte[] iv = new byte[16];
                ms.Read(iv, 0, 16);
                provider.IV = iv;

                using (var decryptor = provider.CreateDecryptor())
                {
                    using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                    {
                        using (var sr = new StreamReader(cs))
                        {
                            return sr.ReadToEnd();
                        }
                    }
                }
            }
        }
    }

However, I get the following exception:

System.Security.Cryptography.CryptographicException was unhandled
HResult=-2146233296 Message=Padding is invalid and cannot be removed.

The encryptedText received by DecryptString is 80 bytes in length.

JSWilson
  • 1,113
  • 1
  • 11
  • 28
  • try this example code: http://www.mediafire.com/download/v0d38r3p2rh10x0/EncryptStringSample.zip – princ___y Dec 14 '15 at 05:01
  • 1
    @JSWilson There are several issues: 1. AES has key sizes of 128-bits, 192-bits and 256-bits, but not 64-bytes (512-bits). 2. The iv is generally random data of the block size (128-bits for AES) and prepended to the encrypted data. The mode is generally CBC and the padding PKCS#7. Make sure the key and iv are exactly the required sizes. – zaph Dec 14 '15 at 12:26
  • The method: `AES256EncryptWithKey` is an app implementation, you will need to provide that code for it. – zaph Dec 14 '15 at 13:26
  • This is what I am using for encryption: http://stackoverflow.com/questions/11482470/ios-5-data-encryption-aes-256-encryptwithkey-not-found/11483134#11483134 – JSWilson Dec 14 '15 at 13:55
  • @prince The sample you provided has a default IV built into the sample so it won't work with the data coming from IOS. – JSWilson Dec 14 '15 at 14:47

2 Answers2

3

The sample ObjC code uses by default CBC modem, PKCS#7 padding and a default iv of 16 0x00 bytes.

The C# also uses CBC mode and PKCS#7 padding. The decryption code expects a 16-byte iv pre-pended to the encrypted data and that does not exist.

byte[] iv = new byte[16];
ms.Read(iv, 0, 16);
provider.IV = iv;

This needs to be changed so that iv is set to an array of 16 0x00 bytes and the ms.Read(iv, 0, 16) statement needs to be deleted so the decrypt function gets all of the encrypted data.

Notes:

  1. Using a devault anything in encryption is a bad idea, always provide the correect length data.

  2. Authentication of the encrypted data needs should be added so that it can be determined if there an incorrect key or the data has been tampered with.

  3. There really should be a version number and a random IV used and prepended to the encrypted so you should really consider correcting this. This demonstrates why a version number generally needs to be provided and used.

RNCryptor covers the above issues.

The handling of the encryption key also needs to be considered so that is is as secure as necessary.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • you are a good guy! I tried replacing the three lines you did not like with provider.IV = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; However, that did not work. I wrote a corresponding C# Encryption routine to check my C# Decryption routine. The C# routines work well together but do not work with the IOS one. The C# generates/expects 128 bytes while the IOS generates/expects 64 bytes for the same data input. I need to take a closer look at what the IOS routine is doing. – JSWilson Dec 14 '15 at 19:21
  • What is the length of the input data, can you provide an example, input and output? Hex dumps are best. There may be a difference inthe input, perhapps UTF-16 on C# and UTF-8 on iOS. PKCS#7 padding. PKCS#7 padding will add bytes on encryption and remove them on decryption. – zaph Dec 14 '15 at 19:50
  • Please provide the key that was used for the above sample (in hex or Base64. The above sample has an input length of 57 bytes and an output of 89 Base64 encoded characterts whic is 64 decoded bytes: `2F C6 AC 89 90 ED 3F 10 4D 3F 42 61 1B 43 0F 10 29 51 E6 86 12 9E 6F A9 A6 0B EB 00 49 B7 A3 83 07 A9 2F 15 86 88 E7 D3 AA E4 80 CB 8B 8C A1 BA 6F B8 4A 52 9E BC 6D CD 9D 34 5C 38 90 BE ED 89`. This makes sense, PKCS#7 padding would add the 7 bytes. – zaph Dec 14 '15 at 22:18
  • 1
    How are you converting the key string such as `"My encryption key"` into the encryption key? The C# method will make a decision on the encryption key length based on the provided key string and padded with *perhaps* nulls. It may even be using a UTF-16 version of the string. The ObjC code has an explicitly specified key length and will null pad as necessary. But a string should never be used for the encryption key, it must be used to derive the key, generally now with PBKDF2 (Password Based Key Derivation Function) with a rather large iteration count and a seed. Using default padding is bad. – zaph Dec 14 '15 at 23:03
  • The Objective-C code does not behave as I thought it would. The handling of the IV and the key are not satisfactory. I will have to change the Objective-C code as well as come up with corresponding C# routines. Looks like I have to go to RNCryptor. – JSWilson Dec 15 '15 at 03:26
  • @JSWilson were you able to implement this successfully ? if yes, plz show your implementation. – ahmad Aug 07 '16 at 13:08
1

You need to first decode the base-64 encoded string to a byte[] - see Convert.FromBase64String(). Then you need to use the Aes class to decrypt it - there's an example on its documentation page.

gregstoll
  • 1,318
  • 9
  • 14
  • What AES.Mode should I be using to be compatible with Objective-C? Where do I get the IV from? My key size is 64 bytes. – JSWilson Dec 14 '15 at 12:03
  • The referenced documentation page is very general and has several parameters that are not applicable to AES. – zaph Dec 14 '15 at 12:33