Client-ServerRSA加解密通信方案-Client端(C#)(二)
来源:互联网 发布:c语言 生成随机数 编辑:程序博客网 时间:2024/06/06 05:35
0. 背景
在前一文中有叙述了RSA加解密的Server端(一),使用C++在linux环境中实践。本文中将叙述Client Unity端中RSA加解密,使用符合(一)中图1的中通信协议。
1. 自定义密钥模块CryptModule.cs
在(一)中我们产生了公钥public.pem
和私钥private.pem
,我们将这两个文件复制到客户端StreamingAssets
路径中,并且使用:
string pub = Path.Combine(Application.streamingAssetsPath, "public.pem");string pri = Path.Combine(Application.streamingAssetsPath, "private.pem");
表明其路径,然后通过文件路径加载公钥私钥:
CryptModule cmodule = new CryptModule();cmodule.LoadRSAPriKey(pri);cmodule.LoadRSAPubKey(pub);
其中CryptModule是一个关于RSA钥模块,如下图所示:
图1.RSA钥模块
它有两个RSACryptoServiceProvider
类[MSDN]实例m_oPriRsa
、m_oPubRsa
,两个加载秘钥的方法LoadRSAPriKey/LoadRSAPubKey
。
加载OpenSSL
形式的秘钥,必须使用OpenSSL的封装库,对于客户端来说,不必安装整套OpenSSL
的库来完成(当然也有客户端安装OpenSSL库流程)。在这里需要用到RSA加载秘钥的接口(PEM_read_RSA_PUBKEY(fp, &rsa,NULL, NULL)
; PEM_read_RSAPrivateKey(fp, &rsa,NULL, NULL)
)。
这里用到了rsakey.cs
文件中的LoadProviderFromFile
方法,因此上述两个方法具体实现为:
public bool LoadRSAPriKey(string strFilePath){ rsakey.LoadProviderFromFile(strFilePath, ref m_oPriRsa); return m_oPriRsa != null;}public bool LoadRSAPubKey(string strFilePath){ rsakey.LoadProviderFromFile(strFilePath, ref m_oPubRsa); return m_oPubRsa != null;}
至于LoadProviderFromFile
的由来会在下文讲述。
当成功加载两个RSACryptoServiceProvider
类实例m_oPriRsa
、m_oPubRsa
后,关于加解密的有四个接口:
public byte[] RSAPubKeyEncrypt(byte[] byPlainText)public byte[] RSAPriKeyDecrypt(byte[] byPlainText)public byte[] RSAPriKeyEncrypt(byte[] byPlainText)public byte[] RSAPubKeyDecrypt(byte[] byPlainText)
接口名字表明了接口的作用。其中接口内部还是调用了m_oPriRsa/m_oPubRsa
的Encrypt
或Decrypt
方法,具体参考[MSDN]。
2. 加载PEM格式RSA秘钥(rsakey.cs)
因此在这里我们需要提到JavaScience
的OpenSSLKey.cs的源码。OpenSSLKey.cs
是个基于.NET框架的解析PEM或DER格式RSA秘钥的控制台工具库。在成功解析RSA的公钥和私钥后,它会返回一个.NET框架的RSACryptoServiceProvider
实例,并且可产出一个PKCS#12格式的文件,这个文件可以使用Java 2中的内建库来解析得到RSA的公钥和私钥。
综上,OpenSSLKey.cs
旨在帮助非对称加密算法RSA在OpenSSL, .NET, JAVA跨环境的可操作性。
PEM加密后的秘钥必须是如下形式中的一种:
(1)-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEF...-----END PUBLIC KEY-----(2)-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQDfnaXDy9v4q8PfV ...-----END RSA PRIVATE KEY-----(3)-----BEGIN RSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDDEK-Info: DES-EDE3-CBC,379AB79E55059F9Agaakm48Y8qYA997fJREN4JtfVkfTdnVzaZK2 ....-----END RSA PRIVATE KEY-----(PKCS #8 formats)(4)-----BEGIN PRIVATE KEY-----MIICeAIBADANBgkqhkiG9w0BA ....-----END PRIVATE KEY-----(5)-----BEGIN ENCRYPTED PRIVATE KEY-----MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG .....-----END ENCRYPTED PRIVATE KEY-----
参考OpenSSLKey.cs
代码,结合本文需要加载PEM格式的RSA秘钥的需求,这里写了rsakey.cs
(github地址)来满足需求。rsakey.cs
提供了一个public static
方法LoadProviderFromFile
:
public static void LoadProviderFromFile(string pszFilePath, ref RSACryptoServiceProvider provider)
输入参数pszFilePath
是公钥或是私钥的文件路径;ref provider
是解析PEM格式RSA秘钥后的个RSACryptoServiceProvider
类实例引用。方法通过文件内内容会自动判断需要解析的是公钥还是私钥。
3. 栗子
在写好CryptModule
之后,就可以在Unity场景中举个栗子。
a). 新建场景example.unity后,有MainCamera物体;
b). 新建RsaTest.cs脚本,并挂在MainCamnera上,代码如下:
// RsaTest.csusing UnityEngine;using System.Collections;using crypt;using System.Text;using System.IO;public class RsaTest : MonoBehaviour { // Use this for initialization void Start () { // (0) 加载公钥与私钥 string pub = Path.Combine(Application.streamingAssetsPath, "public.pem"); string pri = Path.Combine(Application.streamingAssetsPath, "private.pem"); CryptModule cmodule = new CryptModule(); cmodule.LoadRSAPriKey(pri); cmodule.LoadRSAPubKey(pub); string text = "<pub_encrypt & pri_decrypt> Hello this is tab_space"; // 原文 // (1)使用公钥加密, 得到byEncryptText byte[] byEncryptText = cmodule.RSAPubKeyEncrypt(Encoding.UTF8.GetBytes(text)); Debug.Log("Pub Encrypted length:" + byEncryptText.Length); // (2)使用私钥解密, 得到byEncryptText byte[] byDecryptText = cmodule.RSAPriKeyDecrypt(byEncryptText); Debug.Log("Pri Decrypted length:" + byDecryptText.Length.ToString()); string strDecryptText = Encoding.UTF8.GetString(byDecryptText); Debug.Log("Pri Decrypted Text:" + strDecryptText); Debug.Log("/*----------------------------------------------------------*/"); text = "<pri_encrypt & pub_decrypt> Hello this is tab_space"; // 原文 // (1)使用私钥加密, 得到byEncryptText byEncryptText = cmodule.RSAPriKeyEncrypt(Encoding.UTF8.GetBytes(text)); Debug.Log("Pri Encrypted length:" + byEncryptText.Length); // (2)使用公钥解密, 得到byEncryptText byDecryptText = cmodule.RSAPubKeyDecrypt(byEncryptText); Debug.Log("Pub Decrypted length:" + byDecryptText.Length.ToString()); strDecryptText = Encoding.UTF8.GetString(byDecryptText); Debug.Log("Pub Decrypted Text:" + strDecryptText); } // Update is called once per frame void Update () { }}
(c). 打印的log截图:
4. 总结
本文讲述了在客户端(Unity/C#)参考OpenSSLKey.cs工具库对RSA秘钥的PEM文件格式的加载过程,并通过RSACryptoServiceProvider
类实例的Encrypt/Decrypt
方法对byte[]
进行RSA加解密的技术过程。栗子的Unity工程已上传至csdz的github中。
- Client-ServerRSA加解密通信方案-Client端(C#)(二)
- Client-ServerRSA加解密通信方案-Server端(C++)(一)
- 异步通信实例(二)Client
- socket通信实例client端
- iOS Client 与WebSocket 通信(二)
- iOS Client 与WebSocket 通信(二)
- iOS Client 与WebSocket 通信(二)
- iOS Client 与WebSocket 通信(二)
- iOS Client 与WebSocket 通信(二)
- client.c
- JAX-WS(二)- client
- client
- client
- Client
- Client
- Client
- Client
- client
- Python开发学习笔记(9) - list,tuple,string切片
- Android Fragment切换时的动画效果
- 习题43 基本的面向对象分析和设计
- Java并发控制synchronized与AtomicInteger类
- Android 投射工具和录屏工具
- Client-ServerRSA加解密通信方案-Client端(C#)(二)
- Android多文件断点续传(四)——处理网络状态变化
- 总结下Oracle 中的Insert用法
- 参数的更新
- Android打包过程
- (个人笔记)JAVA6和7的不同编码风格导致的错误
- python中对字典(dict)的迭代
- mysql 全面优化
- linux下devicetree中常用的of函数