125

谁能指出我正确的方向来加密一个字符串,返回另一个带有加密数据的字符串?(我一直在尝试使用 AES256 加密。)我想编写一个方法,它需要两个 NSString 实例,一个是要加密的消息,另一个是要加密的“密码”——我怀疑我必须生成带有密码的加密密钥,如果密码与加密数据一起提供,则可以反转。然后该方法应返回从加密数据创建的 NSString。

我已经尝试过这篇文章第一条评论中详述的技术,但到目前为止我还没有运气。Apple 的CryptoExercise肯定有一些东西,但我无法理解它......我已经看到很多对CCCrypt的引用,但在我使用它的每种情况下它都失败了。

我还必须能够解密加密的字符串,但我希望它像 kCCEncrypt/kCCDecrypt 一样简单。

4

5 回答 5

128

由于您尚未发布任何代码,因此很难确切知道您遇到了哪些问题。但是,您链接到的博客文章似乎工作得相当不错……除了CCCrypt()导致编译错误的每次调用中的额外逗号之外。

后来对该帖子的评论包括这个改编代码,它对我有用,而且看起来更简单一些。如果您将他们的代码包含在 NSData 类别中,您可以编写如下内容:(注意:这些printf()调用仅用于演示数据在各个点的状态——在实际应用程序中,打印这样的值是没有意义的.)

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString *key = @"my password";
    NSString *secret = @"text to encrypt";

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *cipher = [plain AES256EncryptWithKey:key];
    printf("%s\n", [[cipher description] UTF8String]);

    plain = [cipher AES256DecryptWithKey:key];
    printf("%s\n", [[plain description] UTF8String]);
    printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);

    [pool drain];
    return 0;
}

鉴于此代码,以及加密数据不会总是很好地转换为 NSString 的事实,编写两种方法来包装您需要的功能可能更方便,正向和反向......

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

这绝对适用于 Snow Leopard,@Boz报告说 CommonCrypto 是 iPhone 上核心操作系统的一部分。10.4 和 10.5 都有/usr/include/CommonCrypto,虽然 10.5 有手册页CCCryptor.3cc而 10.4 没有,所以 YMMV。


编辑:请参阅有关使用 Base64 编码将加密数据字节表示为使用安全、无损转换的字符串(如果需要)的后续问题。

于 2009-09-09T16:05:58.537 回答
46

我已经为 NSData 和 NSString 整理了一组类别,这些类别使用​​了Jeff LaMarche 博客上的解决方案以及Quinn Taylor 在 Stack Overflow 上的一些提示

它使用类别来扩展 NSData 以提供 AES256 加密,还提供 NSString 的扩展以 BASE64 安全地将加密数据编码为字符串。

这是一个显示加密字符串用法的示例:

NSString *plainString = @"This string will be encrypted";
NSString *key = @"YourEncryptionKey"; // should be provided by a user

NSLog( @"Original String: %@", plainString );

NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( @"Encrypted String: %@", encryptedString );

NSLog( @"Decrypted String: %@", [encryptedString AES256DecryptWithKey:key] );

在此处获取完整的源代码:

https://gist.github.com/838614

感谢所有有用的提示!

——迈克尔

于 2011-02-22T13:00:41.930 回答
35

@owlstead,关于您对“给定答案之一的加密安全变体”的请求,请参阅RNCryptor。它旨在完全按照您的要求进行(并且是针对此处列出的代码的问题而构建的)。

RNCryptor 使用带有 salt 的 PBKDF2,提供随机 IV,并附加 HMAC(也是从带有自己的 salt 的 PBKDF2 生成的。它支持同步和异步操作。

于 2012-08-14T19:44:33.277 回答
13

我在@QuinnTaylor 上等了一会儿来更新他的答案,但由于他没有,所以这里的答案更清楚一些,并且它会加载到 XCode7(也许更大)上。我在 Cocoa 应用程序中使用了它,但它可能也适用于 iOS 应用程序。没有 ARC 错误。

粘贴在 AppDelegate.m 或 AppDelegate.mm 文件中的任何 @implementation 部分之前。

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (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

将这两个函数粘贴到您想要的 @implementation 类中。就我而言,我在 AppDelegate.mm 或 AppDelegate.m 文件中选择了@implementation AppDelegate。

- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
    return [data base64EncodedStringWithOptions:kNilOptions];
}

- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
    return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
于 2016-01-18T18:20:15.840 回答
0
Please use the below mentioned URL to encrypt string using AES excryption with 
key and IV values.

https://github.com/muneebahmad/AESiOSObjC

于 2020-01-21T09:57:51.473 回答