4

I need to encrypt a string on the iPhone and send it to a .Net for decryption using Triple DES. I am able to encrypt/decrypt on the iPhone and with .Net, but I get different results in both platforms.

I use the very same code as the encryption/decryption with AES between .Net and iPhone in here

The only thing that I changed .net is the encryption algorithm, so where it says AesCryptoServiceProvider, I put TripleDesServiceProvider

As in .net the only thing that I changed is the encryption algorithm, so where it says kCCAlgorithmAES128, I put kCCAlgorithm3DES

What am I missing?

[UPDATE]

Thanks for your responses.

If I stay in the same platform I can encrypt/decrypt without a problem, but if I encrypt in iPhone and decrypt in .net there is a problem because in each platform has different results with the same inputs.

As Overslacked said I think the problem has to do with salt, but I couldn't find any sha or md5 documentation that the algorithm is using in each platform, or any parameter to customize this.

Here is the code that I am actually using in iPhone:

int main(int argc, char *argv[]){
    NSString * _secret = @"hello";    
    NSString * _key = @"1234567890";    
    _out = [self doCipher:_secret key:_key context:kCCEncrypt];    
    NSLog(@"encrypted data in str: %@", _out);    
    _outDecrypted = [StringEncryption doCipher:_out key:_key context:kCCDecrypt];    
    NSLog(@"decrypted data in str: %@", _outDecrypted);    
}

+ (NSString *)doCipher:(NSString *)sTextIn key:(NSString *)sKey
               context:(CCOperation)encryptOrDecrypt {

    NSMutableData * dTextIn;
    if (encryptOrDecrypt == kCCDecrypt) {    
        dTextIn = [[[NSData alloc] base64DecodeString:sTextIn ]mutableCopy];    
    }    
    else{    
        dTextIn = [[sTextIn dataUsingEncoding: NSASCIIStringEncoding]mutableCopy];    
    }       
    NSMutableData * dKey = [[sKey dataUsingEncoding:NSASCIIStringEncoding]mutableCopy];            
    [dKey setLength:24];        
    uint8_t *bufferPtr1 = NULL;    
    size_t bufferPtrSize1 = 0;    
    size_t movedBytes1 = 0;    
    uint8_t iv[kCCBlockSize3DES];    
    memset((void *) iv, 0x0, (size_t) sizeof(iv));    
    bufferPtrSize1 = ([sTextIn length] + kCCBlockSize3DES) & ~(kCCBlockSize3DES -1);    
    bufferPtr1 = malloc(bufferPtrSize1 * sizeof(uint8_t));    
    memset((void *)bufferPtr1, 0x00, bufferPtrSize1);    
    ccStatus = CCCrypt(encryptOrDecrypt, // CCOperation op    
        kCCAlgorithm3DES, // CCAlgorithm alg    
        kCCOptionPKCS7Padding, // CCOptions options    
        [dKey bytes], // const void *key    
        [dKey length], // size_t keyLength    
        iv, // const void *iv    
        [dTextIn bytes], // const void *dataIn
        [dTextIn length],  // size_t dataInLength    
        (void *)bufferPtr1, // void *dataOut    
        bufferPtrSize1,     // size_t dataOutAvailable 
        &movedBytes1);      // size_t *dataOutMoved     
    NSString * sResult;    
    if (encryptOrDecrypt == kCCDecrypt){    
        sResult = [[[ NSString alloc] initWithData:[NSData dataWithBytes:bufferPtr1     
                           length:movedBytes1] encoding:NSASCIIStringEncoding] autorelease];    
    }    
    else {    
        NSData *dResult = [NSData dataWithBytes:bufferPtr1 length:movedBytes1];    
        sResult = [dResult base64EncodeData:dResult];    
    }       
    return sResult;
}   

