【问题标题】:Unable to decrypt AES data using Obj-C that was encrypted using Java无法使用使用 Java 加密的 Obj-C 解密 AES 数据
【发布时间】:2017-12-19 22:44:55
【问题描述】:

我一直在尝试解密一些由服务器发送到我的应用程序的 AES 加密数据。

为了解决问题,我编写了一个小型 Java 程序来模拟服务器正在做什么。它使用 AES 加密一些测试数据,然后将其编码为 Base64:

AesCipherService cipherService  = new AesCipherService();
cipherService.setKeySize(128);

String stringKey = "2EE1F10212ADD4BE";
byte[] keyAsBytes =  stringKey.getBytes();

String text = "text to encrypt";
byte[] encryptedBytes    = cipherService.encrypt(text.getBytes(), keyAsBytes).getBytes();
String base64String      = Base64.encodeToString(encryptedBytes);
System.out.println(base64String);

// Reverse the process to check can retrieve "text to encrypt":
byte[] bytesToDecode = Base64.decode(base64String);
byte[] decryptedBytes = cipherService.decrypt(bytesToDecode, keyAsBytes).getBytes();         
String decryptedString = new String(decryptedBytes);   
System.out.println(decryptedString);

运行时输出如下:

R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4=

要加密的文本

这样我就可以成功加密数据,打印出来。然后,如果我将其解密,则会显示原始文本,因此这里一切正常。

现在这是我的 Obj-C 代码,我尝试在其中解密从 Java 代码加密的数据。我已从 NetBeans IDE 输出窗口复制/粘贴加密数据作为要解密的 obj-c 内容的源数据:

- (void) decryptData
{
    NSData* dataToDecrypt       = [[NSData alloc] initWithBase64EncodedString: @"R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4="  options: 0];
    NSString* key               = @"2EE1F10212ADD4BE";

    char keyPtr[kCCKeySizeAES128];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [dataToDecrypt length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          keyPtr,
                                          [dataToDecrypt bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        NSLog(@"Success");
        NSData* unencryptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        Byte *unencryptedAsBytes = (Byte*)malloc(unencryptedData.length);
        memcpy(unencryptedAsBytes, [unencryptedData  bytes], unencryptedData.length);
        NSString *decryptedString = [NSString stringWithUTF8String:[unencryptedData bytes]];
        NSLog(@"%@", decryptedString);
    }
}

运行时,状态为 kCCSuccess,numBytesDecrypted 为 32(与 dataLength 相同),但解密后的字符串不是“要加密的文本”,decryptedString 为 nil,如果我在 Xcode 的控制台中输入 unencryptedAsBytes,它会显示:

"\aY|\376\347cD*\320NC\x14\x91C\x88\301\341z\xaca\x11\371

知道这里有什么问题吗?

【问题讨论】:

  • 4. AesCipherService 记录在哪里?您是否使用密钥作为 IV,这是不安全的。 5. 也许IV是加密数据的前16个字节,这并不罕见。
  • @zaph AesCipherService 是 Apache 加密库 shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/crypto/… 的一部分。代码的 java 部分不是由我编写的,而是由服务器开发人员编写的,我正在尝试编写 Objective-C 部分来解密他们加密的内容。我在上面发布的代码是我以精简格式重新创建他们所做的工作,以尝试以更易于管理的方式重新创建问题。他们如上所述使用 AesCipherService ,即他们没有明确设置 IV 等,因此正在使用 AesCipherService 默认值。

标签: java ios objective-c encryption


【解决方案1】:

Java 加密代码生成一个随机 IV 并用它作为加密的前缀。为了解密,IV 从加密中分离出来。

十六进制:

key:       32454531463130323132414444344245  
iv:        479501A4FDF46235FD01ED87A0F6F646 (first 16 binary bytes of the full encryption)  
encrypted: B7E2E6B40963677469CD7ECDA217E40E (rest of binary bytes of the full encryption)  
decrypted: 7465787420746F20656E6372797074

代码:

NSData* fullEncrypted       = [[NSData alloc] initWithBase64EncodedString: @"R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4="  options: 0];
NSData *ivData = [fullEncrypted subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encryptedData = [fullEncrypted subdataWithRange:NSMakeRange(kCCBlockSizeAES128, fullEncrypted.length-kCCBlockSizeAES128)];
NSLog(@"ivData:          %@", ivData);
NSLog(@"encryptedData:   %@", encryptedData);

NSData *keyData = [@"2EE1F10212ADD4BE" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"keyData:         %@", keyData);

NSMutableData *unencryptedData = [NSMutableData dataWithLength:encryptedData.length];
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                      kCCAlgorithmAES,
                                      kCCOptionPKCS7Padding,
                                      keyData.bytes, keyData.length,
                                      ivData.bytes,
                                      encryptedData.bytes, encryptedData.length,
                                      unencryptedData.mutableBytes, unencryptedData.length,
                                      &numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
    NSLog(@"Success");

    unencryptedData.length = numBytesDecrypted;
    NSLog(@"unencryptedData: %@", unencryptedData);

    NSString *decryptedString = [[NSString alloc] initWithData:unencryptedData encoding:NSUTF8StringEncoding];
    NSLog(@"decryptedString: %@", decryptedString);
}

输出:

ivData:          479501a4 fdf46235 fd01ed87 a0f6f646  
encryptedData:   b7e2e6b4 09636774 69cd7ecd a217e40e  
keyData:         32454531 46313032 31324144 44344245  
Success  
unencryptedData: 74657874 20746f20 656e6372 79707400  
decryptedString: text to encrypt  

【讨论】:

  • 太棒了!太感谢你了,我已经被困在这个问题上好几天了。您如何确定随机 IV 被添加到加密数据中?
  • 因为这很常见,而且加密的数据比应有的长一个块。此外,ObjC 代码默认为 CBC 模式,并且需要 IV。当然,我首先对错误的编码进行了猜测。
  • 顺便说一句,这是一个整洁的AES converter,注意输出数据中的尾随01,即填充。
  • 感谢您的帮助,我真的很感激。
  • 您好,为什么在分配的 unencryptedData 的长度上加上 + kCCBlockSizeAES128?
猜你喜欢
  • 1970-01-01
  • 2011-03-06
  • 2015-10-22
  • 1970-01-01
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多