Silverlight信息加密 - 通过Rfc2898DeriveBytes类使用基于HMACSHA1的伪随机数生成器实现PBKDF2 (转)

http://blog.csdn.net/xuyue1987/article/details/6706600

在上一篇文章当中,介绍到了通过Silverlight获取web.config中的值,最后提到了加密的问题,因此首先对该安全问题做一个简单的描述。

问题描述

1. 下方是我的web.config文件,当中配置这一个媒体文件服务器的IP地址

  1. <?xml version="1.0"?>  
  2.   
  3. <!--  
  4.   For more information on how to configure your ASP.NET application, please visit  
  5.   http://go.microsoft.com/fwlink/?LinkId=169433  
  6.   -->  
  7.   
  8. <configuration>  
  9.   <connectionStrings>  
  10.     <add name="VideoFiles_ConnectionString" connectionString="127.0.0.1"/>  
  11.   </connectionStrings>  
  12.     <system.web>  
  13.         <compilation debug="true" targetFramework="4.0" />  
  14.     </system.web>  
  15.   
  16. </configuration>  

2. 当在Silverlight程序中获取到该config中的值时,我们可以发现,通过查看页面的Source Code,是可以看到这个IP地址的,它是以明文的方式显示出来的,这样会引发安全性问题,我相信没有人愿意将自己的服务器IP地址暴露在外面

 

解决方法

在Page页面获取到web.config后,对该文件当中的内容进行加密,从而有效地解决了明文显示的问题,这样,别人就不能通过查看源代码的方式从前台获取你的服务器IP地址或者其他机密信息了,其实现方法如下:

1. 在Page页面后台的.cs文件中,加入机密算法,使用Rfc2898DeriveBytes 获取密码、salt 值和迭代次数,然后通过调用 GetBytes 方法生成密钥:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.UI;  
  6. using System.Web.UI.WebControls;  
  7. using System.Collections.Specialized;  
  8. using System.Text;  
  9. using System.Configuration;  
  10. using System.Security.Cryptography;  
  11. using System.IO;  
  12.   
  13. namespace GetWebConfig.Web  
  14. {  
  15.     public partial class HostPage : System.Web.UI.Page  
  16.     {  
  17.         protected void Page_Load(object sender, EventArgs e)  
  18.         {  
  19.             //Clear the Cache  
  20.             Response.Cache.SetCacheability(HttpCacheability.NoCache);  
  21.             WriteInitParams();  
  22.         }  
  23.   
  24.         private void WriteInitParams()  
  25.         {  
  26.             string strConn = ConfigurationManager.ConnectionStrings["VideoFiles_ConnectionString"].ToString();  
  27.             StringBuilder stringBuilder = new StringBuilder();  
  28.             stringBuilder.Append("<param name=\"InitParams\" value=\"");  
  29.             stringBuilder.Append(Encrypt(strConn));  
  30.             stringBuilder.Append("\"/>");  
  31.             this.litInitParams.Text = stringBuilder.ToString();  
  32.         }  
  33.   
  34.         /**/  
  35.         /// <summary>  
  36.         /// 加密数据  
  37.         /// </summary>  
  38.         /// <param name="input">加密前的字符串</param>  
  39.         /// <returns>加密后的字符串</returns>  
  40.         public static string Encrypt(string input)  
  41.         {  
  42.             // salt值  
  43.             string saltValue = "saltValue";  
  44.             // 密码值  
  45.             string pwdValue = "xuyue";  
  46.   
  47.             byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes(input);  
  48.             byte[] salt = System.Text.UTF8Encoding.UTF8.GetBytes(saltValue);  
  49.   
  50.             // AesManaged - 高级加密标准(AES) 对称算法的管理类  
  51.             System.Security.Cryptography.AesManaged aes = new System.Security.Cryptography.AesManaged();  
  52.   
  53.             // Rfc2898DeriveBytes - 通过使用基于 HMACSHA1 的伪随机数生成器,实现基于密码的密钥派生功能 (PBKDF2 - 一种基于密码的密钥派生函数)  
  54.             // 通过 密码 和 salt 派生密钥  
  55.             System.Security.Cryptography.Rfc2898DeriveBytes rfc = new System.Security.Cryptography.Rfc2898DeriveBytes(pwdValue, salt);  
  56.   
  57.             /**/  
  58.             /* 
  59.              * AesManaged.BlockSize - 加密操作的块大小(单位:bit) 
  60.              * AesManaged.LegalBlockSizes - 对称算法支持的块大小(单位:bit) 
  61.              * AesManaged.KeySize - 对称算法的密钥大小(单位:bit) 
  62.              * AesManaged.LegalKeySizes - 对称算法支持的密钥大小(单位:bit) 
  63.              * AesManaged.Key - 对称算法的密钥 
  64.              * AesManaged.IV - 对称算法的密钥大小 
  65.              * Rfc2898DeriveBytes.GetBytes(int 需要生成的伪随机密钥字节数) - 生成密钥 
  66.              */  
  67.   
  68.             aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;  
  69.             aes.KeySize = aes.LegalKeySizes[0].MaxSize;  
  70.             aes.Key = rfc.GetBytes(aes.KeySize / 8);  
  71.             aes.IV = rfc.GetBytes(aes.BlockSize / 8);  
  72.   
  73.             // 用当前的 Key 属性和初始化向量 IV 创建对称加密器对象  
  74.             System.Security.Cryptography.ICryptoTransform encryptTransform = aes.CreateEncryptor();  
  75.   
  76.             // 加密后的输出流  
  77.             System.IO.MemoryStream encryptStream = new System.IO.MemoryStream();  
  78.   
  79.             // 将加密后的目标流(encryptStream)与加密转换(encryptTransform)相连接  
  80.             System.Security.Cryptography.CryptoStream encryptor = new System.Security.Cryptography.CryptoStream  
  81.                 (encryptStream, encryptTransform, System.Security.Cryptography.CryptoStreamMode.Write);  
  82.   
  83.             // 将一个字节序列写入当前 CryptoStream (完成加密的过程)  
  84.             encryptor.Write(data, 0, data.Length);  
  85.             encryptor.Close();  
  86.   
  87.             // 将加密后所得到的流转换成字节数组,再用Base64编码将其转换为字符串  
  88.             string encryptedString = Convert.ToBase64String(encryptStream.ToArray());  
  89.   
  90.             return encryptedString;  
  91.         }  
  92.     }  
  93. }  

