3

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

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

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

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

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

密钥大小为 24 字节(3 个不同的密钥),IV 为 8 字节长。它们在 2 个代码中都是相同的。

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

我尝试使用带有 .Net 3.5 和 4.0 版本的 Mono,或者使用带有 .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;
}
4

2 回答 2

1

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

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

于 2013-06-14T15:40:06.123 回答
1

这些都不正确:

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++ 中更改反馈大小。您设置 aAlgorithmParameters来保存反馈大小参数,然后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 模式是否允许如此小的反馈大小。如果它抛出异常,那么您将需要使用 just CFB_Mode

AlgorithmParametersoperator()由于过载,可能看起来有点奇怪。NameValuePairs你可以在 Crypto++ wiki 上阅读它。其他感兴趣的 wiki 页面是TripleDESCFB Mode

----

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

但是,如果事情仍然对您不起作用,那么您就是一个未编码或解释的字节消息。例如,在 .Net 和 Crypto++ 中都使用它:

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

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

于 2017-04-28T19:48:30.437 回答