Here is the code that I am using for .net

    class Program
    {
        static void Main(string[] args)
        {
           string key = "1234567890";
           string secret = "hello";
           string crypto = EncryptedString.EncryptString(secret, key);
           Console.WriteLine(crypto);
           secret = EncryptedString.DecryptString(crypto, key);
           Console.WriteLine(secret);
           Main(null); 

        }

    }


 public class EncryptedString
    {
        public static string EncryptString(string plainSourceStringToEncrypt, string passPhrase)
        {
            //Set up the encryption objects
            using (TripleDESCryptoServiceProvider acsp = GetProvider(Encoding.ASCII.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
                String b64 =  System.Text.ASCIIEncoding.ASCII.GetString(encryptedBytes);
                return Convert.ToBase64String(encryptedBytes);
            }
        }


        public static string DecryptString(string base64StringToDecrypt, string passphrase)
        {
            //Set up the encryption objects
            using (TripleDESCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passphrase)))
            {
                byte[] RawBytes = Convert.FromBase64String(base64StringToDecrypt);
                ICryptoTransform ictD = acsp.CreateDecryptor();
                MemoryStream msD = new MemoryStream(RawBytes, 0, RawBytes.Length);
                CryptoStream csD = new CryptoStream(msD, ictD, CryptoStreamMode.Read);
                return (new StreamReader(csD)).ReadToEnd();
            }
        }

        private static TripleDESCryptoServiceProvider GetProvider(byte[] key)
        {
            TripleDESCryptoServiceProvider result = new TripleDESCryptoServiceProvider();
            result.Mode = CipherMode.CBC;
            result.Padding = PaddingMode.PKCS7;
            result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
            result.Key = key;
            return result;
        }

    }
BenMorel
  • 34,448
  • 50
  • 182
  • 322
G Mauri
  • 43
  • 1
  • 4
  • 1
    AES and TripleDES are completely different algorithms. – overslacked Dec 08 '09 at 21:29
  • What do you mean, "I get different results in both platforms." What is different? When encryption is used correctly, a given plaintext should produce different ciphertext each time it is encrypted. Is that what you're seeing? – erickson Dec 08 '09 at 21:30
  • I need to use TripleDes instead of AES. If I encrypt secret="hello" key="1234567890" I get in iphone="My8ZTBX07jU=", and in .net="qpbpZnxzFqQ=" – G Mauri Dec 08 '09 at 21:54
  • 1
    There are no "salts" in encryption but possible an IV (initialization vector) depending on mode. ECB has no iv. – zaph Dec 09 '09 at 18:11
  • YOu need to separate the problem. First get the crypto working with identical 24 byte keys. The code is making assumptions about string conversions and padding. Just use char key[] = "111111111111111111111111"; on both sides. Ship the base64 stuff. hex dump the key and data in and data out. When you have that working add back in the other stuff. – zaph Dec 09 '09 at 18:43
  • example for encrypt and decrypt with 3Des (also with Des and AES) it works fine and get the result exactly the same with ASP.NET See: http://discussions.apple.com/thread.jspa?messageID=9017515 – zaph Dec 09 '09 at 18:50
  • Zaph - for the purposes of this question the salts and IVs are the same thing. The link in G Mauri's original question points to a Stack Overflow question in which this problem and solution is explained very well: http://stackoverflow.com/questions/538435/aes-interoperability-between-net-and-iphone/ – overslacked Dec 09 '09 at 19:34

3 Answers3

4

AES keys are 128, 192 or 256 bits, 192 is rarely seen.

Triple DSE is usually 112 bits but can be 168 bits. Notice that this is specified in bits. Triple DES expects each byte to have a parity bit and thus 7 data bits. Usually Triple DES is used in a compatibility mode (compatible with Single DES) by performing single DES encode, decode and encode with one key used for both an encode and decode, k1, k2, k1. Thus 8 byte key * 7 bits * 2 = 112. Sometimes decode, encode, decode is used so this too can be a problem.

Get the keys correct first. Since you are changing from AES to 3DES the key sizes will be different, that may be a problem. Also make sure the modes and IVs are correct.

The best bet is to dump the key, IV (if there is one) and data in hex on both sides of the crypto function and on both platforms. First work to get these to match. Then the problem is in the base64 or whatever other manipulations are involved.

zaph
  • 111,848
  • 21
  • 189
  • 228
0

You need to match all of your inputs, keys, salts and algorithms on both sides EXACTLY for this to work. AesCryptoServiceProvider and TripleDesServiceProvider will produce different results and kCCAlgorithmAES128 and kCCAlgorithm3DES will produce different results.

Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
0

Be mindful of the random value that .Net's crypto package will add to your data before encryption, if I recall correctly it's usually the first 16 bits of data.

jessecurry
  • 22,068
  • 8
  • 52
  • 44