Search code examples
objective-cnsstringnsdatacbc-mode

How does AES-128 CBC encryption with IV work in objective-C?


I am trying to encrypt a string with 'AES-128 CBC with IV'. Here is the input parameter and expected output:

Key: 000102030405060708090A0B0C0D0E0F

IV: 00102030405060708090A0B0C0D0E0F0

Input data: EA010B23CDA9B16F0001020304050607

Output: B773C36749E87D3F8FED98FE52026A15

I have verified the output on this web site: http://extranet.cryptomathic.com/aescalc/index?key=000102030405060708090A0B0C0D0E0F&iv=00102030405060708090A0B0C0D0E0F0&input=EA010B23CDA9B16F0001020304050607&mode=cbc&action=Encrypt&output=B773C36749E87D3F8FED98FE52026A15

How to encrypt a string with AES-128 CBC with IV in objective C? (With same result as http://extranet.cryptomathic.com/aescalc) I am trying to get the encrypted string - B773C36749E87D3F8FED98FE52026A15 , but no luck.



I have tried to use this library for the encryption: https://github.com/Pakhee/Cross-platform-AES-encryption/tree/master/iOS

Here is my objective c code:

NSString* data = @"EA010B23CDA9B16F0001020304050607";
NSString* key = @"000102030405060708090A0B0C0D0E0F";
NSString* iv = @"00102030405060708090A0B0C0D0E0F0";


NSData *encryptedData = [[StringEncryption alloc] encrypt:[@"EA010B23CDA9B16F0001020304050607" dataUsingEncoding:NSUTF8StringEncoding] key:key iv:iv];
NSLog(@"encryptedData %@", encryptedData);

The output of encryptedData is: <68f8ed75 e79f2ba2 c80e67a2 f0c84b7a c4b07fd1 59e937e5 14644cba c0ddb60c 40502375 7798e7a1 58bd05a5 b3d9e7bd>



I expect the value of *encryptedData should be <42373733 43333637 34394538 37443346 38464544 39384645 35323032 36413135>, which is hex of B773C36749E87D3F8FED98FE52026A15

I have tried another library - https://github.com/dev5tec/FBEncryptor

NSData* _data = [data dataUsingEncoding:NSUTF8StringEncoding];
NSData* _key = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData* _iv = [iv dataUsingEncoding:NSUTF8StringEncoding];


NSData *encryptedData2 = [FBEncryptorAES encryptData:_data key:_key iv:_iv];
NSLog(@"encryptedData2 = %@", encryptedData2);

Output is <2beea977 aef69eb1 ed9f6dd0 7bf5f1ce d1e5df46 2cbf8465 773f122d 03267abb 2e113d9b 07189268 4fd6babe 7b1c0056>

It seems that I am using wrong library or I have wrong input to the encryption function. Any recommendation of AES library for objective c?


Solution

  • Common Crypto is the correct thing to use for encryption for iOS and OSX. The issue it to provide the correct input.

    The input key, iv and data appear to be in hexadecimal. Cryptomathic expects it inputs to be in hexadecimal and it's output is in hexadecimal so it works correctly.

    But the ObjC code uses:

    NSString* data = @"EA010B23CDA9B16F0001020304050607";
    NSData* _data = [data dataUsingEncoding:NSUTF8StringEncoding];
    

    which uses the hexadecimal as a character string.
    Instead use a hex to data conversion such as @Larme linked to, see the first comment.

    From the sizes of the input and output it appears you are using PKCS#7 padding which adds a full block of padding if the input is an exact multiple of the block size, Cryptomathic does not add PKCS#7 padding.

    Update

    @interface Crypt : NSObject
    + (NSData *)aes128Data:(NSData *)dataIn;
    + (NSData *)dataFromHexString:(NSString *)hexString;
    @end
    
    @implementation Crypt
    
    + (NSData *)aes128Data:(NSData *)dataIn
                 operation:(CCOperation)operation  // kCC Encrypt, Decrypt
                       key:(NSData *)key
                   options:(CCOptions)options      // kCCOption PKCS7Padding, ECBMode,
                        iv:(NSData *)iv
                     error:(NSError **)error
    {
        CCCryptorStatus ccStatus   = kCCSuccess;
        size_t          cryptBytes = 0;
        NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
    
        ccStatus = CCCrypt( operation,
                           kCCAlgorithmAES,
                           options,
                           key.bytes, key.length,
                           iv.bytes,
                           dataIn.bytes, dataIn.length,
                           dataOut.mutableBytes, dataOut.length,
                           &cryptBytes);
    
        if (ccStatus == kCCSuccess) {
            dataOut.length = cryptBytes;
        }
        else {
            if (error) {
                *error = [NSError errorWithDomain:@"kEncryptionError"
                                             code:ccStatus
                                         userInfo:nil];
            }
            dataOut = nil;
        }
    
        return dataOut;
    }
    
    + (NSData *)dataFromHexString:(NSString *)hexString {
        char buf[3];
        buf[2] = '\0';
        unsigned char *bytes = malloc([hexString length]/2);
        unsigned char *bp = bytes;
        for (CFIndex i = 0; i < [hexString length]; i += 2) {
            buf[0] = [hexString characterAtIndex:i];
            buf[1] = [hexString characterAtIndex:i+1];
            char *b2 = NULL;
            *bp++ = strtol(buf, &b2, 16);
        }
    
        return [NSData dataWithBytesNoCopy:bytes length:[hexString length]/2 freeWhenDone:YES];
    }
    
    @end
    
    NSString *dataHexString = @"EA010B23CDA9B16F0001020304050607";
    NSString *keyHexString = @"000102030405060708090A0B0C0D0E0F";
    NSString *ivHexString = @"00102030405060708090A0B0C0D0E0F0";
    
    NSLog(@"dataHexString: %@", dataHexString);
    NSLog(@"keyHexString:  %@", keyHexString);
    NSLog(@"ivHexString:   %@", ivHexString);
    
    NSData *data = [Crypt dataFromHexString:dataHexString];
    NSData *key  = [Crypt dataFromHexString:keyHexString];
    NSData *iv   = [Crypt dataFromHexString:ivHexString];
    
    NSLog(@"data: %@", data);
    NSLog(@"key:  %@", key);
    NSLog(@"iv:   %@", iv);
    
    NSError *error;
    NSData *encryptedData = [Crypt
                             aes128Data:data
                             operation:kCCEncrypt
                             key:key
                             options:0
                             iv:iv
                             error:&error];
    
    NSLog(@"encryptedData %@", encryptedData);
    

    Output:

    dataHexString: EA010B23CDA9B16F0001020304050607
    keyHexString:  000102030405060708090A0B0C0D0E0F
    ivHexString:   00102030405060708090A0B0C0D0E0F0
    
    data: <ea010b23 cda9b16f 00010203 04050607>
    key:  <00010203 04050607 08090a0b 0c0d0e0f>
    iv:   <00102030 40506070 8090a0b0 c0d0e0f0>
    
    encryptedData: <b773c367 49e87d3f 8fed98fe 52026a15>
    

    Note encryptedData matches the Cryptomathic result.