【问题标题】:TripleDES in CFB mode, C# and Crypto++ differsCFB 模式下的 TripleDES,C# 和 Crypto++ 不同
【发布时间】:2013-06-14 15:29:07
【问题描述】:

这是我的问题:我有一个 C++ 遗留代码(使用 crypto++ v5.6.1),我用 C# 开发了一个新代码(.NET 3.5 使用 System.Security.Cryptography)。我无法更改 C++ 代码,但我需要能够解密之前加密的数据,并且之前的应用程序必须能够解密我将使用新的 C# 代码加密的数据。

在这两种情况下使用的算法都是带有CFB密码模式的TripleDES,但最终加密的数据不一样,字节数和第一个字节一样,但除此之外所有其他字节都是不同。

填充是在 C++ 代码中手动完成的(添加零)。所以我将 PaddingValue 设置为 PaddingMode.Zeros。 (我也尝试在 C# 代码的末尾手动添加零,它没有改变任何东西)。

我尝试使用不同的 System.Text.Encoding 但结果是相同的(实际上测试的字符是“纯”ASCII(即:0 到 126 之间))。

C++ 代码中 MandatoryBlockSize() 的值是 8,所以我也将 FeedbackSize 设置为 8。但如果我理解它写,它实际上是我的静脉注射的大小,不是吗?

密钥大小为 24 字节(3 个不同的密钥),IV 为 8 字节长。 2个代码里都是一样的。

如果我在这两种情况下都使用 CBC 模式,结果是相同的(但是,正如我所说,我无法更改旧代码...),OFB 和 CTS 模式会引发异常(其中一个不可用且不兼容另一个)在我的 .NET 应用程序上,所以我无法比较结果。

我尝试将 Mono 与 .Net 3.5 和 4.0 版本一起使用,或者将 Visual 与 .Net 3.5 或 4.0 一起使用,4 个加密结果相同但与原始结果不同。

现在我真的不知道要测试什么...我宁愿不将 Crypto++ 包装在 C++/CLI 项目中以使用它而不是 System.Security.Cryptography。

有人有什么建议或者可以告诉我我做错了什么吗?

这是 C++ 代码:

void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv)
{
    byte    *bIn;
    byte    *bOut;
    LONG    l2,lb;

    CFB_FIPS_Mode<DES_EDE3>::Encryption encryption_DES_EDE3_CFB;
    encryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

    lb = encryption_DES_EDE3_CFB.MandatoryBlockSize();
    l2 = ((lIn + lb - 1)/lb)*lb;

    bIn = (byte*)malloc(l2);
    bOut = (byte*)malloc(l2);

    memset(bIn,0,l2);
    memset(bOut,0,l2);
    memcpy(bIn,bDataIn,lIn);

    encryption_DES_EDE3_CFB.ProcessString(bOut, bIn, l2);

    *lOut = l2;

    return bOut;
}

这是 C# 代码:

public FibxCrypt()
{
    _cryptoAlgo = new TripleDESCryptoServiceProvider();
    //_cryptoAlgo.GenerateKey();
    _cryptoAlgo.Key = _key;
    //_cryptoAlgo.GenerateIV();
    _cryptoAlgo.IV = _iv;
    _cryptoAlgo.Mode = CipherMode.CFB;
    _cryptoAlgo.Padding = PaddingMode.Zeros;

    _encoding = new UTF8Encoding();
}

private MemoryStream EncryptingString(string plainText, out long encryptSize)
{
    // Check arguments. 
    if (plainText == null || plainText.Length <= 0)
        throw new ArgumentNullException("plainText");

    // Create a decrytor to perform the stream transform.
    ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor();

    // Create the streams used for encryption. 
    //using (MemoryStream msEncrypt = new MemoryStream())
    MemoryStream msEncrypt = new MemoryStream();

    encryptSize = ((plainText.Length + _cryptoAlgo.FeedbackSize - 1) / _cryptoAlgo.FeedbackSize) * _cryptoAlgo.FeedbackSize;

    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    {
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt, _encoding))
        {
            //Write all data to the stream.
            swEncrypt.Write(plainText);
        }
    }

    // Return the encrypted memory stream. 
    return msEncrypt;
}

编辑:我尝试直接使用加密器,而不是使用流,我遇到了同样的问题。

private MemoryStream EncryptingString(string plainText, out long encryptSize)
{
    // Check arguments. 
    if (plainText == null || plainText.Length <= 0)
        throw new ArgumentNullException("plainText");

    ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor();

    byte[] cipherData = encryptor.TransformFinalBlock(
        _encoding.GetBytes(plainText), 0, plainText.Length);

    // Return the encrypted memory stream. 
    return msEncrypt;
}

