iPhone(Objective-c)和Java之间的AES区别
Posted
技术标签:
【中文标题】iPhone(Objective-c)和Java之间的AES区别【英文标题】:AES difference between iPhone (Objective-c) and Java 【发布时间】:2010-12-10 23:19:20 【问题描述】:我整天都在扯头发试图解决这个问题......
我有一个在 iPhone 上运行的 Objective-c 客户端,连接到 Java 服务器。 iPhone 正在使用 AES 加密数据,但我无法在服务器上对其进行解密。我正在使用已知的密码和消息(单个字符串)并在 iPhone 上生成字节数组,在 Java 服务器上使用相同的键和消息生成比较字节数组,但字节数组完全不同(因此不能在 Java 端进行解码)。
客户端正在使用具有以下设置的 CommonCrypto 库...
Data 是一个 NSData
,其中包含使用 dataUsingEncoding:NSASCIIStringEncoding
的单词“消息”
密钥是NSData
,再次使用上述编码保存短语“1234567891123456”。
算法是kCCAlgorithmAES128
选项是kCCOptionsPKCS7Padding
(我认为这相当于服务器上的ECB?!)
服务器正在使用以下代码...
byte[] key = "1234567891123456".getBytes();
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec k = new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal("message".getBytes());
但是 encryptedData 中的数据与 Objective-c 代码中生成的数据不匹配,字节数组完全不同。
谁能看出我做错了什么?我认为设置都是一样的... :(
更新 - 根据要求....好吧,就这样吧……
iPhone 客户端正在加密以下字符串“消息” 它使用密钥“1234567891123456” 它使用“1010101010101010”的初始化向量 它使用 AES128,具有 CBC 模式(据我所知)和 kCCOptionsPKCS7Padding 选项。
加密(base64编码)的结果是UHIYllDFAXl81ZM7OZPAuA==
服务器使用相同的密钥和初始化向量加密相同的字符串。 它使用以下 Cipher.getInstance("AES/CBC/PKCS5Padding");
加密(base64编码)的结果是ALBnFIHysLbvAxjvtNo9vQ==
谢谢。
更新 2 - 根据要求...这是 iPhone 代码....
NSData *toencrypt = [@"message" dataUsingEncoding:NSASCIIStringEncoding];
NSData *pass = [@"1234567891123456" dataUsingEncoding:NSASCIIStringEncoding];
NSData *iv = [@"1010101010101010" dataUsingEncoding:NSASCIIStringEncoding];
CCCryptorStatus status = kCCSuccess;
NSData *encrypted = [toencrypt dataEncryptedUsingAlgorithm:kCCAlgorithmAES128 key:pass initializationVector:iv options:kCCOptionPKCS7Padding error:&status];
NSString *text = [NSString base64StringFromData:encrypted length:[encrypted length]];
用于加密的 NSData 类别来自这里...
http://github.com/AlanQuatermain/aqtoolkit/tree/master/CommonCrypto/
顺便说一句,我检查了 toencrypt、pass 和 iv 中的字节数组,它们与服务器上的匹配。
【问题讨论】:
我已将服务器更改为按照建议使用 ECB,但仍然无法正常工作。顺便说一句,我确实注意到服务器使用 PKCS5 和客户端使用 PKCS7,但是客户端上没有 5 可用,服务器上没有 7 可用,显然它们无论如何都是兼容的。 是的,PKCS7 填充与 PKCS5Padding 相同。如果更改为 ECB 不起作用,则 iPhone 可能正在使用 CBC 模式。您需要确定初始化向量并确保服务器使用的是相同的。 感谢您的回复。我在客户端和服务器上创建了一个相同的 IV,但仍然无法正常工作。这就是严重缺乏适用于 iPhone 的体面且可靠的 AES 库的地方! :( 您能否发布一个纯文本示例以及每个环境中生成的密文? 您是否尝试过在客户端使用 AES 算法的其他变体? (即 AES192、AES256) 【参考方案1】:这不是我的区域,但看起来在客户端上你有PKCS7
,但在服务器上你有PKCS5
。
【讨论】:
从wikipedia 开始,这些模式是可以互换的。【参考方案2】:我刚刚遇到了完全相同的问题。我在 ios 客户端上使用 CommonCrypto,使用设置:
NSData * encrypted = [data dataEncryptedUsingAlgorithm:kCCAlgorithmAES128 key:pass initializationVector:iv options:kCCOptionPKCS7Padding error:&status];
服务器使用Cipher.getInstance("AES/CBC/PKCS5Padding");
,其密钥和初始化向量与客户端相同。
在最后几个小时撞墙之后,我终于按照 Jason 的建议检查了 dataEncryptedUsingAlgorithm
例程并在 FixKeyLengths
之后打印出 keyData
。原来我的 128 位密钥扩展为 192 位,并在末尾添加了 0。修复此问题后,一切正常。 :)
更新:我的答案是在 2 年前发布的,这个问题似乎在最新的NSData+CommonCrypto 代码中得到了修复。具体来说,这是导致问题的部分:
static void FixKeyLengths( CCAlgorithm algorithm, NSMutableData * keyData, NSMutableData * ivData )
NSUInteger keyLength = [keyData length];
switch ( algorithm )
case kCCAlgorithmAES128:
if ( keyLength <= 16 )
[keyData setLength: 16];
else if ( keyLength <= 24 )
[keyData setLength: 24];
else
[keyData setLength: 32];
break;
第一次检查 keyLength <= 16
以前不存在。
如果您现在仍然遇到问题,那可能是其他问题。
【讨论】:
您好,我也遇到同样的问题,能否分享示例代码。谢谢。 @ylian :我面临同样的问题。请分享您的代码。【参考方案3】:iPhone 使用 AES 的什么模式?您没有列出任何内容,所以这可能意味着它没有使用链接 (ECB)。
但是,在 Java 端,您使用的是 CBC,但没有指定初始化向量。那绝对是错误的。如果您真的在使用 CBC,您必须拥有在加密期间使用的 IV。 IV 不是秘密。可以和密文一起发送。
如果你真的使用ECB,没有IV,但是你的Java指定了错误的模式。
【讨论】:
【参考方案4】:根据您的示例,服务器运行正常,而客户端运行不正常。
看数据,我猜是key错了。请向我们展示 iPhone 代码,尤其是从“1234567891123456”到您的密钥的代码。
【讨论】:
按要求添加到原帖中。【参考方案5】:我最近在另一个项目中遇到了这个问题。问题是密钥太长了一个字节,无法放入dataEncryptedUsingAlgorithm
方法内的char
缓冲区。
问题在于NSString
上的getBytes
方法是软失败的。它将大部分字符串复制到缓冲区中,但由于密钥太长一个字节,它会通过将第一个字符设置为 NUL
(字符 0)将操作“标记”为失败。
进入 Xcode 中的那个方法,看看你的键 char[16] 缓冲区是什么样子的。它可能有同样的问题,并且有 0, '2', '3', '4', ...
的内容。
【讨论】:
以上是关于iPhone(Objective-c)和Java之间的AES区别的主要内容,如果未能解决你的问题,请参考以下文章
如何将 int 从 iPhone 发送到 Apple Watch 标签(objective-c)
使用 Objective-C - iPhone 设置代理用户名和密码
iPhone 上的 Objective-C - NSOperationQueue 和 NSInvocationOperation 的使用