AES Encryption for an NSString on the iPhone
有人能给我指出正确的方向来加密一个字符串,用加密的数据返回另一个字符串吗?(我一直在尝试使用aes256加密。)我想写一个方法,它使用两个nsstring实例,一个是要加密的消息,另一个是要用"密码"加密的消息。我怀疑我必须用密码生成加密密钥,如果密码随加密数据一起提供,这种方法可以逆转。然后,该方法应返回从加密数据创建的nsstring。
我已经尝试过这篇文章第一条评论中详细介绍的技术,但到目前为止我还没有运气。苹果的密码练习当然有点道理,但我搞不懂…我见过很多关于cccrypt的引用,但在我使用过的每个案例中都失败了。
我还必须能够解密加密的字符串,但我希望这和kccencrypt/kccdecrypt一样简单。
由于您没有发布任何代码,所以很难确切知道您遇到了哪些问题。然而,你链接到的博客帖子似乎工作得相当不错…除了对
稍后对这篇文章的评论中包含了这个适用于我的代码,看起来更直接一些。如果将它们的代码包含在nsdata类别中,则可以这样编写:(注意:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 ", [[cipher description] UTF8String]); plain = [cipher AES256DecryptWithKey:key]; printf("%s ", [[plain description] UTF8String]); printf("%s ", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]); [pool drain]; return 0; } |
考虑到这段代码,加上加密数据并不总是能很好地转换成nsstring,编写两种方法来包装您所需的功能(正向和反向)可能会更方便…
1 2 3 4 5 6 7 8 | - (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]; } |
这绝对适用于雪豹,@boz报告说CommonCrypto是iPhone核心操作系统的一部分。10.4和10.5都有
编辑:请参阅下面的问题:使用base64编码将加密数据字节表示为使用安全无损转换的字符串(如果需要)。
我收集了一组NSdata和NSstring的类别,它们使用了Jeff Lamarche的博客中的解决方案,以及Quinn Taylor在Stack Overflow中给出的一些提示。
它使用类别扩展nsdata以提供aes256加密,还提供nsstring到base64的扩展,将加密数据安全编码到字符串。
下面是一个用于加密字符串的示例:
1 2 3 4 5 6 7 8 9 | 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
感谢您提供的所有有用提示!
——米迦勒
@关于您对"给定答案之一的密码安全变体"的请求,请参阅rncryptor。它被设计为完全按照您的请求执行(并且是为响应这里列出的代码的问题而构建的)。
RNCryptor使用含盐的pbkdf2,提供随机的IV,并附加HMAC(也由pbkdf2生成,带有自己的盐)。它支持同步和异步操作。
我在@quinntaylor上等待了一段时间更新他的答案,但是因为他没有更新,所以这里的答案更清晰,并且可以加载到xcode7(也许更大)。我在一个Cocoa应用程序中使用过这个,但是它也可以在iOS应用程序中正常工作。没有弧错误。
粘贴到appdelegate.m或appdelegate.mm文件中的任何@implementation节之前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #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.m m或appdelegate.m文件中选择了@implementation appdelegate。
1 2 3 4 5 6 7 8 9 | - (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]; } |