本文的应用场景是,Unity c#向vc++ 工程传递用户名和密码,可能会面临的安全性问题:
假如第三方对dll进行替换,c#的账号密码直接往下传,可能导致用户密码泄露的风险。
针对此种情况,对用户名和密码在C#层进行加密,并在C++ dll库中进行解密,从而在一定程度上规避此风险。
C++ RSA加解密方案
支持.net的RSACryptoServiceProvider
cryto++ library
openssl
第一种方案,C++RSA 跟C#版的RSA配套,用起来极为方便,但是依赖.net架构。需要依赖.net环境,将工程设置为支持clr。
后两种方案,是第三方集成库。当前使用较为广泛的方法是openssl,下面着重介绍openssl在RSA上的使用。
Openssl编译配置
按顺序执行下列命令
d:\openssl-1.0.1e> perl Configure VC-WIN32 no-asm –prefix=d:\openssl_lib (存放编译后的库文文件目录)
d:\openssl-1.0.1e> ms\do_ms
d:\openssl-1.0.1e> nmake -f ms\ntdll.mak (编译动态库)
d:\openssl-1.0.1e> nmake -f ms\nt.mak (编译静态库)
装载openssl到指定的目录d:\opensll_lib中
d:\openssl-1.0.1e> nmake -f ms\ntdll.mak install
d:\openssl-1.0.1e> nmake -f ms\nt.mak install
(b)继续编译, 提示错误:
cryptlib.obj : error LNK2001: unresolved external symbol _OPENSSL_ia32_cpuid
out32dll/libeay32.dll : fatal error LNK1120: 1 unresolved externals
解决办法: 修改do_ms文件如下:
perl util/mkfiles.pl >MINFO
perl util/mk1mf.pl debug no-asm VC-WIN32 >ms/nt.mak
perl util/mk1mf.pl debug dll no-asm VC-WIN32 >ms/ntdll.mak
perl util/mk1mf.pl debug no-asm VC-CE >ms/ce.mak
perl util/mk1mf.pl debug dll no-asm VC-CE >ms/cedll.mak
perl util/mkdef.pl 32 libeay > ms/libeay32.def
perl util/mkdef.pl 32 ssleay > ms/ssleay32.def
集成OpenSSL
打开Project Property面板:
Configuration Properties——VC++ Directories——Include Directories新增”d:\openssl_lib\include”(存放编译后的库文件的目录中);
VC++ Directories ——”Library files”选择中新增目录”d:\openssl_lib\lib”;
Configuration Properties ——Linker——Input——Additional Dependencies,添加libeay32.lib 和ssleay32.lib两个库即可。
Openssl生成公私密钥和证书
安装openssl,cmd执行openssl
OpenSSL>genrsa -out rsa_private_key.pem 1024
生成的pem文件如下:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDJsiBpRxfPFRh9DbmWizZbm5/HKxhpOOQMlmGo2LIuVWxXuzYj
TyQ9Jfn+zDfIGG3NLkAHrpcW0U8figjCXb/dXptc/MabgwPIP1jL1uqTLgIYeVsT
Jm6vEzd7c/t81VaOJDjFkQlrlqdOsH5JnAlGtqITqXHSimbgBDUjtJW+qwIDAQAB
AoGAICuGGeSZ+pCd0ExhHo7jw6bFzEmmYhoN3agauYiemt9LIY8dqnIUEKC/CBHg
j8y9rq1CzzbcqGoIGbq1fPLhCBAn1dkRePKKqSd1BM99oVwDP2YYBqzaUtPz1TYN
q0Q9QqKuQgkWkPC+7QugnDzIuzlqO9+/wdugLd2UateZZqECQQD4qtEsMPrSu9g8
yTjJOnyChYhQuUXbLalFlqSRnHWM7eIxqNkMjhPoK3sxGWWMNT410kNhxgWUZnMT
bbXjO2E7AkEAz6S5JjIY/GhFxer9vxY3yjUW7Agtnk0zyi70RpbuvttdNjUxeXiG
f/q3ilNJE2eWt2PaICb/c32PdCO5P5RBUQJBANZnmiErPikTM/f9W8wNdKupbQaF
KNk5fpj0sYKnT6equHwu5K5xlnJ5gyeriSYiBjirydN0xPzWdORMlSaO3V8CQCob
c1hljF+THaMXFkHr1YBx56YRun6BlWEIyIyQCvY1Md/ORawmXtARHas1XHpM5Wln
HFKs1dyrt62LmQNloyECQAZEeNq5AyRGRq+oAPjMlGEUrKR/7w3zXdCO2nyCYtQX
YkE4+ZBUeKBFgPEoHGUqY+yOD9xIg5d6rbf71Hh2kx0=
-----END RSA PRIVATE KEY-----
2)把RSA私钥转换成PKCS8格式
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
writing RSA key
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM –nocrypt
Enter Encryption Password:
Verifying - Enter Encryption Password:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICoTAbBgkqhkiG9w0BBQMwDgQIsz6q/2JpXSACAggABIICgHPkfKkuH+Dn18q0
k0xUIDmnKvApJlXlaRF1jo4wF1hbO0RThwr2r//AlScy5yoEeUMyhh5ae4yEzT7r
U3nGYcnVV64AkwV/JMthpYNVPpb4OL8xbOyGbmU3UigoAhLo4/bDkiGDs9ZTRyDW
p0QyOyFJZ0L7NhvWmkYsDUAahY/xjYQy3Cghk5pvhSQjhbAu3yaF3UtJNZhqGZCN
/p7nrwG9Vt0Ys6nzUC4PQFafyZzdfl4l9f0WlCwWSRNy+s3hxLavJySt6ycGAbNL
ue3lGpnVPLCgwh5p5I3w9Aym96hDsAvMdqXg92mbeO22Tqz8MccVQqIYO+HpPXn7
uH3aYx4sxjV/p+wUK/XlNL/XEoyw+WVJ4wxBBFGtZvk5lurCODdgFsZbfzGWO9gW
5Y2kXp4FK9iVzhiS1YI5fn6yaKAUPB+jtj5xSrmtxhV7Q7N5YuJeFsGhXNpuQKxy
XWyEbU2gbsuI0LYAr+r7M5LWSouYLne3NDfB1Op2oFwoz9j+p+drEgoByDWZQMo6
ay4T928LdHQFgKYajtBkch2Z5lNwwUdaZwe8AalJVTM2otDE9QSpiOq4Sjmyu5Od
Kt3SesMEoCQSJ2SM3dqMqEIBf/YDtL4juFId0uffNW2BcpVrq5muJ0+xTtWmC75Z
SsULmCwWzYTKe+OiG8r/Z7DVXY30onWfJnPJEGl3vyMGDDgacYQrN3qGMUGoJxzL
MeEdt9xfTlpY4XO/DIUAPEWJtLN0XvHSKlqMtk/m124ugugLzi4SmWusYDTs1rS3
MjpnNpSFYw12jBVcM95PCtuLmP7Ts9LXc5zbtpYIv8IP/S5RlasSQpCNfRLlADbB
d6pH+PA=
-----END ENCRYPTED PRIVATE KEY-----
3) 生成RSA公钥
输入命令rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem,
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJsiBpRxfPFRh9DbmWizZbm5/H
KxhpOOQMlmGo2LIuVWxXuzYjTyQ9Jfn+zDfIGG3NLkAHrpcW0U8figjCXb/dXptc
/MabgwPIP1jL1uqTLgIYeVsTJm6vEzd7c/t81VaOJDjFkQlrlqdOsH5JnAlGtqIT
qXHSimbgBDUjtJW+qwIDAQAB
-----END PUBLIC KEY-----
创建证书请求
openssl req -new -out cert.csr -key rsa_private_key.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:86
State or Province Name (full name) [Some-State]:Guangdong
Locality Name (eg, city) []:Shenzhen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Xfiction
Organizational Unit Name (eg, section) []:K
Common Name (eg, YOUR name) []:fiction
Email Address []:xfiction@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:xfiction8989
An optional company name []:xfiction
自签署根证书(自签署,就是不通过CA认证中心自行进行证书签名,这里用是x509)
openssl x509 -req -in cert.csr -out public.der -outform der -signkey rsa_private_key.pem -days 3650
Signature ok
subject=/C=86/ST=Guangdong/L=Shenzhen/O=Xfiction/OU=K/CN=fiction/emailAddress=xfiction@gmail.com
Getting Private key
XML到PEM的转换:
由于C#的RSACryptoServiceProvider所使用的是xml格式,openssl使用pem格式的秘钥。需要对秘钥进行转换。
可以直接通过线上转换工具RSA Key Converter(https://superdry.apphb.com/tools/online-rsa-key-converter)进行转换。
附上代码
RSAEncryptService rasService = new RSAEncryptService();
string psdEncrpted = rasService.RSAEncryptStr(pwd);
RSA* pPrivateRSA = createRSAWithMem(strPrivateKeyPerm);
//string strPubEncode = "ZfBe7UOZzjdoKsnf90vQe47klfj9+EmmlBUA86IMhFIpceKB0NxLeGSivw0JUk7s9QN+CFPIRTkr1Z7gXgniGNlkbuZzZcIoao1kWkvRGM81KTPt0YS8v/2RAE83re/c6zby4fGmELx9S+t8HdiUovDQaKZgz2ycgomfCxyI7mw=";
string strPubEncode = pwd;
string strPrivateDecode;
char strOrgData[1024] = { 0 };
Private_Decrypt(pPrivateRSA, strPubEncode, strPrivateDecode);
const char* decryptPwd = strPrivateDecode.c_str();
C#和c++代码见附件