objective-c iPhone 上 NSString 的 AES 加密
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1400246/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AES Encryption for an NSString on the iPhone
提问by Boz
Can anybody point me in the right direction to be able to encrypt a string, returning another string with the encrypted data? (I've been trying with AES256 encryption.) I want to write a method which takes two NSString instances, one being the message to encrypt and the other being a 'passcode' to encrypt it with - I suspect I'd have to generate the encryption key with the passcode, in a way that can be reversed if the passcode is supplied with the encrypted data. The method should then return an NSString created from the encrypted data.
任何人都可以指出我正确的方向来加密一个字符串,返回另一个带有加密数据的字符串吗?(我一直在尝试使用 AES256 加密。)我想编写一个方法,它需要两个 NSString 实例,一个是要加密的消息,另一个是用来加密它的“密码”-我怀疑我必须生成带有密码的加密密钥,如果密码与加密数据一起提供,则可以反转。然后该方法应返回从加密数据创建的 NSString。
I've tried the technique detailed in the first comment on this post, but I've had no luck so far. Apple's CryptoExercisecertainly has something, but I can't make sense of it... I've seen lots of references to CCCrypt, but it's failed in every case I've used it.
我已经尝试了这篇文章的第一条评论中详述的技术,但到目前为止我还没有运气。Apple 的CryptoExercise肯定有一些东西,但我无法理解它......我已经看到很多对CCCrypt的引用,但在我使用它的每种情况下它都失败了。
I would also have to be able to decrypt an encrypted string, but I hope that's as simple as kCCEncrypt/kCCDecrypt.
我还必须能够解密加密的字符串,但我希望这就像 kCCEncrypt/kCCDecrypt 一样简单。
回答by Quinn Taylor
Since you haven't posted any code, it's difficult to know exactly which problems you're encountering. However, the blog post you link to does seem to work pretty decently... aside from the extra comma in each call to CCCrypt()which caused compile errors.
由于您还没有发布任何代码,因此很难确切地知道您遇到了哪些问题。但是,您链接到的博客文章似乎工作得相当不错……除了每个调用中的额外逗号CCCrypt()会导致编译错误。
A later comment on that post includes this adapted code, which works for me, and seems a bit more straightforward. If you include their code for the NSData category, you can write something like this: (Note: The printf()calls are only for demonstrating the state of the data at various points — in a real application, it wouldn't make sense to print such values.)
稍后对该帖子的评论包括此改编后的代码,它对我有用,而且看起来更简单一些。如果您将他们的代码包含在 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;
}
Given this code, and the fact that encrypted data will not always translate nicely into an NSString, it may be more convenient to write two methods that wrap the functionality you need, in forward and reverse...
鉴于此代码,以及加密数据并不总是很好地转换为 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];
}
This definitely works on Snow Leopard, and @Bozreports that CommonCrypto is part of the Core OS on the iPhone. Both 10.4 and 10.5 have /usr/include/CommonCrypto, although 10.5 has a man page for CCCryptor.3ccand 10.4 doesn't, so YMMV.
这绝对适用于雪豹,@Boz报告说 CommonCrypto 是 iPhone 核心操作系统的一部分。10.4 和 10.5 都有/usr/include/CommonCrypto,虽然 10.5 有一个手册页CCCryptor.3cc而 10.4 没有,所以 YMMV。
EDIT:See this follow-up questionon using Base64 encoding for representing encrypted data bytes as a string (if desired) using safe, lossless conversions.
编辑:请参阅有关使用 Base64 编码使用安全、无损转换将加密数据字节表示为字符串(如果需要)的后续问题。
回答by Michael Thiel
I have put together a collection of categories for NSData and NSString which uses solutions found on Jeff LaMarche's blogand some hintsby Quinn Taylor here on Stack Overflow.
我已经为 NSData 和 NSString 收集了一系列类别,它们使用了在Jeff LaMarche 的博客上找到的解决方案以及Quinn Taylor 在 Stack Overflow 上的一些提示。
It uses categories to extend NSData to provide AES256 encryption and also offers an extension of NSString to BASE64-encode encrypted data safely to strings.
它使用类别来扩展 NSData 以提供 AES256 加密,并且还提供了 NSString 的扩展,以将 BASE64 加密的数据安全地编码为字符串。
Here's an example to show the usage for encrypting strings:
下面是一个例子来展示加密字符串的用法:
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] );
Get the full source code here:
在此处获取完整源代码:
Thanks for all the helpful hints!
感谢所有有用的提示!
-- Michael
——迈克尔
回答by Rob Napier
@owlstead, regarding your request for "a cryptographically secure variant of one of the given answers," please see RNCryptor. It was designed to do exactly what you're requesting (and was built in response to the problems with the code listed here).
@owlstead,关于您对“给定答案之一的加密安全变体”的请求,请参阅RNCryptor。它旨在完全满足您的要求(并且是为响应此处列出的代码的问题而构建的)。
RNCryptor uses PBKDF2 with salt, provides a random IV, and attaches HMAC (also generated from PBKDF2 with its own salt. It support synchronous and asynchronous operation.
RNCryptor 使用带盐的 PBKDF2,提供随机 IV,并附加 HMAC(也是从带有自己的盐的 PBKDF2 生成的。它支持同步和异步操作。
回答by Volomike
I waited a bit on @QuinnTaylor to update his answer, but since he didn't, here's the answer a bit more clearly and in a way that it will load on XCode7 (and perhaps greater). I used this in a Cocoa application, but it likely will work okay with an iOS application as well. Has no ARC errors.
我在@QuinnTaylor 上等了一会儿来更新他的答案,但由于他没有,所以这里的答案更清楚一点,并且它会加载到 XCode7(也许更大)上。我在 Cocoa 应用程序中使用了它,但它可能也适用于 iOS 应用程序。没有 ARC 错误。
Paste before any @implementation section in your AppDelegate.m or AppDelegate.mm file.
在 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
Paste these two functions in the @implementation class you desire. In my case, I chose @implementation AppDelegate in my AppDelegate.mm or AppDelegate.m file.
将这两个函数粘贴到您想要的 @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];
}
回答by SURESH SANKE
Please use the below mentioned URL to encrypt string using AES excryption with
key and IV values.

