【问题标题】:AES Encryption CryptLib in iOS 13 not workingiOS 13 中的 AES 加密 CryptLib 不起作用
【发布时间】:2020-01-25 16:18:14
【问题描述】:

我的应用程序使用 AES 256 加密来加密字符串。之前使用的相同代码会产生不同的结果。这个问题在 iOS 13 发布时就开始了。而且它只发生在交付到商店或使用 Xcode 11 构建的应用程序中。

这是用于加密的代码:


- (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];  
    }  
}

##

我想知道代码路径中的某些内容在其工作方式上是否发生了变化。调用进行加密的方法是“encryptPlainTextWith”。提前致谢。

【问题讨论】:

  • 当你在这里说“CryptLib”时,我相信你的意思是 CommonCrypto,对吗?
  • 我会看一下 libSodium,与 CommonCrypto 相比,它非常易于使用。也就是说,CryptoKit 在 iOS 13 中让事情变得更好

标签: objective-c encryption aes ios13 xcode11


【解决方案1】:

内部:

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

我换了

NSString *hash=[out description];

NSString *hash=[out debugDescription];

一切都恢复了正常。干杯快乐编码。

@Rob Napier 的替代解决方案

创建单独的函数将 NSData 转换为 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];
}

在那之后:

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

我换了

NSString *hash=[out description];

NSString *hash = [self hex:out];

【讨论】:

  • 这依赖于debugDescription 的未记录行为,它可能会以与依赖description 完全相同的方式破坏。请参阅stackoverflow.com/questions/16521164/…(或搜索“将 nsdata 转换为十六进制”)以获得正确的实现。
  • @RobNapier 将 nsdata 转换为十六进制对我来说也可以正常工作,我使用您的链接进行了测试。现在我们有 2 个解决方案。谢谢你的建议。
【解决方案2】:

我怀疑您的密钥长度超过 32 个 UTF-8 字节。在这种情况下,此代码不正确。您的 patchNeeded 条件基本上是在创建一个垃圾键。如果这个函数返回 false,buffer 的内容不会被承诺,但是你依赖它们。

没有安全的方法来截断你获得的密钥,所以我不确定你想要什么行为。这取决于您传递的字符串类型。

如果iv 短于 16 个 UTF-8 字节,则此代码也不正确。您最终会从堆栈中包含随机值。该部分可以通过以下方式修复:

bzero(ivPointer, sizeof(ivPointer));

但如果您之前的版本依赖于随机值,这仍然会有所不同。

假设您需要匹配旧行为,最好的调试方法是在调试器中运行您以前的版本,看看 keyPointerivPointer 最终会是什么。

(请注意,这种创建密钥的方法非常不安全。它极大地缩小了 AES 密钥空间。多少取决于您传递的字符串类型,但这很戏剧化。您也不应该重复使用相同的密钥+iv在使用 CBC 时将两条消息组合在一起,这看起来可能是这样。如果可能,我建议移至正确的 AES 实现。您可以查看RNCryptor 以了解如何执行此操作的示例,或者如果您直接使用 RNCryptor喜欢。)

【讨论】:

  • 感谢您的回答,我找到了解决方案,效果很好。
猜你喜欢
  • 2020-01-31
  • 2017-09-26
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 2015-07-19
  • 1970-01-01
相关资源
最近更新 更多