2. 之后,在Silverlight页面获取config数据的时候,通过解密算法进行解密,得到真正的IP地址信息:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Documents;  
  8. using System.Windows.Input;  
  9. using System.Windows.Media;  
  10. using System.Windows.Media.Animation;  
  11. using System.Windows.Shapes;  
  12. using System.Security.Cryptography;  
  13. using System.IO;  
  14. using System.Text;  
  15.   
  16. namespace GetWebConfig  
  17. {  
  18.     public partial class MainPage : UserControl  
  19.     {  
  20.         private IDictionary<stringstring> _config;  
  21.         public MainPage()  
  22.         {  
  23.             InitializeComponent();  
  24.             _config = (Application.Current as App).Configurations;  
  25.             if (_config.Count > 0)  
  26.                 lblWebconfig.Content = "Web.config connectionString: " + Decrypt(_config.ElementAt(0).Key.ToString() + "==");  
  27.         }  
  28.   
  29.         /// <summary>  
  30.         /// 解密数据  
  31.         /// </summary>  
  32.         /// <param name="input">加密后的字符串</param>  
  33.         /// <returns>加密前的字符串</returns>  
  34.         public string Decrypt(string input)  
  35.         {  
  36.             // salt值(与加密时设置的值一致)  
  37.             string saltValue = "saltValue";  
  38.             // 密码值(与加密时设置的值一致)  
  39.             string pwdValue = "xuyue";  
  40.   
  41.             byte[] encryptBytes = Convert.FromBase64String(input);  
  42.             byte[] salt = Encoding.UTF8.GetBytes(saltValue);  
  43.   
  44.             System.Security.Cryptography.AesManaged aes = new System.Security.Cryptography.AesManaged();  
  45.   
  46.             System.Security.Cryptography.Rfc2898DeriveBytes rfc = new System.Security.Cryptography.Rfc2898DeriveBytes(pwdValue, salt);  
  47.   
  48.             aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;  
  49.             aes.KeySize = aes.LegalKeySizes[0].MaxSize;  
  50.             aes.Key = rfc.GetBytes(aes.KeySize / 8);  
  51.             aes.IV = rfc.GetBytes(aes.BlockSize / 8);  
  52.   
  53.             // 用当前的 Key 属性和初始化向量 IV 创建对称解密器对象  
  54.             System.Security.Cryptography.ICryptoTransform decryptTransform = aes.CreateDecryptor();  
  55.   
  56.             // 解密后的输出流  
  57.             MemoryStream decryptStream = new MemoryStream();  
  58.   
  59.             // 将解密后的目标流(decryptStream)与解密转换(decryptTransform)相连接  
  60.             System.Security.Cryptography.CryptoStream decryptor = new System.Security.Cryptography.CryptoStream(  
  61.                 decryptStream, decryptTransform, System.Security.Cryptography.CryptoStreamMode.Write);  
  62.   
  63.             // 将一个字节序列写入当前 CryptoStream (完成解密的过程)  
  64.             decryptor.Write(encryptBytes, 0, encryptBytes.Length);  
  65.             decryptor.Close();  
  66.   
  67.             // 将解密后所得到的流转换为字符串  
  68.             byte[] decryptBytes = decryptStream.ToArray();  
  69.             string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);  
  70.   
  71.             return decryptedString;  
  72.         }  
  73.     }  
  74. }  

最终实现效果如下,这时候我们通过查看源文件看到的则是被加密后的信息,而不是127.0.0.1,只有在Silverlight进行解密之后,才能看到我们想要的数据。

posted @ 2011-12-15 14:24  董雨  阅读(454)  评论(0编辑  收藏  举报