使用Crypto ++和.NET的CFB模式的TripleDES

时间:2017-04-27 18:25:53

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

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

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

这是C ++示例

K3zUUA==

产生以下结果:

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();
       }
   }
 }

这是C#示例:

K7nXyg==

产生以下结果:

K7nXyg==  
K3zUUA==

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

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();
       }
   }
 }

任何人都可以指出他们显示不同结果的问题。

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

---------------------更新4/27/2017 -------------------- ---------------------

现在尝试使用一点点不同的.NET实现,给我不同的结果......

K7nXyp+x9kY=

给了我:

application.properties

为什么?

------更新4/28/2017 -----------

This文章非常清楚地描述了Crypto ++的实现。

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

enter image description here

根据讨论here,似乎.NET TripleDESCryptoServiceProvider在8位中使用CipherMode.CFB,而Crypto ++使用128位。当尝试为.NET设置FeedbackSize时,它会抛出异常。

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

1 个答案:

答案 0 :(得分:1)

来自评论:

  
    

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

  
     

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

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

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

你真的需要达到基线。在达到基线之前,不应使用随机消息和随机密钥和iv。

这是在Crypto ++中使用小于块大小的反馈大小的示例。这个例子可以在CFB Mode的Crypto ++ wiki上找到(我们为此答案添加了它)。您将不得不拨入您的参数随机参数(但我建议您首先使用类似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);
}