Android到iOS的密码迁移

3

我需要将一个使用Cipher的Android应用迁移到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));

我尝试了很多Objc的东西,但找不到一种方法来获得与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和24个字符的DES/CBC密钥。因此,我将代码从CocoaFu更改为:
- (NSData *)doCipher:(NSData *)dataIn
             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 + 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中对“test”消息进行编码时,我得到了“f69d7c299597c880”,但在iOS上(当然使用相同的密钥)我得到了3DES的“< 91864397 > < 41434eaa >”,以及DES的“< ed660859 > < 4bad6f7f >”。你有什么其他的想法可以改变吗?


Base64编码与十六进制编码不同,请在比较输出之前使用相同的编码。 - Paŭlo Ebermann
3个回答

4
这是一个棘手的问题,因为它要么有效,要么无效,很少有线索。最好的方法是尽可能简单地开始并逐步构建。
首先要学习Java代码的确切作用。在CBC模式下,将有一个iv(初始化向量),但在发布的Java代码中没有明确指定。您需要找出Java代码正在使用什么。还请发布完整的Java代码。
从代码PaddedBufferedBlockCipher中,我推断出存在块填充,这可能是PKCS5或PKCS7,从填充的角度来看两者是相同的,iOS等效选项是kCCOptionPKCS7Padding。请确保此事。
确保密钥长度相同,对于AES,选项为128、192和256位,除非有特殊原因,否则使用128。
代码Hex.encode似乎意味着输出正在进行十六进制编码,您需要在iOS上执行相同操作,这与Base64不同。
另一个主要问题是在两侧获取所有参数相同。特别感兴趣的是:
1.加密键值和大小 2.模式:CBC、ECB等(您应该使用CBC) 3.大多数模式都需要初始化向量(iv) 4.填充方法:PKCS7等(AES是块密码,需要输入块大小的倍数) 5.任何加密后处理,如十六进制或Base64编码。
尽可能简单地开始,iv为全部0,数据为一个块大小,无填充,简单密钥,无后处理。从可以在系统之间共享的文件中获取密钥、iv和测试数据,这将防止一些错误,如c字符串jul终止等。
这是我使用的iOS代码:
#import <CommonCrypto/CommonCryptor.h>

+ (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.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添加到您的项目中。

如果安全性很重要,请考虑让具有安全经验的人创建代码和协议。如果安全性不太重要,只需以明文形式发送密码。

应用程序中出现一些错误并不那么糟糕,应用程序仍然基本工作,但如果出现安全漏洞,所有安全都将丢失。

好的安全性并不像人们想象的那么简单——就像我的妻子说的:“如果加密很容易,每个人都会这样做”,但她真正的意思是正确地做。


谢谢!我取得了一些进展并在原帖上发表了,希望你可以帮助我。 - Sebastián Castro

0

好的,我有一些进展(希望如此)。检查Java代码,他们使用块大小为8和24个字符密钥的DES/CBC。因此,我将代码从CocoaFu更改为以下内容:

- (NSData *)doCipher:(NSData *)dataIn
             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 + 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中对"test"消息进行编码时,我得到了"f69d7c299597c880",但在iOS上(当然使用相同的密钥),我得到了"< 91864397 > < 41434eaa >"用于3DES和"< ed660859 > < 4bad6f7f >"用于DES。您有什么其他建议吗?

-1

你正在尝试在密码中使用CBC模式,但iOS不支持CBC模式,只支持ECB。看这里


iOS CommonCrypto 支持 CBC,而且 CBC 是默认的。 - zaph
在 SO 的参考中添加了注释以更正 CBC 得到支持的事实。 - zaph
我认为正如CocoaFu所说,CBC是默认选项。 - Sebastián Castro
从苹果的头文件CommonCryptor.h中:初始化向量,可选。当启用Cipher Block Chaining(CBC)模式时,块密码使用它。如果存在,则必须与所选算法的块大小相同。如果选择了CBC模式(通过选项标志中缺少kCCOptionECBMode位),并且没有IV,则将使用NULL(全零)IV。 - zaph
@CocoaFu 好的,我会了解的。 - Barmaley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接