iPhone 上 NSString 的 AES 加密
-
05-07-2019 - |
题
任何人都可以为我指明正确的方向,以便能够加密字符串,并返回带有加密数据的另一个字符串吗?(我一直在尝试使用 AES256 加密。)我想编写一种需要两个 NSString 实例的方法,一个是要加密的消息,另一个是用于加密它的“密码” - 我怀疑我必须生成加密密钥与密码,如果密码与加密数据一起提供,则可以反转。然后该方法应该返回一个从加密数据创建的 NSString。
我已经尝试过详细的技术 这篇文章的第一条评论, ,但到目前为止我还没有运气。苹果 加密练习 确实有一些东西,但我无法理解它......我看过很多参考资料 CCC加密, ,但在我使用过的每种情况下都失败了。
我还必须能够解密加密的字符串,但我希望这像 kCCEncrypt/kCCDecrypt 一样简单。
解决方案
由于您尚未发布任何代码,因此很难确切地知道您遇到的问题。但是,您链接到的博客文章似乎确实工作得很好......除了每次调用 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上Core OS的一部分。 10.4和10.5都有 / usr / include / CommonCrypto
,虽然10.5有 CCCryptor.3cc
的手册页而10.4没有,所以YMMV。
编辑:有关使用Base64编码表示加密数据字节的信息,请参阅此后续问题使用安全,无损转换作为字符串(如果需要)。
其他提示
我已经整理了 NSData 和 NSString 的类别集合,其中使用了在 杰夫·拉马什的博客 和 一些提示 作者: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] );
在这里获取完整的源代码:
感谢所有有用的提示!
——迈克尔
@owlstead,关于您对“给定答案之一的加密安全变体”的请求,请参阅 RNCryptor 。它的设计完全符合您的要求(并且是为了响应此处列出的代码的问题而构建的。)
RNCryptor使用PBKDF2与salt,提供随机IV,并附加HMAC(也是从PBKDF2生成的,具有自己的盐。它支持同步和异步操作。
我等待@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];
}