【问题标题】:TripleDES in CFB mode using Crypto++ and .NET使用 Crypto++ 和 .NET 的 CFB 模式中的 TripleDES
【发布时间】:2017-04-27 18:25:52
【问题描述】:

我正在尝试使用具有 Crypto++ 的 C++ 应用程序和使用 TripleDESCryptoServiceProvider 的 .NET 应用程序使用 TripleDES 获得相同的结果。我尝试将 Key 和 IV 设置为相同,但得到不同的结果。

这个问题已经问过here,但没有明确的答案。

这里是 C++ 示例

#include <stdio.h>
#include <cstdlib>
#include <string>
#include <iostream>


#include "dll.h"
#include "mybase64.h"

using namespace std;

USING_NAMESPACE(CryptoPP)



int main()
{
std::cout << "Crypto++ Example" << endl;

std:cout << "TEST" << endl;


const int textSize = 4;
const int keySize = 24; 

byte iv[] = { 240, 4, 37, 12, 167, 153, 233, 177 };
byte key[] = {191, 231, 220, 196, 173, 36, 92, 125, 146, 210, 117, 220, 95, 104, 154, 69, 180, 113, 146, 19, 124, 62, 60, 79};


byte encryptedText[textSize];

char cText[] = {'T', 'E', 'S', 'T'};

byte* text = new byte[textSize];

for (int ndx = 0; ndx<4; ndx++)
{
    text[ndx] = (byte)cText[ndx];
}


CFB_FIPS_Mode<DES_EDE3>::Encryption encryption;

encryption.SetKeyWithIV(key, keySize, iv);

encryption.ProcessString(encryptedText, text, 4);

string encoded;

encoded = base64_encode(encryptedText, 4);

cout << encoded << endl;

system("pause");

return 0;
 }

产生以下结果:

K3zUUA==

这是 C# 示例:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace TripleDESExample
{
   class Program
   {
       static void Main(string[] args)
       {
           string message = "TEST";
           byte[] iv = { 240, 4, 37, 12, 167, 153, 233, 177 };
           byte[] key = { 191, 231, 220, 196, 173, 36, 92, 125, 146, 210, 117, 220, 95, 104, 154, 69, 180, 113, 146, 19, 124, 62, 60, 79 };

           byte[] data = Encoding.ASCII.GetBytes(message);

           using (var tdes = new TripleDESCryptoServiceProvider())
           {
               tdes.Mode = CipherMode.CFB;
               tdes.Padding = PaddingMode.Zeros;

               tdes.IV = iv;
               tdes.Key = key;

               using (var ms = new MemoryStream())
               {
                   using (var crypto = new CryptoStream(ms, tdes.CreateEncryptor(), CryptoStreamMode.Write))
                   {
                       crypto.Write(data, 0, data.Length);
                       crypto.Close();

                    }


                    Array.Copy(ms.ToArray(), data, data.Length);

                    Console.WriteLine(string.Format("Encrypted: {0}", Convert.ToBase64String(data)));

               }
           }

           Console.WriteLine("Press any key...");
           Console.ReadKey();
       }
   }
 }

这会产生以下结果:

K7nXyg==

所以你可以看到它们产生了不同的结果。

K7nXyg==  
K3zUUA==

谁能指出他们显示不同结果的问题。

如果可能,请提供示例代码。

---------------------2017 年 4 月 27 日更新-------------------- ---------------------

现在尝试使用稍微不同的 .NET 实现也给了我不同的结果......

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace TripleDESExample
{
   class Program
   {
       static void Main(string[] args)
       {
           string message = "TEST";


        byte[] iv = { 240, 4, 37, 12, 167, 153, 233, 177 };
        byte[] key = { 191, 231, 220, 196, 173, 36, 92, 125, 146, 210, 117, 220, 95, 104, 154, 69, 180, 113, 146, 19, 124, 62, 60, 79 };



        byte[] bytes = Encoding.ASCII.GetBytes(message);

        TripleDESCryptoServiceProvider cryptoServiceProvider1 = new TripleDESCryptoServiceProvider();
        cryptoServiceProvider1.Key = key;
        cryptoServiceProvider1.IV = iv;
        cryptoServiceProvider1.Mode = CipherMode.CFB;
        cryptoServiceProvider1.Padding = PaddingMode.Zeros;
        TripleDESCryptoServiceProvider cryptoServiceProvider2 = cryptoServiceProvider1;


        byte[] inArray = cryptoServiceProvider2.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);
        cryptoServiceProvider2.Clear();

        Console.WriteLine(string.Format("Encrypted: {0}", Convert.ToBase64String(inArray, 0, inArray.Length)));



        Console.WriteLine("Press any key...");
        Console.ReadKey();
       }
   }
 }

这给了我:

K7nXyp+x9kY=

为什么?

--------2017 年 4 月 28 日更新------------

This 文章很好地描述了 Crypto++ 的实现。

当我尝试增加 BlockSize 和 FeedbackSize 时,我收到以下错误:


根据here 的讨论,似乎 .NET TripleDESCryptoServiceProvider 使用 8 位 CipherMode.CFB,而 Crypto++ 使用 128 位。当尝试将 .NET 的 FeedbackSize 设置得更高时,它会引发异常。

有人知道如何解决这个问题吗?

