zoukankan      html  css  js  c++  java
  • 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);        
            }
        }
    }
  • 相关阅读:
    .Matrix-Alpha总结展望
    .Matrix测试随笔
    Beta冲刺--第三次冲刺随笔
    Beta冲刺--第二天随笔
    Beta冲刺--第一天随笔
    专业团队——Beta冲刺凡事预则立
    专业团队Alpha总结展望——前事不忘后事之师
    专业团队——(Alpha冲刺)测试随笔
    专业团队——Alpha冲刺汇总
    总结随笔
  • 原文地址:https://www.cnblogs.com/SkySoot/p/3045415.html
Copyright © 2011-2022 走看看