无法解密在iPhone上通过OpenSSL编码的数据

Dav*_*Nix 4 iphone encryption openssl cryptography ios

对我上一个问题的后续跟进: 如何从OpenSSL加密数据中获取初始化向量(iv)

我正在使用OpenSSL命令行实用程序来加密字符串,然后尝试<CommonCrypto/CommonCryptor.h>用来解密iPhone上的字符串.使用Dropbox SDK,将带有加密字符串的xml文件加载到iPhone上,我的应用程序尝试解析和解密此文件中的字符串.

这是openssl命令的一个例子:

printf %s "Hello" | openssl enc -aes-128-cbc -K 00ff349830193845af43984758690213 -iv 0 -base64
Run Code Online (Sandbox Code Playgroud)

上面的base 64字符串放在一个XML文件中,然后由app解析.

我正在使用Matt Gallagher的NSData来解码base64文本.我假设它正常工作; 我还没有找到一个测试它的好方法.(来源:http: //cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html).

这是解码加密字符串的方法.
在这种情况下,关键是NSString等于@"00ff349830193845af43984758690213".

+ (NSString *)string:(NSString *)encryptedString withAES128Key:(NSString *)key {

// decode base64, from Matt Gallagher's NSData category
NSData *b64DecodedData = [NSData dataFromBase64String:encryptedString];

NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];

// fyi, I plan to replace this later with a random iv
NSData *ivData = [@"00000000000000000000000000000000" dataUsingEncoding:NSUTF8StringEncoding];

// decrypt the string
NSData *decodedData = [self doCipher:b64DecodedData iv:ivData key:keyData context:kCCDecrypt];

NSString *unencryptedString = [[NSString alloc] initWithBytes:[decodedData bytes] length:[decodedData length] encoding:NSUTF8StringEncoding];

return [unencryptedString autorelease];
}
Run Code Online (Sandbox Code Playgroud)

这是执行实际解密的方法:(此方法的信用转到其他stackoverflow用户.)

+ (NSData *)doCipher:(NSData *)dataIn
              iv:(NSData *)iv
             key:(NSData *)symmetricKey
         context:(CCOperation)encryptOrDecrypt
{
CCCryptorStatus ccStatus   = kCCSuccess;
size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];

ccStatus = CCCrypt( encryptOrDecrypt,
                   kCCAlgorithmAES128,
                   kCCOptionPKCS7Padding,
                   [symmetricKey bytes], 
                   kCCKeySizeAES128,
                   iv,
                   dataIn.bytes,
                   dataIn.length,
                   dataOut.mutableBytes,
                   dataOut.length,
                   &cryptBytes);

// error occurs here, error -4304 kCCDecodeError
if (ccStatus != kCCSuccess) {
    // Handle error
    NSLog(@"CCCrypt status: %d", ccStatus);
}

dataOut.length = cryptBytes;

return dataOut;
}
Run Code Online (Sandbox Code Playgroud)

发生错误时,错误代码-4304kCCDecodeError因为ccStatus不等于kCCSuccess.

我觉得键和iv没有正确设置为NSData对象.OpenSSL要求key和iv为十六进制值,我已经完成并小心地将它们设置为128位.但是,我认为我在将这些字符串转换为NSData时缺少一些doCipher方法.

任何帮助是极大的赞赏!一整天都在玩弄这一天.

zap*_*aph 8

虽然iv处理不正确,但问题最少.

解码错误听起来像不正确的参数长度,因为任何随机的iv,键和数据都应该是有效的输入.(我的妻子同意并且她专业地做这件事.)在将它们转换为NSData之后检查密钥和数据长度等内容.请注意,使用不正确或不兼容的填充传递加密数据也会导致解码错误.

为Base64编写一个测试,你的iOS代码与openssl.

从更简单的测试中解决问题.

例如,删除base64直到您获得加密顶级工作.尝试简单数据,比如一个块长度为0,填充可能是个问题.尝试更简单的密钥,例如全0.您可以在Mac Terminal命令行上使用OPENSSL.

一旦基本加密工作,就会添加所需的功能.

对于来自命令行的openssl使用输入和输出文件,它们将处理二进制文件,因此您至少最初不会遇到这个障碍.这是一个示例:

(file_orig.txt contains: "1234567890123456")

openssl enc -e -aes-128-cbc -K 00ff349830193845af43984758690213 -p -iv 0 -nosalt -in file_orig.txt -out file_aes.txt
Run Code Online (Sandbox Code Playgroud)

它打印出它生成的密钥以及它使用的iv:

key=00ff349830193845af43984758690213
iv =00000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

然后,您可以在iOS方法中读取相同的数据文件.

这是一个使用openssl创建的文件的iOS方法:(
将密钥openssl输出放入文件key-hex-openssl.txt)

NSData *keyHexData = [@"00ff349830193845af43984758690213" dataUsingEncoding:NSUTF8StringEncoding];
NSData *testData   = [NSData dataWithContentsOfFile:@"yourDirectoryPath/file_aes.txt"];
NSData *clearData  = [NSData dataWithContentsOfFile:@"yourDirectoryPath/file_orig.txt"];

NSLog(@"keyHexData: %@", keyHexData);
NSLog(@"testData:   %@", testData);
NSLog(@"clearData:  %@", clearData);

unsigned char keyBytes[16];
unsigned char *hex = (uint8_t *)keyHexData.bytes;

char byte_chars[3] = {'\0','\0','\0'};
for (int i=0; i<16; i++) {
    byte_chars[0] = hex[i*2];
    byte_chars[1] = hex[(i*2)+1];
    keyBytes[i] = strtol(byte_chars, NULL, 16);
}
NSData *keyData = [NSData dataWithBytes:keyBytes length:16];
NSLog(@"keyData:    %@", keyData);

NSData *ivData = [NSData dataWithBytes:(char []){0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} length:16];
NSLog(@"ivData:     %@", ivData);

CCCryptorStatus ccStatus   = kCCSuccess;
size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
NSMutableData  *clearOut   = [NSMutableData dataWithLength:testData.length];

ccStatus = CCCrypt(kCCDecrypt,
                   kCCAlgorithmAES128,
                   kCCOptionPKCS7Padding,
                   keyData.bytes, 
                   kCCKeySizeAES128,
                   ivData.bytes,
                   testData.bytes,
                   testData.length,
                   clearOut.mutableBytes,
                   clearOut.length,
                   &cryptBytes);

if (ccStatus != kCCSuccess) {
    NSLog(@"CCCrypt status: %d", ccStatus);
}

clearOut.length = cryptBytes;
NSLog(@"clearOut:   %@", clearOut);
keyHexData: <41393641 34344436 31343245 43463546 33444339 30303038 46453941 34383838>
testData:   <86a8b306 0f33db02 01e77e66 af5bcb3a>
clearData:  <31323334 35363738 39303132 33343536>
keyData:    <a96a44d6 142ecf5f 3dc90008 fe9a4888>
ivData:     <00000000 00000000 00000000 00000000>
clearOut:   <31323334 35363738 39303132 33343536>
Run Code Online (Sandbox Code Playgroud)

请注意,clearData已恢复为clearOut

这演示了使用openssl加密和使用CommonCrypto进行解密.

需要克服的问题:
1)需要添加Base64

这是完成所需加密的起点.

  • 有趣的是,有多少人只使用CommonCrypto并不真正知道发送到CCCrypt的密钥应该是原始字节.谢谢你的回答. (2认同)