views:

429

answers:

3

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?

Thanks in advanced

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

    }
A: 

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
+4  A: 

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
Thank you so much. I just needed to convert the key into a c string
G Mauri
A: 

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