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_oPriRsam_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_oPriRsam_oPubRsa后,关于加解密的有四个接口:

public byte[] RSAPubKeyEncrypt(byte[] byPlainText)public byte[] RSAPriKeyDecrypt(byte[] byPlainText)public byte[] RSAPriKeyEncrypt(byte[] byPlainText)public byte[] RSAPubKeyDecrypt(byte[] byPlainText)

接口名字表明了接口的作用。其中接口内部还是调用了m_oPriRsa/m_oPubRsaEncryptDecrypt方法,具体参考[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中。

1 0
原创粉丝点击