C++发送字符串到C#失真,导致解密失败分析

前言

这个问题发生在一款正在开发的病例查看软件,病例查看软件为了保护病人的一些数据,对病例文件进行了加密,这些文件和密钥同时进行分发(这是存在一定风险的,然方案之前就定了,修改麻烦)。

密钥的读取、文件的加密解密由cpp开发的encryption.dll进行。

 

问题现象

使用C#调用cpp的一个dll读取2进制文件密钥,然后根据密钥解码文本文件,发现某些病例解码后文件和未加密前是一致的,有些文件则出现乱码,导致不能使用。

 

排查过程

 

开始怀疑是,在调用的C#端进行加密解密重构,哪里可能出现了异常,因为之前通过注入时,由于scope管理的问题,导致病例id在查看时没有更新,于是读取到密钥不是当前的密钥,从而不能正常解密文件;然一通查下来,重构没有问题,id更新正常,加密解密的输入没有问题。

 

那么就怀疑加密模块encryption.dll可能是出了什么问题。

但单独将encryption的项目重新配置了下,以console程序的方式,在主函数里添加测试代码后发现一切正常……

 

这时就怀疑,C#端调用时获取到的密钥可能失真了,与c++端给出的密钥可能不一致。试了下,确实如此。

 

以下为C++获取的密钥:

image

 

以下为C#调用端拿到的C++返回的密钥,忽略左侧的日期。

image

 

原因终于找到 ……

 

原因分析

C++在加载密钥后,以字符串的方式返回给调用的C#方法,C#方法临时保存密钥在内存中,在解密时将密钥与输入文件地址当作参数,再传入C++程序中进行解密。

然而C++中的string字符串:​​C++ std::string​​:可以包含任意字节(包括 \0),是字节容器

而C#中字符串:C# string:文本字符串

 

要试图让 C# string 和 C++ std::string 存储相同的二进制数据​​ - 这是不可能的任务,因为它们的根本设计目的不同。

 

解决方案

 

1.  不改变当前的密钥方式与存储方式的情况下,只能修改密钥的读取;C++程序加载密钥后,不再以字符串的方式返回给C#调用,而是以char数组或char*方式返回。

2.  C++端直接不再返回密钥,而是自行在读取后保存在内存中,只将加密解密方法暴露出来即可。这应该是最符合面向对象原则的一种处理方法。

 

以上都是在还使用原c++ dll的情况下的,最差的情况,就是C#端自行实现密钥加载、加密解密方法。

 

建议

多语言混合编程时,一定要注意语言之间的差异。如像C++字符串与C#字符串间的差异,有符号的char与无符号的char的区别,内存的管理等等……

posted @ 2025-08-29 13:42  盛沧海  阅读(5)  评论(0)    收藏  举报