从C#调用时,从CFB模式截断输出
Truncated output from CFB mode when calling from C#
我有一个非常烦人的问题,我两天都无法解决。我有一个encrypt()
方法,它利用了用C++编写的Crypto++库。方法实现如下:
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;
};
当我在本机环境中调用此方法时,它工作得很好,可以毫无问题地加密整个26Kb的xml字符串。
最终,我不得不在C#代码中实现加密,为此,我在本机dll中编写了以下包装器代码,以便稍后与PInvoke一起使用:
extern "C"
API_EXPORT char* _cdecl encrypt(char* contents)
{
string cont(contents);
CRijndaelHelper rij;
string transformedText = rij.Encrypt(cont);
return marshalReturn(transformedText);
}
而PInvoke部分看起来如下:
[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个字节,仅此而已。
请告知。
您的根本问题是使用了错误的类型。加密适用于字节数组,而不适用于文本。您需要停止使用string
、char*
等。在非托管代码中需要使用unsigned char*
,在托管代码中使用byte[]
。
你可能很难接受这个建议,但我还是建议你的。除了零字节被视为空终止符的问题(截断的原因(之外,您当前的方法只是忽略了文本编码的问题。你不能那样做。
您可能有充分的理由希望将一个字符串转换为另一个字符串。这很好,但转换的加密部分需要对字节数组进行操作。处理文本到文本加密的方法是使用转换链。加密时的转换运行方式如下:
- 使用定义良好的编码将字符串转换为字节数组。例如,UTF-8
- 加密字节数组,这将导致输出另一个字节数组
- 使用例如base64将此加密字节数组编码为文本
这尊重加密在字节数组上操作的事实,以及对文本编码的明确性。
在相反的方向上,您颠倒步骤:
- 将base64解码为加密的字节数组
- 解密此字节数组
- 使用UTF-8对解密后的字节数组进行解码,以获得原始字符串
返回从本机代码调用时正确加密的字符串
问题不在于C++encrypt
,它使用std::string
。问题是将它编组回作为char*
的托管代码。
将CRijndaelHelper::Encrypt
更改为以下内容以删除将以1/255的概率大量散布的嵌入NULL
:
#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;
};
对于Base64
编码,作为char*
的封送处理将而不是截断遇到的第一个NULL
字节的加密结果。
然后,解密:
StringSource ss(cipher, true,
new Base64Decoder(
new StreamTransformationFilter(d,
new StringSink(text)
)));
- 递归函数计算序列中的平方和(并输出过程)
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 请解释"函数1(p1,p2,p3);"的输出
- C++:将控制台输出存储在宏中更好吗
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 简化C++包括变量名称和函数输出的模式
- 执行输出模式必须与示例相同
- C++11 fgetc 在"r+b"模式下使用时向我的文件输出 0
- 在C 中未获得所需的1-0模式金字塔输出
- 如何在C++[库模式]中抑制 LibSVM 的输出
- 为什么写入模式下的管道会输出一些东西
- 如果命令不只是打印结果,而是进入某种交互模式,如何处理来自C++的终端命令执行的输出?
- c++模式将popen()输出与strcmp()匹配
- 使用Python / c++开发:在调试模式下没有输出
- 当Unicode模式打开时,打印到VS2010中的调试输出
- 坏的音频输出在立体声模式- FFMPEG PortAudio c++
- 从C#调用时,从CFB模式截断输出
- 只在调试模式下输出控制台
- 奇怪的文本模式文件输出行为