谁能指出我正确的方向,以便能够加密一个字符串,并用加密的数据返回另一个字符串? (我一直在尝试使用AES256加密。)我想编写一个方法,该方法使用两个NSString实例,一个实例是要加密的消息,另一个是要使用其加密的“密码”-我怀疑我必须生成如果密码随加密数据一起提供,则可以用相反的方式将密码和密码一起加密。然后,该方法应返回从加密数据创建的NSString。

我已经尝试过本文第一条评论中详细介绍的技术,但到目前为止我还没有运气。苹果的CryptoExercise肯定有一些东西,但是我听不懂...我已经看到很多CCCrypt的引用,但是在我用过的每种情况下都失败了。

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

评论

请注意,我已经赏识了Rob Napier提供的安全版本的答案。

#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