ASP.NET 加密 Part.3(非对称算法)

       非对称加密算法和对称加密算法有些类似,只有少许不同。主要在于对密钥的管理上。对称加密算法只有一个密钥,而非对称加密算法有两个密钥:一个用来加密数据(公钥),一个用来解密数据(私钥)。公钥可以传递给任何想加密数据的人,而私钥只应由解密信息的人所拥有。

 

       .NET Framework 只为实际的数据加密提供了 1 个非对称加密算法RSA,记住,DSA 只用于数字签名),因此,创建这个工具并不需要包含一个用来选择加密算法的方法:

public static class AsymmetricEncryptionUtility
{
    public static string GenerateKey(string targetFile){}
    private static void ReadKey(RSACryptoServiceProvider algorithm , string keyFile){}
    public static byte[] EncryptData(string data,string publicKey){}
    public static string DecryptData(byte[] data,string keyFile){}
}

 

      GenerateKey() 创建 RSA 加密算法的实例,用来生成密钥。它只在通过 DPAPI 保护的文件中存储私钥,并使用该算法的 ToXmlString() 以及 XML 字符串的形式返回公钥。这是比较实际的,私钥通常被应用程序保存为秘密信息,公钥可以被共享以便加密信息,然后该加密信息被应用程序使用其秘密的私钥解密。

       这个函数的调用者需要将公钥存储在某个地方,这对加密信息来讲是必要的:

public static string GenerateKey(string targetFile)
{
    RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
 
    // 创建并返回包含当前 RSA 对象的密钥的 XML 字符串
    // true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥
    string completeKey = algorithm.ToXmlString(true);
    byte[] keyBytes = Encoding.UTF8.GetBytes(completeKey);
 
    keyBytes = ProtectedData.Protect(keyBytes, null, DataProtectionScope.LocalMachine);
 
    using (FileStream fs = new FileStream(targetFile, FileMode.Create))
    {
        fs.Write(keyBytes, 0, keyBytes.Length);
 
    }
    return algorithm.ToXmlString(false);
}

 

       ReadKey() 只需要从文件中读取密钥,然后通过 FromXml() 初始化传递的加密算法实例即可

private static void ReadKey(RSACryptoServiceProvider algorithm, string keyFile)
{
    byte[] keyBytes;
 
    using (FileStream fs = new FileStream(keyFile, FileMode.Open))
    {
        keyBytes = new byte[fs.Length];
        fs.Read(keyBytes, 0, (int)fs.Length);
    }
 
    keyBytes = ProtectedData.Unprotect(keyBytes, null, DataProtectionScope.LocalMachine);
 
    algorithm.FromXmlString(Encoding.UTF8.GetString(keyBytes));
}

 

       EncryptData() 需要调用者传入 GenerateKey() 返回的公钥的 XML 字符串表示,又因为私钥不需要用来加密,使用 RSA 进行加密和解密的代码如下

public static byte[] EncryptData(string data, string publicKey) 
{
    RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
    // 通过 XML 字符串中的密钥信息初始化 RSA 对象
    algorithm.FromXmlString(publicKey);
 
    return algorithm.Encrypt(Encoding.UTF8.GetBytes(data), true);        
}
 
public static string DecryptData(byte[] data, string keyFile) 
{
    RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
    ReadKey(algorithm, keyFile);
 
    byte[] clearData = algorithm.Decrypt(data, true);
    return Encoding.UTF8.GetString(clearData);        
}

 

       测试页面的代码:

using System;
using System.IO;
using System.Text;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Security.Cryptography;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using EncryptionUtility;
 
 
public partial class _Asymmetric : System.Web.UI.Page
{
    private string KeyFileName;
 
    protected void Page_Load(object sender, EventArgs e)
    {
        KeyFileName = Server.MapPath("~/") + "asymmetric_key.config";
    }
 
    protected void GenerateKeyCommand_Click(object sender, EventArgs e)
    {
        try
        {
            PublicKeyText.Text = AsymmetricEncryptionUtility.GenerateKey(KeyFileName);
            Response.Write("Key generated successfully!<br/>");
        }
        catch
        {
            Response.Write("Exception occured when encrypting key!");
        }
    }
 
    protected void EncryptCommand_Click(object sender, EventArgs e)
    {
        // Check for encryption key
        if (!File.Exists(KeyFileName))
        {
            Response.Write("Missing encryption key. Please generate key!");
        }
 
        try
        {
            byte[] data = AsymmetricEncryptionUtility.EncryptData(
                                ClearDataText.Text, PublicKeyText.Text);
            EncryptedDataText.Text = Convert.ToBase64String(data);
        }
        catch
        {
            Response.Write("Unable to encrypt data!");
        }
    }
 
    protected void DecryptCommand_Click(object sender, EventArgs e)
    {
        // Check for encryption key
        if (!File.Exists(KeyFileName))
        {
            Response.Write("Missing encryption key. Please generate key!");
        }
 
        try
        {
            byte[] data = Convert.FromBase64String(EncryptedDataText.Text);
            ClearDataText.Text = AsymmetricEncryptionUtility.DecryptData(data, KeyFileName);
        }
        catch
        {
            Response.Write("Unable to decrypt data!");
        }
    }
 
