1

The java code is

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

byte[] ivBytes = new byte[c.getBlockSize()];
String IV = CryptoUtils.hexEncode(ivBytes);

It's giving random 16 bytes response like

563ffcecaa43753bd09613095ad24a12.

How to write corresponding code into objective c?

I have some bunch of objective c code -

 - (NSData *)createCipher:(NSString*)data WithKey:(NSString*)key {
 NSData* result = nil;

 // setup key
 unsigned char cKey[kCCKeySizeAES256]; // room for terminator (unused)
 bzero(cKey, sizeof(cKey)); // fill with zeroes (for padding)
 [key getBytes:cKey length:kCCKeySizeAES256];

 // setup iv
 char cIv[kCCBlockSizeAES128];
 bzero(cIv, kCCBlockSizeAES128);
 if (iv) {
 [iv getBytes:cIv length:kCCBlockSizeAES128];
 }

 // setup output buffer
 size_t bufferSize = [data length] + kCCBlockSizeAES128;
 void *buffer = malloc(bufferSize);

 // do encrypt
 size_t encryptedSize = 0;
 CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, //CCOperation op
 kCCAlgorithmAES128, //CCAlgorithm alg
 kCCOptionPKCS7Padding, //CCOptions
 cKey, //const void *key
 kCCKeySizeAES256, //size_t keyLength
 cIv, // optional initialization vector
 [data bytes], // optional per op and alg
 [data length],
 buffer, // data RETURNED here
 bufferSize,
 &encryptedSize);


 if (cryptStatus == kCCSuccess) {
 result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
 } else {
 free(buffer);
 NSLog(@"[ERROR] failed to encrypt|CCCryptoStatus: %d", cryptStatus);
 }

 return result;
 }

However, this code is used to encrypt the data, now How to generate the IV ?

Nico
  • 1,788
  • 2
  • 23
  • 41
  • `563ffcecaa43753bd09613095ad24a12` is 16-bytes expressed in hexadecimal, not a "32 bit response" as stated in the question. – zaph Sep 15 '17 at 12:22
  • OMG, "iOS Developer at MasterCard", there must be someone who understands encryption there and how IVs are handled! Just wondering how MasterCard would have a developer writing encryption code without even basic training in cryptography. – zaph Sep 15 '17 at 13:01

1 Answers1

3

Just generate random bytes for the IV:

int             ivLength   = kCCBlockSizeAES128;
NSMutableData  *ivData = [NSMutableData dataWithLength:kCCBlockSizeAES128];
SecRandomCopyBytes(kSecRandomDefault, ivLength, ivData.mutableBytes);

That will produce data suitable for CCCrypt, just use ivData.bytes.

Example usage of ivData:

ccStatus = CCCrypt(
                   ...
                   ivData.bytes,
                   ...
                  );

Full example for generating a random IV at encryption and passing it prefixed to the encrypted data for decryption:

+ (NSData *)aesCBCEncrypt:(NSData *)data
                         key:(NSData *)key
                       error:(NSError **)error
{
    if (key.length != 16 && key.length != 24 && key.length != 32) {
        *error = [NSError errorWithDomain:@"keyLengthError" code:-1 userInfo:nil];
        return nil;
    }

    CCCryptorStatus ccStatus   = kCCSuccess;
    int             ivLength   = kCCBlockSizeAES128;
    size_t          cryptBytes = 0;
    NSMutableData  *dataOut     = [NSMutableData dataWithLength:ivLength + data.length + kCCBlockSizeAES128];

    int status = SecRandomCopyBytes(kSecRandomDefault, ivLength, dataOut.mutableBytes);
    if (status != 0) {
        *error = [NSError errorWithDomain:@"ivError" code:status userInfo:nil];
        return nil;
    }
    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmAES,
                       kCCOptionPKCS7Padding,
                       key.bytes, key.length,
                       dataOut.bytes,
                       data.bytes, data.length,
                       dataOut.mutableBytes + ivLength, dataOut.length,
                       &cryptBytes);

    if (ccStatus == kCCSuccess) {
        dataOut.length = cryptBytes + ivLength;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError" code:ccStatus userInfo:nil];
        }
        dataOut = nil;
    }

    return dataOut;
}

+ (NSData *)aesCBCDecrypt:(NSData *)data
                         key:(NSData *)key
                       error:(NSError **)error
{
    if (key.length != 16 && key.length != 24 && key.length != 32) {
        *error = [NSError errorWithDomain:@"keyLengthError" code:-1 userInfo:nil];
        return nil;
    }

    CCCryptorStatus ccStatus   = kCCSuccess;
    int             ivLength   = kCCBlockSizeAES128;
    size_t          clearBytes = 0;
    NSMutableData *dataOut     = [NSMutableData dataWithLength:data.length - ivLength];

    ccStatus = CCCrypt(kCCDecrypt,
                       kCCAlgorithmAES,
                       kCCOptionPKCS7Padding,
                       key.bytes, key.length,
                       data.bytes,
                       data.bytes + ivLength, data.length - ivLength,
                       dataOut.mutableBytes, dataOut.length,
                       &clearBytes);

    if (ccStatus == kCCSuccess) {
        dataOut.length = clearBytes;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError" code:ccStatus userInfo:nil];
        }
        dataOut = nil;
    }

    return dataOut;
}

Test:

NSError *error;
NSData *key   = [@"Bad example key " dataUsingEncoding:NSUTF8StringEncoding];
NSData *clear = [@"Test Input"       dataUsingEncoding:NSUTF8StringEncoding];

NSData *encrypted = [Crypto aesCBCEncrypt:clear
                                         key:key
                                       error:&error];

NSData *decrypted = [Crypto aesCBCDecrypt:encrypted
                                         key:key
                                       error:&error];

NSLog(@"key:       %@", key);
NSLog(@"clear:     %@", clear);
NSLog(@"encrypted: %@", encrypted);
NSLog(@"decrypted: %@", decrypted);

Output:

key:       42616420 6578616d 706c6520 6b657920
clear:     54657374 20496e70 7574
encrypted: 44f02b5e 40bf5031 01cc55fd cad80a77 790b9d05 5a6c8de7 6c949191 d3ba57de
decrypted: 54657374 20496e70 7574
zaph
  • 111,848
  • 21
  • 189
  • 228
  • Thanks Zaph!, We must follow the same cipher generation algo i.e. "AES/CBC/PKCS5Padding" to generate IV, how can random byte generation solve our problem when at the time of decryption at server end process will be reversed by java lang ? – Nico Sep 15 '17 at 07:38
  • An IV is not generated at decryption time, the IV used for encryption must be passed to the decryption somehow, one generally used method is to prepend it to the encrypted data, that is what my example code does. – zaph Sep 15 '17 at 12:29
  • Zalph I was really happy to use this code and was able to encrypt decrypt by using KEY and IV . But I got stuck while creating a salt by using PKDF2 and to prepend with encrypted key and to decrypt the same . can you also please kindly help us by including that in the answer ? – User1075 Nov 04 '20 at 19:03
  • @zaph https://stackoverflow.com/questions/64679465/how-to-add-salt-to-aes-encryption-in-ios-and-decrypting-it-using-objective-c .... I need your enlightenment in this link sir – User1075 Nov 04 '20 at 19:05
  • Amazing.. its working fine ... Thanks a lot @zaph – Hitarth Jun 23 '21 at 12:56