Search code examples
iosencryptionaescommoncrypto

AES128 CTR encryption with iv


I want to implement AES128 CTR with iv and key. I'm looking for any advice how to do that in best way and not reinvent wheel.

I found good lib for this RNCryptor, but looks like this aes is not supported there.

Also I test this approach, but looks like this is not CTR.

EDIT


I used zpproach from @zaph

NSData *result = [NSData cryptData:dataStr
                         operation:kCCEncrypt
                              mode:kCCModeCTR
                         algorithm:kCCAlgorithmAES128
                           padding:ccNoPadding
                         keyLength:kCCKeySizeAES128
                                iv:ivHex
                               key:keyHex
                             error:&error];

but receive CCCryptorCreate status: -4305

Just found in sources

@constant kCCUnimplemented Function not implemented for the current algorithm.

Link


Solution

  • You need to use CommonCrypto but not the one-shot CCCrypt version, but instead the full CCCryptorCreateWithMode, CCCryptorUpdate, CCCryptorFinal and CCCryptorRelease with mode kCCModeCTR version.

    Here is sample code I have, it may not fit your needs and you will have to decide on the counter (IV) form.

    #import <CommonCrypto/CommonCrypto.h>
    
    + (NSData *)cryptData:(NSData *)dataIn
                operation:(CCOperation)operation  // kCC Encrypt, Decrypt
                     mode:(CCMode)mode            // kCCMode ECB, CBC, CFB, CTR, OFB, RC4, CFB8
                algorithm:(CCAlgorithm)algorithm  // CCAlgorithm AES DES, 3DES, CAST, RC4, RC2, Blowfish
                  padding:(CCPadding)padding      // cc NoPadding, PKCS7Padding
                keyLength:(size_t)keyLength       // kCCKeySizeAES 128, 192, 256
                       iv:(NSData *)iv            // CBC, CFB, CFB8, OFB, CTR
                      key:(NSData *)key
                    error:(NSError **)error
    {
        if (key.length != keyLength) {
            NSLog(@"CCCryptorArgument key.length: %lu != keyLength: %zu", (unsigned long)key.length, keyLength);
            if (error) {
                *error = [NSError errorWithDomain:@"kArgumentError key length" code:key.length userInfo:nil];
            }
            return nil;
        }
    
        size_t dataOutMoved = 0;
        size_t dataOutMovedTotal = 0;
        CCCryptorStatus ccStatus = 0;
        CCCryptorRef cryptor = NULL;
    
        ccStatus = CCCryptorCreateWithMode(operation, mode, algorithm,
                                           padding,
                                           iv.bytes, key.bytes,
                                           keyLength,
                                           NULL, 0, 0, // tweak XTS mode, numRounds
                                           kCCModeOptionCTR_BE, // CCModeOptions
                                           &cryptor);
    
        if (cryptor == 0 || ccStatus != kCCSuccess) {
            NSLog(@"CCCryptorCreate status: %d", ccStatus);
            if (error) {
                *error = [NSError errorWithDomain:@"kCreateError" code:ccStatus userInfo:nil];
            }
            CCCryptorRelease(cryptor);
            return nil;
        }
    
        size_t dataOutLength = CCCryptorGetOutputLength(cryptor, dataIn.length, true);
        NSMutableData *dataOut = [NSMutableData dataWithLength:dataOutLength];
        char *dataOutPointer = (char *)dataOut.mutableBytes;
    
        ccStatus = CCCryptorUpdate(cryptor,
                                   dataIn.bytes, dataIn.length,
                                   dataOutPointer, dataOutLength,
                                   &dataOutMoved);
        dataOutMovedTotal += dataOutMoved;
    
        if (ccStatus != kCCSuccess) {
            NSLog(@"CCCryptorUpdate status: %d", ccStatus);
            if (error) {
                *error = [NSError errorWithDomain:@"kUpdateError" code:ccStatus userInfo:nil];
            }
            CCCryptorRelease(cryptor);
            return nil;
        }
    
        ccStatus = CCCryptorFinal(cryptor,
                                  dataOutPointer + dataOutMoved, dataOutLength - dataOutMoved,
                                  &dataOutMoved);
        if (ccStatus != kCCSuccess) {
            NSLog(@"CCCryptorFinal status: %d", ccStatus);
            if (error) {
                *error = [NSError errorWithDomain:@"kFinalError" code:ccStatus userInfo:nil];
            }
            CCCryptorRelease(cryptor);
            return nil;
        }
    
        CCCryptorRelease(cryptor);
    
        dataOutMovedTotal += dataOutMoved;
        dataOut.length = dataOutMovedTotal;
    
        return dataOut;
    }
    

    Sample invocation:

    NSData *dataIn  = [@"DataInDataInData" dataUsingEncoding: NSUTF8StringEncoding];
    NSData *key     = [@"KeyKeyKeyKeyKeyK" dataUsingEncoding: NSUTF8StringEncoding];
    NSData *counter = [@"CounterCounterCo" dataUsingEncoding: NSUTF8StringEncoding];
    NSError *error;
    NSData *encrpted = [Crypto
                        cryptData:dataIn
                        operation:kCCEncrypt
                        mode:kCCModeCTR
                        algorithm:kCCAlgorithmAES
                        padding:ccNoPadding
                        keyLength:kCCKeySizeAES128
                        iv:counter
                        key:key
                        error:&error];
    NSLog(@"encrypted: %@", encrpted);
    

    Output: encrypted: 064e8073 76973eba 3192474f 9831db34