    protected void ClearCommand_Click(object sender, EventArgs e)
    {
        ClearDataText.Text = "";
        EncryptedDataText.Text = "";
    }
}

       测试页面设计代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Asymmetric.aspx.cs" Inherits="_Asymmetric" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div style="text-align: center">
        <asp:Panel ID="MainPanel" runat="server" BorderStyle="Solid" BorderWidth="1px" Width="100%">
            <table border="0" width="100%">
                <tr>
                    <td style="text-align: left">
                        Step 1:<br />
                        Generate Encryption Key
                    </td>
                    <td style="text-align: left">
                        <asp:LinkButton ID="GenerateKeyCommand" runat="server" OnClick="GenerateKeyCommand_Click">Generate Key</asp:LinkButton><br />
                        <asp:TextBox ID="PublicKeyText" runat="server" Rows="5" TextMode="MultiLine" Columns="40"
                            Width="600px"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td style="text-align: left">
                        Step 2:<br />
                        Clear-text data
                    </td>
                    <td style="text-align: left">
                        <asp:TextBox ID="ClearDataText" runat="server" Rows="5" TextMode="MultiLine" Width="600px"
                            Columns="40"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td style="text-align: left">
                        Step 3:<br />
                        Encrypted data
                    </td>
                    <td style="text-align: left">
                        <asp:TextBox ID="EncryptedDataText" runat="server" Rows="5" TextMode="MultiLine"
                            Width="600px" Columns="40"></asp:TextBox>
                    </td>
                </tr>
                <tr>
                    <td>
                    </td>
                    <td>
                        <asp:LinkButton ID="EncryptCommand" runat="server" OnClick="EncryptCommand_Click">Encrypt</asp:LinkButton>&nbsp;<asp:LinkButton
                            ID="DecryptCommand" runat="server" OnClick="DecryptCommand_Click">Decrypt</asp:LinkButton>&nbsp;<asp:LinkButton
                                ID="ClearCommand" runat="server" OnClick="ClearCommand_Click">Clear</asp:LinkButton>
                    </td>
                </tr>
            </table>
        </asp:Panel>
    </div>
    </form>
</body>
</html>

 

       测试效果:

       image

 

       最后,这里是非对称算法工具的完整代码,并附上中文注释:

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;
 
namespace EncryptionUtility
{
    public static class AsymmetricEncryptionUtility
    {
        /// <summary>
        /// 生成加密密钥
        /// </summary>
        /// <param name="targetFile">保存私钥的文件路径</param>
        /// <returns>返回公钥</returns>
        public static string GenerateKey(string targetFile)
        {
            RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
 
            // RSACryptoServiceProvider.ToXmlString():
            // 创建并返回包含当前 RSA 对象的密钥的 XML 字符串
            // true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥
            string completeKey = algorithm.ToXmlString(true);
            byte[] keyBytes = Encoding.UTF8.GetBytes(completeKey);
 
            // 使用 DPAPI 保护私钥
            keyBytes = ProtectedData.Protect(keyBytes, null, DataProtectionScope.LocalMachine);
 
            using (FileStream fs = new FileStream(targetFile, FileMode.Create))
            {
                fs.Write(keyBytes, 0, keyBytes.Length);
            }
            return algorithm.ToXmlString(false);
        }
 
        /// <summary>
        /// 读取私钥,重新配置 RSA 算法实例的密钥
        /// </summary>
        /// <param name="algorithm"></param>
        /// <param name="keyFile"></param>
        private static void ReadKey(RSACryptoServiceProvider algorithm, string keyFile)
        {
            byte[] keyBytes;
 
            using (FileStream fs = new FileStream(keyFile, FileMode.Open))
            {
                keyBytes = new byte[fs.Length];
                fs.Read(keyBytes, 0, (int)fs.Length);
            }
 
            // 解除 DPAPI 对私钥的保护
            keyBytes = ProtectedData.Unprotect(keyBytes, null, DataProtectionScope.LocalMachine);
 
            algorithm.FromXmlString(Encoding.UTF8.GetString(keyBytes));
        }
 
        /// <summary>
        /// 加密数据
        /// </summary>
        /// <param name="data">欲加密的对象文本字符串</param>
        /// <param name="publicKey">加密公钥</param>
        /// <returns>加密后的数据</returns>
        public static byte[] EncryptData(string data, string publicKey) 
        {
            RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
            // 通过 XML 字符串中的密钥信息初始化 RSA 对象
            algorithm.FromXmlString(publicKey);
 
            return algorithm.Encrypt(Encoding.UTF8.GetBytes(data), true);        
        }
 
        /// <summary>
        /// 解密数据
        /// </summary>
        /// <param name="data">被加密的数据</param>
        /// <param name="keyFile">私钥所在文件路径</param>
        /// <returns>解密后的数据</returns>
        public static string DecryptData(byte[] data, string keyFile) 
        {
            RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider();
            ReadKey(algorithm, keyFile);
 
            byte[] clearData = algorithm.Decrypt(data, true);
            return Encoding.UTF8.GetString(clearData);        
        }
    }
}

posted on 2013-04-26 18:10  SkySoot  阅读(598)  评论(0编辑  收藏  举报

导航