如何在Java和Objective-C(iPhone)之间使AES加密相同?

Sim*_*Lee 25 java iphone encryption aes objective-c

我正在加密objective-c中的字符串,并使用AES加密Java中的相同字符串,并且看到一些奇怪的问题.结果的第一部分与某个点匹配,但后来却不同,因此当我将Java的结果解码到iPhone上时,它无法对其进行解密.

我正在使用一个源代码字符串"现在然后这是什么废话.你知道吗?" 使用"1234567890123456"的键

加密的objective-c代码如下:注意:它是NSData类别,因此假设在NSData对象上调用该方法,因此'self'包含要加密的字节数据.

   - (NSData *)AESEncryptWithKey:(NSString *)key {
 char keyPtr[kCCKeySizeAES128+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, kCCKeySizeAES128,
            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;
}
Run Code Online (Sandbox Code Playgroud)

而java加密代码是......

public byte[] encryptData(byte[] data, String key) {
    byte[] encrypted = null;

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    byte[] keyBytes = key.getBytes();

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);

        encrypted = new byte[cipher.getOutputSize(data.length)];
        int ctLength = cipher.update(data, 0, data.length, encrypted, 0);
        ctLength += cipher.doFinal(encrypted, ctLength);
    } catch (Exception e) {
        logger.log(Level.SEVERE, e.getMessage());
    } finally {
        return encrypted;
    }
}
Run Code Online (Sandbox Code Playgroud)

objective-c代码的十六进制输出是 -

7a68ea36 8288c73d f7c45d8d 22432577 9693920a 4fae38b2 2e4bdcef 9aeb8afe 69394f3e 1eb62fa7 74da2b5c 8d7b3c89 a295d306 f1f90349 6899ac34 63a6efa0
Run Code Online (Sandbox Code Playgroud)

和java输出是 -

7a68ea36 8288c73d f7c45d8d 22432577 e66b32f9 772b6679 d7c0cb69 037b8740 883f8211 748229f4 723984beb 50b5aea1 f17594c9 fad2d05e e0926805 572156d
Run Code Online (Sandbox Code Playgroud)

正如你所看到的一切都很好 -

7a68ea36 8288c73d f7c45d8d 22432577
Run Code Online (Sandbox Code Playgroud)

我猜我有一些设置不同,但无法解决什么,我尝试在Java端的ECB和CBC之间进行更改,但它没有任何效果.

任何人都可以帮忙!?请....

Ale*_*ing 18

由于CCCrypt采用IV,它是否不使用链接块密码方法(如CBC)?这与你看到的一致:第一个块是相同的,但在第二个块中,Java版本应用原始密钥进行加密,但OSX版本似乎使用其他东西.

编辑:

这里我看到了一个例子.好像你需要将kCCOptionECBMode传递给CCCrypt:

ccStatus = CCCrypt(encryptOrDecrypt,
        kCCAlgorithm3DES,
        kCCOptionECBMode, <-- this could help
        vkey, //"123456789012345678901234", //key
        kCCKeySize3DES,
        nil, //"init Vec", //iv,
        vplainText, //"Your Name", //plainText,
        plainTextBufferSize,
        (void *)bufferPtr,
        bufferPtrSize,
        &movedBytes);
Run Code Online (Sandbox Code Playgroud)

编辑2:

我玩了一些命令行,看看哪一个是正确的.我以为我可以贡献它:

$ echo "Now then and what is this nonsense all about. Do you know?" | openssl enc -aes-128-ecb -K $(echo 1234567890123456 | xxd -p) -iv 0 | xxd 
0000000: 7a68 ea36 8288 c73d f7c4 5d8d 2243 2577  zh.6...=..]."C%w
0000010: e66b 32f9 772b 6679 d7c0 cb69 037b 8740  .k2.w+fy...i.{.@
0000020: 883f 8211 7482 29f4 7239 84be b50b 5aea  .?..t.).r9....Z.
0000030: eaa7 519b 65e8 fa26 a1bb de52 083b 478f  ..Q.e..&...R.;G.
Run Code Online (Sandbox Code Playgroud)


小智 11

我花了几周时间解密一个base64编码的AES256加密字符串.加密是由CCCrypt(Objective-C)在iPad上完成的.解密将在Java中完成(使用Bouncy Castle).

在这个过程中,我终于成功并学到了很多东西.加密代码与上面完全相同(我想它来自iPhone开发人员文档中的Objective-C示例).

CCCrypt()文档没有提到的是它默认使用CBC模式(如果你没有指定像kCCOptionECBMode这样的选项).它确实提到IV,如果没有指定,默认为全零(因此IV将是0x00的字节数组,长度为16个成员).

使用这两条信息,您可以在Java和OSx/iphone/ipad(CCCrypt)上使用CBC创建功能相同的加密模块(并避免使用安全性较低的ECB).

Cipher init函数将IV字节数组作为第三个参数:

cipher.init(Cipher.ENCRYPT_MODE, keySpec, IV).
Run Code Online (Sandbox Code Playgroud)


Sim*_*Lee 9

对于其他需要此功能的人来说,disown绝对是现货......在objective-c中创建隐藏的修订调用如下(注意你需要ECB模式和填充)...

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
Run Code Online (Sandbox Code Playgroud)