【问题讨论】:

  • 问题可能是反馈大小。我相信 .Net 对 CFB 模式使用较小的反馈大小,例如 8 位。 Crypto++ 使用 CFB 模式的完整块大小。我建议使用 CBC 模式获取基线。一旦你在 .Net 和 Crypto++ 中得到相同的结果,然后切换到 CFB 模式并转动反馈大小的旋钮。
  • 你有例子如何做到这一点?
  • “听起来问题可能与消息填充有关......” - 我不相信 CFB 模式被填充。问题可能是反馈大小。我不是 Windows 开发人员,所以我无法在 .Net 方面提供帮助。一个 .Net 人将不得不告诉你如何设置反馈大小。顺便问一下,为什么FeedbackSize 不起作用?你得到什么例外?
  • 我尝试使用 .NET 中的所有选项进行填充,但仍然无法产生与 Crypto++ 相同的结果

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


【解决方案1】:

来自cmets:

问题可能是反馈大小。我相信 .Net 对 CFB 模式使用较小的反馈大小,例如 8 位。 Crypto++ 使用 CFB 模式的完整块大小。我建议使用 CBC 模式获取基线。一旦你在 .Net 和 Crypto++ 中得到相同的结果,然后切换到 CFB 模式并转动反馈大小的旋钮。

你有例子如何做到这一点?

您可以在 Crypto++ wiki 上找到 CBC Mode 的示例。其他感兴趣的 wiki 页面可能是 TripleDESCFB Mode

您还可以在 NIST website 上找到这些操作模式的测试向量。

您确实需要达到基线。在达到基线之前,您不应使用随机消息和随机密钥和 ivs。


这是在 Crypto++ 中使用小于块大小反馈大小的示例。该示例可在 Crypto++ wiki 上的 CFB Mode 获得(我们为此答案添加了它)。您将不得不拨入您的参数随机参数(但我建议您首先使用 NIST 测试向量之类的基准)。

您应该警惕使用小于块大小的反馈大小,因为它会降低块密码的安全性。如果可以选择,您应该增加 Mcrypt 或 .Net 的反馈大小;并且不会减少 Crypto++ 的反馈大小。

SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
memset(key, 0x00, key.size());
memset(iv, 0x00, iv.size());

AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
                                      (Name::IV(), ConstByteArrayParameter(iv));

string plain = "CFB Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
   cout << "plain text: " << plain << endl;

   CFB_Mode< AES >::Encryption enc;
   enc.SetKey( key, key.size(), params );

   StringSource ss1( plain, true, 
      new StreamTransformationFilter( enc,
         new StringSink( cipher )
      ) // StreamTransformationFilter      
   ); // StringSource
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss2( cipher, true,
   new HexEncoder(
      new StringSink( encoded )
   ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
   CFB_Mode< AES >::Decryption dec;
   dec.SetKey( key, key.size(), params );

   // The StreamTransformationFilter removes
   //  padding as required.
   StringSource ss3( cipher, true, 
      new StreamTransformationFilter( dec,
         new StringSink( recovered )
      ) // StreamTransformationFilter
   ); // StringSource

   cout << "recovered text: " << recovered << endl;
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

它产生以下输出:

$ ./test.exe
plain text: CFB Mode Test
cipher text: 2506FBCA6F97DC7653B414C291
recovered text: CFB Mode Test

所以你可以看到它们产生了不同的结果。

K7nXyg==
K3zUUA==

以下复制K7nXyg==,但我不清楚这就是你想要的。你真的应该达到你的基线。然后您可以告诉我们诸如无奇偶校验的密钥和 8 位反馈大小之类的信息。

const byte key[] = { 191, 231, 220, 196, 173, 36, 92, 125,
                     146, 210, 117, 220, 95, 104, 154, 69,
                     180, 113, 146, 19, 124, 62, 60, 79 };
const byte  iv[] = { 240, 4, 37, 12, 167, 153, 233, 177 };

ConstByteArrayParameter cb(iv, sizeof(iv));
AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
                                           (Name::IV(), ConstByteArrayParameter(iv, sizeof(iv)));

string plain = "TEST";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
   cout << "plain text: " << plain << endl;

   CFB_Mode< DES_EDE3 >::Encryption enc;
   enc.SetKey( key, sizeof(key), params );

   StringSource ss1( plain, true, 
      new StreamTransformationFilter( enc,
         new StringSink( cipher )
      ) // StreamTransformationFilter      
   ); // StringSource
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss2( cipher, true,
   new Base64Encoder(
      new StringSink( encoded )
   ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
   CFB_Mode< DES_EDE3 >::Decryption dec;
   dec.SetKey( key, sizeof(key), params );

   // The StreamTransformationFilter removes
   //  padding as required.
   StringSource ss3( cipher, true, 
      new StreamTransformationFilter( dec,
         new StringSink( recovered )
      ) // StreamTransformationFilter
   ); // StringSource

   cout << "recovered text: " << recovered << endl;
}
catch( CryptoPP::Exception& ex )
{
   cerr << ex.what() << endl;
   exit(1);
}

【讨论】:

  • 感谢您的回复。我需要在 .NET 中重现这一点,我不是试图调整 Crypto++ 以匹配 .NET,而是反过来。您在 C++ 中提供的示例,我在复制它们时没有问题。我需要让 .NET 实现显示与 Crypto++ 相同的内容。您可以添加基线 NIST 示例吗?
  • 我在使用经过 FIPS 验证的 Crypto++ 5.3 的算法参数时遇到错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多