Brandon M
Brandon M

Reputation: 369

3DES Decryption Sometimes Different

I'm having a problem using the CCCrypt function to simply encrypt/decrypt a chunk of data.

My platform is iOS 8 in Xcode 6.

What I'm doing is, I convert a test string to NSData format and pass it into a wrapper function I made. The return of that function is the encrypted data. I take that encrypted data and then pass it back into the function specifying that it should be decrypted.

I wrapped the use of the encryption/decryption function in a loop so I can see the inconsistent behavior more closely.

The Implementation

NSString* unencryptedString = @"Testtest";
NSData* unencryptedData = [NSData dataWithBytes:(void*)[unencryptedString UTF8String] length:[unencryptedString length]];
NSData* encryptedData = nil;
NSData* decryptedData = nil;

for(int i=0;i<100;i++)
{
    encryptedData = [NSData tripleDesEncrypt:YES Data:unencryptedData error:&err];
    decryptedData = [NSData tripleDesEncrypt:NO Data:encryptedData error:&err];

    NSLog(@"unencrypted: %@, encrypted: %s\n\ndecrypted: %s", unencryptedString, encryptedData.bytes, decryptedData.bytes);

    if(err)
        NSLog(@"error: %@", err);
}

The Function

+(NSData*)tripleDesEncrypt:(BOOL)encrypt
                  Data:(NSData *)inputData
                 error:(NSError **)error
{
    NSString* tripleDesKeyString = @"ABCd@Efghijklmno";
    NSData* tripleDesKeyData = [tripleDesKeyString dataUsingEncoding:NSUTF8StringEncoding];
    const void* tripleDesKey = [tripleDesKeyData bytes];

    NSString* ivKeyString =   @"012345678901234567890123";
    NSData* keyData = [ivKeyString dataUsingEncoding:NSUTF8StringEncoding];
    const void* ivKey = [keyData bytes];
    NSAssert(keyData.length == kCCKeySize3DES, @"tripleDesEncrypt; the keyData is an invalid size");

    NSNumber* pOptions = [NSNumber numberWithInt:kCCOptionPKCS7Padding];
    int options = [pOptions intValue];
    size_t dataMoved;

    unsigned encryptionBufferLen = inputData.length + kCCBlockSize3DES;
    void* encryptedBuffer = malloc(encryptionBufferLen);
    memset(encryptedBuffer, 0, encryptionBufferLen);

    CCCryptorStatus
    result = CCCrypt(encrypt ? kCCEncrypt : kCCDecrypt, // operation
                     kCCAlgorithm3DES, // Algorithm
                     options, // options
                     tripleDesKey, // key
                     tripleDesKeyData.length, // keylength
                     ivKey,// iv
                     inputData.bytes, // dataIn
                     inputData.length, // dataInLength,
                     encryptedBuffer, // dataOut
                     encryptionBufferLen, // dataOutAvailable
                     &dataMoved); // dataOutMoved

    NSData* outputData = [NSData dataWithBytes:encryptedBuffer length:dataMoved];
    free(encryptedBuffer);

    return outputData;
}

The Output

(I'll only run a few iterations of the output to show the weird differences.)

unencrypted: Testtest, encrypted: jgüb  -A7‘œåÅKX
decrypted: ¿Ïh5¥√‚qN;1»Í

unencrypted: Testtest, encrypted: ¥⁄˘qÓırS{ÿœ•
decrypted: Æ˛ {íÒ⁄ñè–%4¢‚g

unencrypted: Testtest, encrypted: jgüb  -A7‘œåÅKX
decrypted: Testtest∞¸yå`j/private/tmp/com.apple.CoreSimulator.SimDevice.47124028-EC86-4CC0-8CA2-7DCDED3994B1.launchd_sim/syslogsock


unencrypted: Testtest, encrypted: /Âò◊9ƒ˘=m]˚†%À
decrypted: u‹z©tÙÁ∑<%ˇπØ•

unencrypted: Testtest, encrypted: jgüb  -A7‘œåÅKX
decrypted: ¿Ïh5¥√‚qN;1»Í

unencrypted: Testtest, encrypted: jgüb  -A7‘œåÅKX
decrypted: Testtest

Upvotes: 2

Views: 305

Answers (1)

zindorsky
zindorsky

Reputation: 1592

Your key is only 16 bytes long. 3DES keys need to be 24 bytes long. So what is happening is that whatever random 8 bytes happen to be in memory after your tripleDesKey get used as the rest of key. Who knows what those bytes actually belong to, and their value could very well change in between the encryption call to tripleDesEncrypt and the decryption call. Different key = different encryption. That would produce the cases where your decryption didn't give back the original plaintext.

(BTW, I don't know why the NAssert on the key length isn't firing. Might you be compiling in release mode, or similar?)

Solution: increase the length of your key to 24 bytes.

As for the garbage you see at the end of the plaintext after decryption: How are you printing the result? The decrypted plaintext won't have a trailing null char, so if you're using something like printf then you will need to put a null char at the end of the plainext before printing it. Otherwise the system will happily output the characters after the end of your plaintext until it happens reaches a null char.

Upvotes: 2

Related Questions