使用Crypto实现c++和c#之间加密的互操作性
interoperability of encryption between C++ and C# with Crypto
我正试图在Qt项目中使用Crypto++ lib加密c++中的字符串,并在web应用程序中解密c#中的字符串。这是我的代码。
c++代码,使用Crypto++ lib
std::string Crypter::encrypt(const std::string& str_in, const std::string& key, const std::string& iv)
{
std::string str_out;
CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption encryption((byte*)key.c_str(), key.length(), (byte*)iv.c_str());
qDebug() << encryption.DefaultKeyLength();
qDebug() << encryption.DefaultIVLength();
CryptoPP::StringSource encryptor(str_in, true,
new CryptoPP::StreamTransformationFilter(encryption,
new CryptoPP::Base64Encoder(
new CryptoPP::StringSink(str_out),
false // do not append a newline
)
)
);
return str_out;
}
在这里调用函数
std::string str = "123456789012345";
std::string key = "01234567891234560123456789123456"; // 32 bytes
std::string iv = "0123456789123456"; // 16 bytes
std::string str_encrypted = c->encrypt(str, key, iv);
std::string str_decrypted = c->decrypt(str_encrypted, key, iv);
std::cout << "str_encrypted: " << str_encrypted << std::endl;
std::cout << "str_decrypted: " << str_decrypted << std::endl;
这段代码产生如下结果
Plain text: "123456789012345"
Encrypted value (base64): 3Qo/6hWctRiID3txA9nC
我在这里用c#写的相同的代码
private void button1_Click(object sender, EventArgs e)
{
string strOutput = Encrypt("123456789012345");
Debug.WriteLine("Encrypted value is: " + strOutput);
}
private string Encrypt(string clearText)
{
byte[] clearBytes = Encoding.ASCII.GetBytes(clearText + " ");
using (Aes encryptor = Aes.Create("AES"))
{
encryptor.BlockSize = 128;
encryptor.KeySize = 128;
encryptor.Mode = CipherMode.CFB;
encryptor.Key = Encoding.ASCII.GetBytes("01234567891234560123456789123456");
encryptor.IV = Encoding.ASCII.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
byte[] bt = ms.ToArray();
clearText = Convert.ToBase64String(bt);
}
}
return clearText;
}
产生如下结果
Encrypted value is: 3YklwM2vG20ZmkOT029jTTL7FlSZHrh0RfvaT1FFa2k=
谁能告诉我我错过了什么?从两种语言中获得相似输出的正确方法是什么?
我的目标是在c++中加密一个值,并在c#中解密。
编辑
我做了一些改变。
将Hello world替换为123456789012345将编码从utf更改为Ascii在c#字符串的末尾增加了一个空字节将模式更改为CFB
我还用新结果编辑了原始结果
不幸的是,这样做之后,两个字符串不匹配。
我已经确保两个输入是相同的
您的c++代码是根据std::string
。这很可能包含在ANSI代码页下编码的文本。当你把它传递到CryptoPP::StringSource
时,我希望它直接处理该文本的字节,而不将其转换为任何其他编码。
c#正在传递Encoding.Unicode.GetBytes
的结果。这意味着加密工作在UTF-16编码数据的字节上。
由于编码不同,字节表示也不同。那么由于字节数不同,加密结果也不同。
你需要让这两段代码在相同的方案下工作。
如果ANSI(或甚至只是ASCII)字符都是你想要处理的(这可能是你的c++代码的情况),那么你可以修改c#代码使用Encoding.Default.GetBytes
(或可能Encoding.ASCII.GetBytes
)来获得clearText的字节。
编辑
进一步看,你的c++代码使用CryptoPP::CFB_Mode
,而你的c#代码使用encryptor.Mode = CipherMode.CBC;
。这些模式需要匹配,否则算法将以不同的方式应用。
您可能需要检查其他属性,例如padding,以确保它们在相同的方案下工作。
似乎有两个潜在的问题。下面的代码将产生与CryptoCC库(3Qo/6hWctRiID3txA9nC
)相同的输出:
byte[] clearBytes = Encoding.ASCII.GetBytes(clearText);
using (var encryptor = RijndaelManaged.Create())
{
encryptor.KeySize = 128;
encryptor.Padding = PaddingMode.Zeros;
encryptor.Mode = CipherMode.CFB;
encryptor.Key = Encoding.ASCII.GetBytes("01234567891234560123456789123456");
encryptor.IV = Encoding.ASCII.GetBytes("0123456789123456");
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
Array.Copy(ms.ToArray(), clearBytes, clearBytes.Length);
clearText = Convert.ToBase64String(clearBytes);
}
}
return clearText;
同样,下面的Crypto++实现将提供在示例(3YklwM2vG20ZmkOT029j
)中返回的值。net。
std::string encrypt(const std::string& str_in, const std::string& key, const std::string& iv)
{
std::string str_out;
CryptoPP::AES::Encryption e1((byte*)key.c_str(), key.length());
// use feedback size of 1 byte.
CryptoPP::CFB_Mode_ExternalCipher::Encryption encryption(e1, (byte*)iv.c_str(), 1);
CryptoPP::StringSource encryptor(str_in, true,
new CryptoPP::StreamTransformationFilter(encryption,
new CryptoPP::Base64Encoder(
new CryptoPP::StringSink(str_out),
false // do not append a newline
)
)
);
return str_out;
}
注意事项:
不需要在字符串后面添加零
Crypto++实现不允许在密码反馈(CFB)模式下填充。.NET实现需要填充;但是,可以手动截断多余的数据(如上面的. net示例所做的那样)。(见http://social.msdn.microsoft.com/Forums/vstudio/en-US/a1be5f49-5f0f-4f5f-b01c-af46fdc71915/des-encryption-cfb-mode)。
请参阅这篇关于使用AES代替Rijndael作为CSP的含义的文章。以下警告特别适用于CFB模式:
本质上,如果您想使用RijndaelManaged作为AES,您需要确保:
- 块大小设置为128位
- 你没有使用CFB模式,或者如果你是反馈大小也是128位
在这种情况下,使用CFB模式会引入额外的并发症。注意,这是使用CFB的结果;如果您使用密码块链(CBC)模式,则Aes
和Rijndael
对于给定的密钥和值(IwffxivpwdSuS9BV0KeyCg==
)返回与Crypto++相同的结果。
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- int(c) 和 c-'0' 之间的区别。C++
- 在cuda线程之间共享大量常量数据
- AES加密到解密未正确输出
- 在c代码之间共享数据的最佳方式
- Mix_Init和Mix_OpenAudio SDL之间的区别是什么
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- 大小相等但成员数量不同的结构之间的性能差异
- 类与私有变量的其他类之间的线程安全性
- 如何在cpp文件之间切换窗口?在Qt中
- 线程之间的布尔停止信号
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 在 const 函数中通过引用和指针返回之间的区别
- C++ 和 node.js 之间的 RSA 加密
- 加密 和Python之间的Diffie-Hellman密钥交换
- openssl rc4 命令行加密和 cpp 文件实现 rc4 之间的区别
- 使用Crypto实现c++和c#之间加密的互操作性
- 使用加密 API 在客户端和服务器之间进行加密和解密的正确方法是什么?