使用Crypto ++和.NET的CFB模式下的TripleDES [英] TripleDES in CFB mode using Crypto++ and .NET

查看:121
本文介绍了使用Crypto ++和.NET的CFB模式下的TripleDES的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

已经在此处提出了这个问题,但是在那里没有明确的答案.

这是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==

任何人都可以指出对他们显示不同结果的问题是什么.

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

--------------------- UPDATE 4/27/2017 -------------------- ---------------------

现在尝试使用稍有不同的.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=

为什么?

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

本文很好地描述了Crypto ++实现./p>

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


根据讨论此处. NET TripleDESCryptoServiceProvider使用8位的CipherMode.CFB,而Crypto ++使用128位的CipherMode.CFB.尝试将.NET的FeedbackSize设置更高时,它将引发异常.

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

解决方案

来自注释:

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

您有示例如何完成此操作吗?

您可以在Crypto ++ Wiki上找到 CBC模式的示例.其他感兴趣的Wiki页面可能是 TripleDES 上找到这些操作模式的测试向量. NIST网站.

您确实需要达到基准.在达到基线之前,不应使用随机消息,随机键和ivs.


这是在Crypto ++中使用小于块大小的反馈大小的示例.该示例可在Crypto ++ Wiki上的 CFB模式中找到(我们为此答案添加了它).您将必须输入参数随机参数(但我建议您首先使用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);
}

I am trying to get same result using TripleDES using C++ app which has Crypto++ and .NET app which uses TripleDESCryptoServiceProvider. I tried setting Key and IV the same but I am getting different results.

This question was already asked here, but there is no clear answer.

Here is C++ example

#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;
 }

which produces following result:

K3zUUA==

Here is C# example:

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

Which produces following result:

K7nXyg==

So you can see that they produce different result.

K7nXyg==  
K3zUUA==

Can anyone point what could be the issue for them showing different result.

If possible please provide example code.

---------------------UPDATE 4/27/2017-----------------------------------------

Now tried using a little differently implementation of .NET giving me different result as well...

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

which gives me:

K7nXyp+x9kY=

Why?

------UPDATE 4/28/2017-----------

This article describes very well Crypto++ implementation.

When I try to increment BlockSize and FeedbackSize I get following error:


Based on the discussion here it seems like .NET TripleDESCryptoServiceProvider uses CipherMode.CFB in 8-bit while Crypto++ uses it with 128-bit. When trying to set FeedbackSize for .NET higher it throws exception.

Does anyone know how to resolve this issue?

解决方案

From the comments:

The issue is likely the feedback size. I believe .Net uses a small feedback size, like 8-bits, for CFB mode. Crypto++ uses the full block size for CFB mode. I'd recommend getting a baseline using CBC mode. Once you arrive at the same result in .Net and Crypto++, then switch to CFB mode and turn knobs on the feedback size.

Do you have example how to accomplish this?

You can find examples of CBC Mode on the Crypto++ wiki. Other wiki pages of interest may be TripleDES and CFB Mode.

You can also find test vectors for these modes of operation on the NIST website.

You really need to get to a baseline. You should not use random messages and random keys and ivs until you achieve your baseline.


Here's an example of using a less-than-blocksize feedback size in Crypto++. The example is available at CFB Mode on the Crypto++ wiki (we added it for this answer). You will have to dial in your parameters random parameters (but I suggest you baseline first with something like the NIST test vectors).

You should be wary of using a feedback size that is smaller than the block size because it can reduce the security of the block cipher. If given a choice, you should increase the feedback size for Mcrypt or .Net; and not reduce the feedback size for 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);
}

It produces the following output:

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


So you can see that they produce different result.

K7nXyg==
K3zUUA==

The following reproduces K7nXyg==, but its not clear to me that's what you want. You really should get to your baseline. Then you can tell us things like a key with no parity and an 8-bit feedback size.

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

这篇关于使用Crypto ++和.NET的CFB模式下的TripleDES的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