C# 从C调用时CFB模式的截断输出#
我有一个相当烦人的问题,我两天都无法解决。我有一个使用C++编写的密码+ +库的<代码>加密()/>代码方法。该方法实现如下:C# 从C调用时CFB模式的截断输出#,c#,c++,encryption,pinvoke,crypto++,C#,C++,Encryption,Pinvoke,Crypto++,我有一个相当烦人的问题,我两天都无法解决。我有一个使用C++编写的密码+ +库的加密()/>代码方法。该方法实现如下: string CRijndaelHelper::Encrypt(string text) { CFB_Mode< AES >::Encryption e; e.SetKeyWithIV(_key, sizeof(_key), _iv); string cipher, encoded; // CFB mode must not us
string CRijndaelHelper::Encrypt(string text)
{
CFB_Mode< AES >::Encryption e;
e.SetKeyWithIV(_key, sizeof(_key), _iv);
string cipher, encoded;
// CFB mode must not use padding. Specifying
// a scheme will result in an exception
StringSource ss(text, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
));
return cipher;
};
[DllImport("EncryptDecrypt.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string encrypt([MarshalAs(UnmanagedType.LPStr)] string contents);
而PInvoke部分如下所示:
string CRijndaelHelper::Encrypt(string text)
{
CFB_Mode< AES >::Encryption e;
e.SetKeyWithIV(_key, sizeof(_key), _iv);
string cipher, encoded;
// CFB mode must not use padding. Specifying
// a scheme will result in an exception
StringSource ss(text, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
));
return cipher;
};
[DllImport("EncryptDecrypt.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string encrypt([MarshalAs(UnmanagedType.LPStr)] string contents);
一切看起来都很正常,除了我在transformedText
变量中只加密了前540个字节,仅此而已
请告知
。。。返回从本机代码调用时正确加密的字符串
问题不是你的C++ >代码>加密<代码>,它使用了<代码> STD::String < /C>。问题在于将其作为
char*
封送回托管代码
将CRijndaelHelper::Encrypt
更改为以下内容,以删除嵌入的NULL
,该值将以1/255的概率自由分布:
#include <cryptopp/base64.h>
using CryptoPP::Base64Encoder;
...
string CRijndaelHelper::Encrypt(string text)
{
CFB_Mode< AES >::Encryption e;
e.SetKeyWithIV(_key, sizeof(_key), _iv);
string cipher, encoded;
// CFB mode must not use padding. Specifying
// a scheme will result in an exception
StringSource ss(text, true,
new StreamTransformationFilter(e,
new Base64Encoder(
new StringSink(cipher)
)));
return cipher;
};
你的根本问题是你使用了错误的类型。加密使用字节数组,而不使用文本。您需要停止使用
string
、char*
等等。您需要在非托管代码中使用unsigned char*
,在托管代码中使用byte[]
你可能很难接受这个建议,但我还是照样给你。除了将零字节视为空终止符(截断的原因)的问题之外,您当前的方法完全忽略了文本编码的问题。你不能那样做
您可能有很好的理由希望将一个字符串转换为另一个字符串。这很好,但是转换的加密部分需要在字节数组上操作。处理文本到文本加密的方法是使用一系列转换。加密时的转换如下所示:
只是猜测一下,但是
rij.Encrypt(cont)
可能会返回一个在位置540附近有0x00字节的数组。百科文本应该均匀分布在[0-255]上,因此在26KB中应该有大量的then。修复方法是将返回值从char*
更改为包含长度的值。使用API\u EXPORT int\u cdecl encrypt(在unsigned char*IN、OUT unsigned char*OUT、INOUT unsigned int*osize中)重新设计该接口可能更好。
成功接收xml字符串并返回从本机代码调用时正确加密的字符串。CryptoPP支持StringSink目标,从代码中可以看出。整个问题是影响API的PInvoke调用会发生什么。我可以肯定地告诉您,StreamTransformationFilter(e,new StringSink(cipher))
最终将在其中嵌入一个NULL
。因为C++字符串具有C字符数组和长度,所以<代码>字符串< /代码>将处理它。一个char*
不会。你就是那个男人!:)现在工作。如果没有帮助,我想我永远也不会明白这一点。我唯一难以理解的是,本机构造的std::string与使用从CLR封送的char*数组初始化的std::string之间的实际区别是什么。编组对这个字符*的实际作用是什么,导致加密失败?事实上,它发生在封送回托管之前。同意你的看法,David,但不幸的是,公司正在使用许多文件,这些文件已经用这种方法加密,因此我担心更改编码可能会导致问题。CRijndaelHelper::Encrypt()代码在我开始实现之前就已经编写好了。然而,上面JWW的方法,加上你的回答,对我帮助很大。谢谢你接受的答案表明方法有所改变,与我的建议没有太大的不同。另一个答案没有解决的是遇到非ASCII文本的可能性。这正是我想说的。@aquila-David在设计问题上是对的。我只帮助解决了一个非常小的问题(嵌入的NULL
导致截断)。你还有更大的问题需要解决。虽然David建议使用UTF-8,但我想说的是,为了便于携带,您必须使用它。@jww感谢您的慷慨评论。我想说UTF8不是唯一可能的选择。虽然这很可能是最好的。有时UTF16可能是最好的。然而,关键是用于从文本到字节数组(以及返回)的编码是以明确的方式定义的。