iOS 中的 AES256 NSString 加密

Posted

技术标签:

【中文标题】iOS 中的 AES256 NSString 加密【英文标题】:AES256 NSString Encryption in iOS 【发布时间】:2012-01-07 10:23:36 【问题描述】:

我的应用使用aes 256-Bit Encryption 使用另一个 NSString(关键字)加密和解密(或应该)一个 NSString(要加密/解密的文本)。当我运行我的项目并运行加密方法时,没有任何内容被加密,文本字段只会自行清除。这是我的代码:

-(void)EncryptText 
    //Declare Keyword and Text
    NSString *plainText = DataBox.text;
    NSString *keyword = Keyword.text;

    //Convert NSString to NSData
    NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    //Encrypt the Data
    NSData *encryptedData = [plainData AESEncryptWithPassphrase:keyword];

    //Convert the NSData back to NSString
    NSString* cypherText = [[NSString alloc] initWithData:encryptedData encoding:NSUTF8StringEncoding];

    //Place the encrypted sting inside the Data Box
    NSLog(@"Cipher Text: %@", cypherText);

头文件可点击此链接下载:ZIP File containing AES Implementation

有人告诉我,我需要使用我的字符串的 Base-64 编码来获得任何结果。如果这是真的,那我该怎么做呢?

我还被告知 ios 5 中的加密发生了变化,我的应用程序是 iOS 5+ 专用应用程序。如果这是真的,那么我必须做些什么才能使这种加密在 iOS 5 上工作,或者我在哪里可以找到另一个适用于 NSString 的 AES 256 位实现。

为什么这段代码没有产生结果?

【问题讨论】:

【参考方案1】:

编辑:下面的链接指的是较旧的实现。最新版本名为RNCryptor。

您的代码未使用 iOS 的内置 AES 实现。它有自己的自定义实现。 AESEncryptWithPassphrase: 也错误地生成了密钥,丢弃了密码中的大部分熵。

在 iOS 上,您应该为 AES 使用 CCCrypt*() 函数。您还应该确保您了解加密和解密例程中发生的情况。编写看起来正确的加密代码非常容易(因为您无法通过检查读取输出),但非常不安全。

请参阅Properly encrypting with AES with CommonCrypto 以了解上述实现的问题以及如何在 iOS 上正确使用 AES。请注意,iOS 5 现在有CCKeyDerivationPBKDF 可用。

在加密之前不需要对字符串进行 Base-64 编码。 Base-64 编码用于需要将二进制数据转换为可以通过电子邮件或其他控制字符存在问题的地方轻松发送的形式的情况。它将 8 位二进制数据转换为 7 位 ASCII 数据。这在这里没有必要或有用。


编辑:仔细阅读有关如何使用此代码的说明至关重要。简单地剪切和粘贴安全代码并希望它有效是危险的。也就是说,RNCryptManager 的完整源代码可作为iOS 5 Programming Pushing the Limits 的第 11 章示例代码的一部分获得,并且可能会有所帮助[编辑:这是旧代码;我现在推荐 RNCryptor,链接在答案的顶部]。这本书(尽管网站上说了什么,但应该会在下周出版)包含关于如何使用此代码的更长时间的讨论,包括如何提高性能和处理非常大的数据集。

【讨论】:

谢谢罗伯!这很有帮助! robnapier.net/blog/aes-commoncrypto-564 处显示的代码会去哪里?它不会进入自己的类,因为没有什么可以进入头文件和实现,所以它会进入我的方法所在的同一个 .m 文件吗? 我通常把它放在一个名为RNCryptManager 的类中,但你可以把它放在任何地方。代码也可以简单地转换为函数而不是类方法。 嗯...好吧,当我这样做时,我将所有代码放入 RNCryptManager.m,我收到 3 个错误,涉及“选择器的未知类方法:”随机、盐或AES 密码 您是否创建了一个 @interface 块来定义相关方法?另请参阅答案底部的上述编辑。它包括一个完整的 RNCryptManager 类示例。【参考方案2】:

具有类别的 NSData 适合 AES 加密,我没有检查 zip 文件,但这应该适合你;

#import <CommonCrypto/CommonCryptor.h>
@implementation NSData (AESAdditions)
- (NSData*)AES256EncryptWithKey:(NSString*)key 
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess)
    
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    

    free(buffer); //free the buffer;
    return nil;


- (NSData*)AES256DecryptWithKey:(NSString*)key 
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesDecrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess)
    
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    

    free(buffer); //free the buffer;
    return nil;

@end

使用它的包装函数,如 ;

- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key 
        return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];


- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key 
        return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
                                      encoding:NSUTF8StringEncoding] autorelease];

【讨论】:

请注意,此实现非常不安全,因为它丢弃了大部分密钥空间,没有 IV,也没有盐或密钥拉伸。请参阅robnapier.net/blog/aes-commoncrypto-564,了解为什么要避免使用这段经常复制的代码。 @tylerdurden 您应该检查密钥的长度,因为如果 key.length > (kCCKeySizeAES256 + 1) 并且密码器将使用 32 '\0',“getCString:maxlength:encoding” 将不会执行任何操作作为它的关键。很危险。

以上是关于iOS 中的 AES256 NSString 加密的主要内容,如果未能解决你的问题,请参考以下文章

iOS之AES加密解密

IOS AES加密之ECB128模式

一些加密方法

iOSAES加密的实现

iOS AES256 解密

PHP 中的 AES-256 加密