2

I am trying to encrypt a NSString using 3DES with CBC mode encryption on iOS.

Same encryption method is being used on ASP.NET as well and the encrypted string they are getting works with the webservice. The encrypted string for woodcraft554 obtained from .NET code is: 9SWzd+rlvu/tK5UZoCXt8Q==.

.NET is using zero padding for encrytion. The code I am using is:

+(NSString*)new3DESwithoperand:(NSString*)plaintext encryptOrDecrypt:(CCOperation)encryptorDecrypt key:(NSString*)key initVec:(NSString*)initVec
{     

NSData* data = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
const void *vplainText = [data bytes];;
size_t plainTextBufferSize = [data length];
NSLog(@"%@, Length: %u",[data description],[data length]);

size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
NSLog(@"%zu, sizof of uint8_t: %zu",bufferPtrSize, sizeof(uint8_t));
size_t movedBytes = 0;
uint8_t *bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
NSLog(@"%zu",sizeof(bufferPtr));
memset((void*)bufferPtr, 0x0, bufferPtrSize);
NSLog(@"%zu",sizeof(bufferPtr));
//    memset((void *)initVec, 0x0, (size_t) sizeof(initVec));
const void * vkey = [[NSString base64DataFromString:key] bytes];
const void *vinitVec = [[NSString base64DataFromString:initVec] bytes];
NSLog(@"vinitvec: %@",[[NSString base64DataFromString:initVec] description]);

CCCryptorStatus ccStatus;
ccStatus = CCCrypt(encryptorDecrypt,
                   kCCAlgorithm3DES,
                   kCCOptionPKCS7Padding & kCCModeCBC,
                   vkey,
                   kCCKeySize3DES,
                   vinitVec,
                   vplainText,
                   plainTextBufferSize,
                   (void*)bufferPtr,
                   bufferPtrSize,
                   &movedBytes);

NSData* result = [NSData dataWithBytes:(const void*)bufferPtr length:(NSUInteger)movedBytes];
NSString* str = [NSString base64StringFromData:result length:result.length];
NSLog(@"%@",str);

return str;
}

I have compared vplainText, vkey and vinitVec from objective-c code to that in .NET. They are same. The encrypted string I am getting is 9SWzd+rlvu8=. I believe it's something to do with padding.

Here is equivalent .NET code they are using:

protected string EncryptCreditCard(string creditCard)
{
    try
    {
        string ENCRYPTION_KEY = ConfigurationManager.AppSettings["ENCRYPTION_KEY"].ToString();
        string ENCRYPTION_IV = ConfigurationManager.AppSettings["ENCRYPTION_IV"].ToString();

        SymmetricAlgorithm sa = SymmetricAlgorithm.Create("TripleDES");
        sa.Key =   System.Convert.FromBase64String(ENCRYPTION_KEY);
        sa.IV =  System.Convert.FromBase64String(ENCRYPTION_IV);
        sa.Padding = PaddingMode.Zeros;

        byte[] inputByteArray = Encoding.ASCII.GetBytes(creditCard);
        MemoryStream mS = new MemoryStream();

        ICryptoTransform trans = sa.CreateEncryptor();
        byte[] buf = new byte[2048];
        CryptoStream cs = new CryptoStream(mS, trans, CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();

        return Convert.ToBase64String(mS.ToArray());
    }
    catch
    {
        return "";
    }
}

How can I get a correct encrypted string in iOS ?

Axel Isouard
  • 1,498
  • 1
  • 24
  • 38
Rishabh Tayal
  • 497
  • 7
  • 15

2 Answers2

1

By using zero padding. Your code clearly states kCCOptionPKCS7Padding, which is not zero padding. The cipher text seems identical otherwise.

Note that you are better off using PaddingMode.PKCS7 in your .NET code. It adds some data in the odd case that your plain text is already a number of times the block size in size, but it is standardized and unpadding is not depending on the plain text value anymore.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thanks for the reply owlstead. How would you apply zero padding on iOS code. I tried passing '0' as parameter in CCCrypt method in place of kCCOptionPKCS7Padding. It doesn't seem to work as well. – Rishabh Tayal Oct 01 '12 at 13:54
  • You may have to program this yourself - zero padding is not standardized. Zero padding simply adds zero bytes to the plaintext until the plaintext is a multiple of the block size. In your case it does not pad as this is already the case. Note that zero padding should not be used with binary data for which the length cannot be determined otherwise (as the binary data may end with a byte set to 0) – Maarten Bodewes Oct 01 '12 at 14:57
  • Obviously it is better to switch to `PaddingMode.PKCS7` in your .NET compatible code, in case you were wondering. You asked to do the opposite, but using PKCS#7 padding is recommended. – Maarten Bodewes Oct 01 '12 at 23:18
  • It's not possible to change code in .NET now. I have to implement zero padding in iOS. I couldn't find any resources online for implementing zero padding in iOS. – Rishabh Tayal Oct 02 '12 at 15:49
  • Just copy your plain text into a new or cipher text buffer (which already should be large enough). Then add bytes valued `00` until you reach the end. Replace the standard plain text buffer with the one you copied the plain text into + padding and encrypt that, without using `kCCOptionPKCS7Padding`. No need for libraries. – Maarten Bodewes Oct 02 '12 at 16:45
  • Thanks for answer...!!! You went a little over my head this time. I am not sure how would you add bytes 00 until I reach the end. – Rishabh Tayal Oct 02 '12 at 19:19
  • The end is the first block boundary you find. (Triple) DES uses 8 byte blocks. So if you have a plain text of 24 bytes you don't need to write any `00` bytes to the buffer. If the plain text is 25 bytes you need to write 32 - 25 = 7 bytes though, the maximum number of padding bytes. – Maarten Bodewes Oct 02 '12 at 20:48
  • I mean my concern was how would you programatically add bytes to the input buffer. – Rishabh Tayal Oct 02 '12 at 21:12
  • Maybe you could put that in another question Rishabh. How to add bytes to an input buffer. Note that I even explained it in one of the comments. Sheesh. – Maarten Bodewes Oct 06 '12 at 21:00
0

The issue is with "key" which is used for encryption. iOS uses a 24Byte key while Adnroid and .NET use 16Byte key.

Have posted a detailed solution for the same issue, which depicts key generation. Solution for different encryption value generated in iOS

Community
  • 1
  • 1
Jugal Desai
  • 164
  • 8
  • This is not an iOS vs Adnroid issue, it is two different schemes of 3DES keys. 3DES encrypts with three 8-byte keys serially (only 56-bits of the 3 bytes are used as key material). "Full" 3DES is 24-bytes with generally a scheme of ede (encrypt with the first key, decrypt that output with the second key and encrypt that output with the third key) but there are other sequences occasionally used. For certain backward compatibility systems (banking is a major one) there is a version where two 8-byte keys are used and one is used twice. This is what Android is doing here. – zaph Oct 20 '14 at 12:10
  • @Zaph I mentioned that the issue is with the Key which is used. There is no issue in Android or iOS. Also thanks for mentioning about the banking sector, i didn't knew that. – Jugal Desai Oct 21 '14 at 13:13