Search code examples
objective-cencryptionaesios13xcode11

AES Encryption CryptLib in iOS 13 not working


My application uses AES 256 encryption to encrypt a string. The same code that was used before is generating a different result. This problem started when iOS 13 was released. And it happens only to applications that are shipped to the store or built with Xcode 11.

Here is the code used for the encryption:


- (NSData *)encrypt:(NSData *)plainText key:(NSString *)key  iv:(NSString *)iv {  
    char keyPointer[kCCKeySizeAES256+2],// room for terminator (unused) ref: https://devforums.apple.com/message/876053#876053  
    ivPointer[kCCBlockSizeAES128+2];  
    BOOL patchNeeded;  
    bzero(keyPointer, sizeof(keyPointer)); // fill with zeroes for padding  

    patchNeeded= ([key length] > kCCKeySizeAES256+1);  
    if(patchNeeded)  
    {  
        NSLog(@"Key length is longer %lu", (unsigned long)[[self md5:key] length]);  
        key = [key substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)  
    }  

    //NSLog(@"md5 :%@", key);  
    [key getCString:keyPointer maxLength:sizeof(keyPointer) encoding:NSUTF8StringEncoding];  
    [iv getCString:ivPointer maxLength:sizeof(ivPointer) encoding:NSUTF8StringEncoding];  

    if (patchNeeded) {  
        keyPointer[0] = '\0';  // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256  
    }  

    NSUInteger dataLength = [plainText length];  

    //see https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CCryptorCreateFromData.3cc.html  
    // For block ciphers, the output size will always be less than or equal to the input size plus the size of one block.  
    size_t buffSize = dataLength + kCCBlockSizeAES128;  
    void *buff = malloc(buffSize);  

    size_t numBytesEncrypted = 0;  
    //refer to http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h  
    //for details on this function  
    //Stateless, one-shot encrypt or decrypt operation.  
    CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */  
                                     kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */  
                                     kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */  
                                     keyPointer, kCCKeySizeAES256, /* key and its length */  
                                     ivPointer, /* initialization vector - use random IV everytime */  
                                     [plainText bytes], [plainText length], /* input  */  
                                     buff, buffSize,/* data RETURNED here */  
                                     &numBytesEncrypted);  
    if (status == kCCSuccess) {  
        return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];  
    }  

    free(buff);  
    return nil;  
}  


- (NSString *) encryptPlainTextWith:(NSString *)plainText key:(NSString *)key iv:(NSString *)iv {  
    return [[[[CryptLib alloc] init] encrypt:[plainText dataUsingEncoding:NSUTF8StringEncoding] key:[[CryptLib alloc] sha256:key length:32] iv:iv] base64EncodedStringWithOptions:0];  
} 
/** 

* This function computes the SHA256 hash of input string 
* @param key input text whose SHA256 hash has to be computed 
* @param length length of the text to be returned 
* @return returns SHA256 hash of input text 
*/  
- (NSString*) sha256:(NSString *)key length:(NSInteger) length{  
    const char *s=[key cStringUsingEncoding:NSASCIIStringEncoding];  
    NSData *keyData=[NSData dataWithBytes:s length:strlen(s)];  

    uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0};  
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);  
    NSData *out=[NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];  
    NSString *hash=[out description];  
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];  
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];  
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];  

    if(length > [hash length])  
    {  
        return  hash;  
    }  
    else  
    {  
        return [hash substringToIndex:length];  
    }  
}

##

I would like to know if something in the code path has changed in the way it works. The method called to do the encryptions is "encryptPlainTextWith". Thanks in advance.


Solution

  • Inside:

    - (NSString*) sha256:(NSString *)key length:(NSInteger) length
    

    I replaced

    NSString *hash=[out description];
    

    To

    NSString *hash=[out debugDescription];
    

    And everything got back to normal. Cheers Happy coding.

    Alternative Solution as per @Rob Napier

    create separate function for converting NSData to Hex

    #pragma mark - String Conversion
    -(NSString*)hex:(NSData*)data{
         NSMutableData *result = [NSMutableData dataWithLength:2*data.length];
         unsigned const char* src = data.bytes;
         unsigned char* dst = result.mutableBytes;
         unsigned char t0, t1;
    
         for (int i = 0; i < data.length; i ++ ) {
              t0 = src[i] >> 4;
              t1 = src[i] & 0x0F;
    
              dst[i*2] = 48 + t0 + (t0 / 10) * 39;
              dst[i*2+1] = 48 + t1 + (t1 / 10) * 39;
         }
    
         return [[NSString alloc] initWithData:result encoding:NSASCIIStringEncoding];
    }
    

    After that Inside:

    - (NSString*) sha256:(NSString *)key length:(NSInteger) length
    

    I replaced

    NSString *hash=[out description];
    

    To

    NSString *hash = [self hex:out];