我必须将 Android 应用迁移到使用 Cipher 的 iOS。所以这里是Android代码:
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()));
...
byte[] result = Hex.encode(output, 0, output.length);
String resultS = new String(Str.toChars(result));
我为objective-c 尝试了很多东西,但找不到一种方法来获得与Java 相同的字符串。我使用了这里的 iOS 代码 http://dotmac.rationalmind.net/2009/02/aes-interoperability-between-net-and-iphone/ (还有更多,但都一样)。
然后要在 iOS 上获取字符串,请使用以下内容:
NSString* resultS = [encryptedData base64Encoding]
但结果字符串不匹配。也许问题是我如何处理 NSData 的编码(似乎 Java 版本不使用 base64,我没问题?)
有什么想法吗?
编辑 1:
好的,我取得了一些进展(我希望)。检查 java 代码,他们使用 8 block 大小和 DES/CBC, key 为 24 个字符。所以我将代码从 CocoaFu 更改为:
- (NSData *)doCipherNSData *)dataIn
keyNSData *)symmetricKey
contextCCOperation)encryptOrDecrypt
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeDES];
uint8_t iv[kChosenCipherBlockSize];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySize3DES,
(const void *)iv,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
当我尝试在 java 中对“测试”消息进行编码时,我得到“f69d7c299597c880”,但在 iOS 上(当然使用相同的 key )我得到 3DES 的“< 91864397 > < 41434eaa >”和“< ed660859 > < 4bad6f7f > "用于 DES。关于我还能改变什么的任何想法?
Best Answer-推荐答案 strong>
这是一个难题,因为它要么有效要么无效,而且线索很少。最好的方法是尽可能简单地开始并逐步建立。
首先要准确了解 java 代码在做什么。使用 CBC 模式将有一个 iv(初始化值),但在发布的 java 代码中没有明确指定。您需要找出 java 代码正在使用什么。同时发布完整的java代码。
从代码PaddedBufferedBlockCipher 我推断有 block 填充,这可能是PKCS5或PKCS7,从填充的角度来看两者是相同的,iOS等效是kCCOptionPKCS7Padding。确保这一点。
确保 key 长度相同,对于 AES,选项为 128、192 和 256 位,除非有特殊原因使用 128。
代码 Hex.encode 似乎暗示输出是十六进制编码的,你需要在 iOS 上做同样的事情,这与 Base64 不同。
另一个主要问题是让两边的所有参数都相同。特别感兴趣的是:
- 加密 key 值和大小
- 模式:CBC、ECB 等(您可能应该使用 CBC)
- 大多数模式都需要初始化向量 (iv)
- 填充方法KCS7 等(AES 是 block 密码,需要输入 block 大小的倍数)
- 任何后期加密处理、十六进制或 Base64 编码。
尽可能简单地开始,iv 全部为 0,一个 block 大小的数据,没有填充,简单的键,没有后处理。从一个可以在系统之间共享的文件中获取key、iv和测试数据,这样可以防止一些错误,比如c string jul终止等。
这是我使用的 iOS 代码:
#import <CommonCrypto/CommonCryptor.h>
+ (NSData *)doCipherNSData *)dataIn
ivNSData *)iv
keyNSData *)symmetricKey
contextCCOperation)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.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
还将 Security.framework 添加到您的项目中。
如果安全性很重要,请考虑让具有安全经验的人创建代码和协议(protocol)。如果安全性不重要,只需明文发送密码即可。
应用中的一些错误还不错,应用基本上仍然可以运行,安全性中的一个错误就失去了所有安全性。
良好的安全性并不像人们想象的那么容易——或者正如我妻子所说:“如果加密很容易,每个人都会这样做”,但她的意思确实正确。
关于Android -> iOS 密码迁移,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/7670540/
|