我正在尝试使用具有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时,我收到以下错误:
根据讨论here,似乎.NET TripleDESCryptoServiceProvider在8位中使用CipherMode.CFB,而Crypto ++使用128位。当尝试为.NET设置FeedbackSize时,它会抛出异常。
有谁知道如何解决这个问题?
答案 0 :(得分:1)
来自评论:
问题可能是反馈大小。我相信.Net使用小的反馈大小,如8位,用于CFB模式。 Crypto ++使用CFB模式的完整块大小。我建议使用CBC模式获取基线。一旦你在.Net和Crypto ++中得到相同的结果,然后切换到CFB模式并在反馈大小上旋转旋钮。
你有例子如何做到这一点?
您可以在Crypto ++ wiki上找到CBC Mode的示例。其他感兴趣的Wiki页面可能是TripleDES和CFB 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);
}