我已经尝试过本文第一条评论中详细介绍的技术,但到目前为止我还没有运气。苹果的CryptoExercise肯定有一些东西,但是我听不懂...我已经看到很多CCCrypt的引用,但是在我用过的每种情况下都失败了。
我会还必须能够解密加密的字符串,但我希望它像kCCEncrypt / kCCDecrypt一样简单。
#1 楼
由于您尚未发布任何代码,因此很难确切地知道您遇到了哪些问题。但是,您链接到的博客文章的确运行得相当不错……除了每次调用CCCrypt()
时引起逗号错误的逗号以外。该文章的后续评论中包含此改编的代码,它对我有用,而且看起来更简单。如果您将其代码包含在NSData类别中,则可以编写如下代码:(注意:
printf()
调用仅用于说明数据在各个点上的状态-在实际的应用程序中,打印这样的内容是没有意义的值)。鉴于此代码,并且加密数据并不总是可以很好地转换为NSString的事实,编写两个包装方法可能更方便正向和反向中所需的功能... 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;
}
这绝对适用于Snow Leopard,并且@Boz报告CommonCrypto是Core OS的一部分。苹果手机。 10.4和10.5都有
/usr/include/CommonCrypto
,尽管10.5有CCCryptor.3cc
的手册页,而10.4没有手册页,所以YMMV。编辑:请参阅以下有关使用Base64编码表示的后续问题使用安全,无损的转换将加密的数据字节作为字符串(如果需要)。
评论
谢谢。 CommonCrypto是iPhone上核心操作系统的一部分,我也正在运行10.6。
–博兹
09年9月9日在18:46
我做了-1,因为引用的代码很危险地不安全。请看Rob Napier的答案。他的博客文章robnapier.net/aes-commoncrypto详细说明了这种做法不安全的原因。
– Erik Engheim
2014年5月29日在12:01
在我的情况下,此解决方案不起作用。我有一个要解码的字符串:U2FsdGVkX1 + MEhsbofUNj58m + 8tu9ifAKRiY / Zf8YIw =,我有密钥:3841b8485cd155d932a2d601b8cee2ec。我无法在您的解决方案中使用密钥解密字符串。谢谢
–乔治
2014年6月11日在16:13
此解决方案在El Capitan上使用XCode 7的Cocoa应用程序中不起作用。ARC禁止自动发布。
– Volomike
16年1月17日,0:59
@QuinnTaylor我可以编辑此答案,但想给您机会,以您认为合适的方式对其进行更改。我在这里修复了您的代码。另外,您可能要指出的是,没有经过修改的代码,它将无法编译。因此,我使用XCode7在El Capitan上的Cocoa应用程序上工作。现在,我想做的是弄清楚如何对这些数据进行Base64Encode / Base64Decode,以使其可传输而不被传输干扰,而不是返回原始数据。
– Volomike
16年1月17日在1:24
#2 楼
我收集了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
感谢所有有用的提示!
-迈克尔
评论
NSString * key = @“ YourEncryptionKey”; //应该由用户提供我们可以生成一个随机的安全256位密钥,而不是由用户提供吗。
–普拉纳夫(Pranav Jaiswal)
2012年4月24日9:45
Jeff LaMarche链接已断开
–提醒
18-2-26在21:38
@michael-您能在这个stackoverflow.com/questions/63632975/中指导我吗……谢谢
–钱德尼
8月31日5:41
#3 楼
@owlstead,关于您对“给定答案之一的加密安全变体”的请求,请参阅RNCryptor。它旨在完全满足您的要求(并针对此处列出的代码的问题而构建)。RNCryptor将PBKDF2与盐配合使用,提供随机IV并附加HMAC(也由PBKDF2带有自己的salt生成,它支持同步和异步操作。
评论
有趣的代码,也许值得。 PBKDF2的迭代计数是多少,您如何计算HMAC?我想只是加密的数据吗?在提供的文档中,我很难找到这一点。
–马滕·博德威斯(Maarten Bodewes)
2012年8月14日在22:38
有关详细信息,请参见“最佳实践安全性”。我建议在iOS上进行1万次迭代(在iPhone 4上约为80毫秒)。是的,比HMAC加密。今晚我可能会查看“数据格式”页面,以确保它在v2.0上是最新的(主要文档是最新的,但是我不记得是否修改了数据格式页面)。
–罗布·纳皮尔
2012年8月14日在22:48
嗯,是的,找到了文档中的回合数并查看了代码。我看到清理功能,并在那里分离了HMAC和加密密钥。如果时间允许,我明天会尝试更深入的研究。然后,我将分配分数。
–马滕·博德威斯(Maarten Bodewes)
2012年8月14日23:06
加密为NSData,并使用许多Base64编码器之一将其转换为字符串。没有数据到字符串编码器,就无法从字符串加密到字符串。
–罗布·纳皮尔
2012年10月7日17:40
@Jack在我的律师的意见下(他以极其丰富的措辞描述了我在出口合规法律方面的专业知识……),我不再提供有关出口合规法律的建议。您需要与您的律师讨论。
–罗布·纳皮尔
18年7月27日在13:08
#4 楼
我在@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];
}
评论
注意:1.进行填充时(PKCS#7),解密时输出大小将小于输入大小。没有理由增加bufferSize,仅使用加密的数据大小即可。 2.而不是先分配缓冲区,然后dataWithBytesNoCopy只是分配一个带有dataWithLength的NSMutableData并将mutableBytes属性用作字节指针,然后通过设置其length属性来调整大小。 3.直接使用字符串进行加密是非常不安全的,应该使用派生密钥,例如PBKDF2创建的密钥。
– zaph
16年1月19日在1:15
@zaph,您可以在某个地方做一个pastebin / pastie,以便我可以看到更改吗?顺便说一句,在上面的代码中,我只是改编了我从奎因·泰勒(Quinn Taylor)看到的代码以使其工作。我仍在继续学习这项业务,您的意见对我非常有用。
– Volomike
16年1月19日在4:14
看到这样的答案,它甚至具有最小的错误处理,并且可以处理加密和解密。无需在解密时扩展缓冲区,如果只有很少的收获,则无需专门处理的代码就更少了。如果需要使用null扩展键(不应该这样做),只需创建一个可变版本的键并设置长度即可:keyData.length = kCCKeySizeAES256;。
– zaph
16年1月19日,下午4:42
有关使用PBKDF2从字符串创建密钥的信息,请参见此SO答案。
– zaph
16 Jan 19'5:41
@Volomike如果使用此功能,那么我应该在iTunes-Connect上选择“导出合规信息”(YES)吗?
–杰克
18年7月27日在6:50
#5 楼
Please use the below mentioned URL to encrypt string using AES excryption with
key and IV values.
https://github.com/muneebahmad/AESiOSObjC
评论
请注意,我已经赏识了Rob Napier提供的安全版本的答案。