【问题讨论】:

    标签: c# .net cryptography crypto++ tripledes


    【解决方案1】:

    您更改的 FeedBackSize 与 CFB 操作模式有关 (msdn documentation)。因此,您还应该检查 C++ 和 C# 中的反馈大小是否相同。

    我相信您的错误可能是 C++ 代码和 C# 代码之间的 BlockSizes。您是否尝试在 C# 实现中设置 BlockSize = 8?

    【讨论】:

    • 感谢您的反馈;)我也尝试在 C# 代码中将 BlockSize 设置为 8,但仅限于 64 位。如果我理解它写它是对应于 C++ MandatoryBlockSize 的 C# 反馈(女巫与 OptimalBlockSize 相同)。
    • @neolutin 好的。您是否尝试过将反馈大小设置为 64 位,以便将整个最后一个块反馈到密码中? C++“强制块大小”可能以 BYTES 报告,而“C#反馈大小”以 BITS 为单位,因此 64 位 = 8 字节,与 c++ 匹配。
    • 我尝试更改反馈大小,但抛出异常消息,例如(我的是法语):CFB 模式的注释大小必须为 8 位。我还尝试一次手动加密 8 个字节(将 AutoFlush 设置为 true,并将我的纯文本按 8 个字节块提供给 StreamWriter),但它没有改变任何东西......
    • @neolutin 那么我目前没有想法。我会在周末尝试一下——同时你可以希望有人顿悟。
    • 感谢您的宝贵时间。我目前正在尝试将 Crypto++ 包装在 C# 库中,但我真的不喜欢这个解决方案...
    【解决方案2】:

    这些都不正确:

    CFB_FIPS_Mode<DES_EDE3>::Encryption enc;
    enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    

    sizeof(key)sizeof(iv) 返回指针的大小,而不是安全参数的大小。你应该改用这个:

    enc.SetKeyWithIV(key, DES_EDE3::DEFAULT_KEYLENGTH, iv, DES_EDE3::BLOCKSIZE);
    

    如果它适用于 .Net,那么您应该更喜欢增加 Mcrypt 和 .Net 等库的反馈大小;并且不会减少 Crypto++ 中的反馈大小。这是因为当反馈大小不是完整块大小时,某些模式会失去安全性。

    我不知道这是否适用于 .Net,但您应该考虑或尝试一下:

    public FibxCrypt()
    {
        _cryptoAlgo = new TripleDESCryptoServiceProvider();
        _cryptoAlgo.Key = _key;
        _cryptoAlgo.IV = _iv;
        _cryptoAlgo.Mode = CipherMode.CFB;
        _cryptoAlgo.Padding = PaddingMode.Zeros;
    
        // Add this:
       _cryptoAlgo.FeedbackSize = _cryptoAlgo.BlockSize;
    }
    

    如果您无法在 .Net 中调整反馈大小,那么以下是如何在 Crypto++ 中更改反馈大小。您设置一个AlgorithmParameters 来保存反馈大小参数,然后使用附加参数调用SetKey

    void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv)
    {
        AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
                                                   (Name::IV(), ConstByteArrayParameter(iv, DES_EDE3::BLOCKSIZE));
        CFB_FIPS_Mode<DES_EDE3>::Encryption enc;
        enc.SetKey(key, 24, DES_EDE3::DEFAULT_KEYLENGTH);
    
        ...
    }
    

    我不清楚在 FIPS 模式下运行的 CFB 模式是否允许如此小的反馈大小。如果它抛出异常,那么您只需要使用CFB_Mode

    AlgorithmParameters 可能看起来有点奇怪,因为 operator() 过载。您可以在 Crypto++ wiki 上的 NameValuePairs 阅读有关它的信息。其他感兴趣的 wiki 页面是 TripleDESCFB Mode

    ----

    另外需要注意的是文本编码。由于 UTF-16,它通常会导致 .Net 和 Java 中的互操作性问题。 UTF-8 和 ASCII 引起的问题最少。你应该没事,因为你encoding = new UTF8Encoding()

    但是如果事情仍然不适合你,那么你就是一个没有编码或解释的字节消息。例如,在 .Net 和 Crypto++ 中都使用它:

    byte msg[4] = { 0x01, 0x02, 0x03, 0x04 };
    

    这四个字节没有被解释,所以它绕过了编码问题。

    【讨论】:

    • 感谢您的回复,但是我不再从事这个项目(即使是公司),所以我无法测试您的解决方案。那时我真的很希望能得到这样的东西……
    • @neolutin - 是的,我想的差不多。提供答案是因为该问题是热门搜索结果;它需要一个答案才能让用户在问题上站稳脚跟。我相信当有人试图将反馈大小从 8 位增加到 128 位时,.Net 会引发异常。但我不是 .Net 专家,所以我将把它留给 .Net 人来提出解决方案。
    猜你喜欢
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2021-06-19
    相关资源
    最近更新 更多