如何在C#中解密使用Rijndael在iOS中加密的字符串

4
我将尝试使用Objective C和C#加密和解密字符串。在本地代码中,两者都能正常工作,但当我尝试在C#中解密iOS加密的字符串时,出现了一些错误。
以下是我在Objective C中使用的代码:
- (NSData *)AES256EncryptWithKey:(NSString *)key  Data: (NSData *) data
{
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)

    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [data length];

    NSData *iv =  [@"abcdefghijklmnopqrstuvwxyz123456" dataUsingEncoding:NSUTF8StringEncoding];

    size_t bufferSize = dataLength + kCCBlockSizeAES128;

    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;

    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          [iv bytes] /* initialization vector (optional) */,
                                          [data bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess)
    {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;

    return nil;
}

我想知道如何在C#中解密,我的块大小为256,IV大小为32,并使用“RijndaelManaged()”。 我没有使用盐和密码。

错误:类似“填充无效且无法删除”的东西。

我尝试设置填充方式,比如PKCS7,none,zero,但是什么都没有帮助我解密。

有人能帮忙吗?

编辑:我的C#代码在这里

public string DecryptString(string encrypted)
{
    string result = null;
    _encoder = new UTF8Encoding();
    if (!string.IsNullOrWhiteSpace(encrypted) && (encrypted.Length >= 32))
    {
        var messageBytes = Convert.FromBase64String(encrypted);
        using (var rm = new RijndaelManaged())
        { 
            rm.BlockSize = _blockSize;
            rm.Key = _encoder.GetBytes("mykey_here");
            rm.IV = _encoder.GetBytes("abcdefghijklmnopqrstuvwxyz123456"); ;
            rm.Padding = PaddingMode.Zeros;
            var decryptor = rm.CreateDecryptor(rm.Key, messageBytes.Take(_ivSize).ToArray());
            result = _encoder.GetString(Transform(messageBytes.Skip(_ivSize).ToArray(), decryptor));
        }
    }

    return result;
}

protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
{
    byte[] result;
    using (var stream = new MemoryStream())
    using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
    {
        cs.Write(buffer, 0, buffer.Length);
        cs.FlushFinalBlock();
        result = stream.ToArray();
    }

    return result;
}

你尝试过将 kCCOptionECBMode | kCCOptionPKCS7Padding 作为 CCCrypt 的第三个参数吗? - Doro
是的,我已经尝试过了,但没有用。如果我尝试使用kCCOptionECBMode,在iOS本身中无法进行加密。 - Rajesh
@Doro,在使用 ECB 模式时不应使用 IV。而且通常情况下,ECB 模式不应该被使用,因为它比 CBC 模式更不安全。 - zaph
@zaph,明白了。我问这个问题是因为在C#中默认模式是ECB,我从文档中读到的。 - Doro
不,RijndaelManaged的默认模式是CBC。文档(请参见我的答案中的链接):“属性值类型:System.Security.Cryptography.PaddingMode对称算法中使用的填充模式。默认值为PaddingMode.PKCS7。” - zaph
1个回答

5
iOS(通用加密)明确指定所有加密参数,而C#代码隐含确定许多参数。这些隐含参数虽然简化了使用,但在尝试实现互操作性时会出现问题。
C#类RijndaelManaged允许显式指定参数,请更改您的代码以使用这些参数,特别是BlockSize(128),KeySize(128),Mode(CipherMode.CBC)和Padding(PaddingMode.PKCS7)。 mode和Padding的默认值是可以接受的。请参见RijndaelManaged Documentation AES和Rijndael不同,特别是AES仅使用128位(16字节)的块大小,而Rijndael允许多个块大小。因此,需要为Rijndael指定128位的块大小。因此,iv也是128位(16字节)。两者都支持128、192和256字节的加密密钥。
你最好使用 AESManaged 类而不是 RijndaelManaged 类。请查看 AesManaged Documentation
C# 需要数据进行 Base64 编码,iOS 不需要显示编码操作,请确保在 iOS 端执行了该操作。
由于你正在使用 iv,请确保两端都使用 CBC 模式。在 Common Crypto 中,CBC 模式是默认的,请确保 C# 端使用了 CBC 模式。
请确保 C# 端使用 PKCS#7 或 PKCS#5 填充,它们是等效的。似乎 PKCS#7 是 C# 端的默认值,所以这应该没问题。
最好使用与指定大小完全相同的密钥,不要依赖默认填充。在Common Crypto中,密钥大小明确指定,并且如果提供的密钥太短,则进行空填充。C#代码似乎是通过提供的密钥确定密钥大小,在这种情况下,密钥为10个字节,因此解密密钥可能默认为128位,并且密钥被内部填充了空值。在iOS上,您明确指定了256位的密钥大小。这是一个需要修复的不匹配问题。提供一个精确匹配iOS端指定大小的密钥。
最后是iv,C#代码期望将iv前置到加密数据中,但iOS代码没有提供。解决方案是更改iOS代码以将iv前置到加密代码中。将iv更改为16字节,即AES块大小。
如果需要更多帮助,请提供测试数据、输入数据、iv和密钥的十六进制转储,以及加密调用之前和之后的转储。

如何在iOS中使用Rijndael加密算法? - Rajesh
我已经查看了你的另一个答案,你说: 对于256位块大小,您需要使用第三方实现中的Rijndael。请问您能否在iOS中推荐任何第三方代码? - Rajesh
不要使用256位块大小。当前的加密标准是AES(高级加密标准),请使用它。此外,人们认为256位块大小不再安全,可能更不安全。块大小与密钥大小无关,AES支持相同的密钥大小:128、192和256位。AES本质上与具有128位块大小的Rijndael相同。第三方实现的Rijndael可能会慢得多,Common Crypto使用特定的硬件指令。此外,Common Crypto AES是一个经过认证的实现。 - zaph

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