用RSA加密實現Web登錄密碼加密傳輸

通常我們做一個Web應用程序的時候都需要登錄,登錄就要輸入用戶名和登錄密碼,並且,用戶名和登錄密碼都是明文傳輸的,這樣就有可能在中途被別人攔截,尤其是在網吧等場合。

這裏順帶一個小插曲,我以前有家公司,辦公室裝修時候安排的網口相對較少,不太夠用,於是我和另外一個同事使用了一個hub來共享一個網口,這就導致了很有趣的現象:任何他的網絡包我都能抓得到,當然了,我的他也能抓得到。這是不是有很大的安全隱患了?我有可能在不經意間會泄漏自己的密碼。

所以,很多安全要求較高的網站都不會明文傳輸密碼,它們會使用https來確保傳輸過程的安全,https是用證書來實現的,證書來自於證書頒發機構,當然了,你也可以自己造一張證書,但這樣別人訪問你的網站的時候還是會遇到麻煩,因爲你自己造的證書不在用戶瀏覽器的信任範圍之內,你還得在用戶瀏覽器上安裝你的證書,來讓用戶瀏覽器相信你的網站,很多用戶並不知道如何操作,就算會操作,也能也不樂意幹;另一種選擇是你向權威證書頒發機構申請一張證書,但這樣有一定的門檻,還需要付費,也不是我們樂意乾的事。

所以,我打算自己實現一個密碼加密傳輸方法。

這裏使用了RSA非對稱加密算法,對稱加密也許大家都已經很熟悉,也就是加密和解密用的都是同樣的密鑰,沒有密鑰,就無法解密,這是對稱加密。而非對稱加密算法中,加密所用的密鑰和解密所用的密鑰是不相同的:你使用我的公鑰加密,我使用我的私鑰來解密;如果你不使用我的公鑰加密,那我無法解密;如果我沒有私鑰,我也沒法解密。

我設計的這個登錄密碼加密傳輸方法的原理圖如下:

 

首先,先演練一下非對稱加密:

[csharp]  view plain  copy
  1. static void Main(string[] args)  
  2. {  
  3.     //用於字符串和byte[]之間的互轉  
  4.     UTF8Encoding utf8encoder = new UTF8Encoding();  
  5.   
  6.     //產生一對公鑰私鑰  
  7.     RSACryptoServiceProvider rsaKeyGenerator = new RSACryptoServiceProvider(1024);  
  8.     string publickey = rsaKeyGenerator.ToXmlString(false);  
  9.     string privatekey = rsaKeyGenerator.ToXmlString(true);  
  10.               
  11.     //使用公鑰加密密碼  
  12.     RSACryptoServiceProvider rsaToEncrypt = new RSACryptoServiceProvider();  
  13.     rsaToEncrypt.FromXmlString(publickey);  
  14.     string strPassword = "@123#abc$";  
  15.     Console.WriteLine("The original password is: {0}", strPassword);  
  16.     byte[] byEncrypted = rsaToEncrypt.Encrypt(utf8encoder.GetBytes(strPassword), false);  
  17.     Console.Write("Encoded bytes: ");  
  18.     foreach (Byte b in byEncrypted)  
  19.     {  
  20.         Console.Write("{0}", b.ToString("X"));  
  21.     }  
  22.     Console.Write("\n");  
  23.     Console.WriteLine("The encrypted code length is: {0}", byEncrypted.Length);  
  24.   
  25.     //解密  
  26.     RSACryptoServiceProvider rsaToDecrypt = new RSACryptoServiceProvider();  
  27.     rsaToDecrypt.FromXmlString(privatekey);  
  28.     byte[] byDecrypted = rsaToDecrypt.Decrypt(byEncrypted, false);  
  29.     string strDecryptedPwd = utf8encoder.GetString(byDecrypted);  
  30.     Console.WriteLine("Decrypted Password is: {0}", strDecryptedPwd);  
  31. }  

大家可以清楚看到,密碼被加密成128字節長度的密文,爲什麼是固定128字節呢?這是因爲我們的RSACryptoServiceProvider默認生成的key的長度是1024,即1024位的加密,所以不管你要加密的密碼有多長,它生成的密文的長度肯定是128字節,也因爲這樣,密碼的長度是有限制的,1024位的RSA算法,只能加密大約100個字節長度的明文,要提高可加密的明文的長度限制,就得增加key的長度,比如把key改到2048位,這樣能加密的明文的長度限制也就變爲大概200出頭這樣……還是太少啊!而且這樣會帶來加密速度的顯著下降,RSA本來就很慢……是的,比同沒有長度限制的對稱加密,這種非對稱加密的限制可真多,即便是200個字符,又能傳輸什麼東西呢?——密碼!這個就夠了,傳輸完密碼之後,我們就使用對稱加密,所以,RSA往往是用來「協商」一個對稱加密的key的。

接下去,真正的難點在於用javascript實現一個和.net的RSA兼容的算法。密碼學,對我來說真像天書一般,每次我一看就頭大,這個工作是沒辦法自己做的了,只能到網上找,那是相當的費力啊,找到許多js的RSA實現,但都和.net的這套東西不兼容,最後還是功夫不負有心人,終於找到了一套。不多說,上代碼:

[html]  view plain  copy
  1. <html xmlns="http://www.w3.org/1999/xhtml">  
  2. <head runat="server">  
  3.     <title>RSA Login Test</title>  
  4.     <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>  
  5.     <script src="Scripts/jQuery.md5.js" type="text/javascript" ></script>  
  6.     <script src="Scripts/BigInt.js" type="text/javascript"></script>  
  7.     <script src="Scripts/RSA.js" type="text/javascript"></script>  
  8.     <script src="Scripts/Barrett.js" type="text/javascript"></script>  
  9.     <script type="text/javascript">  
  10.         function cmdEncrypt() {  
  11.             setMaxDigits(129);  
  12.             var key = new RSAKeyPair("<%=strPublicKeyExponent%>", "", "<%=strPublicKeyModulus%>");  
  13.             var pwdMD5Twice = $.md5($.md5($("#txtPassword").attr("value")));  
  14.             var pwdRtn = encryptedString(key, pwdMD5Twice);  
  15.             $("#encrypted_pwd").attr("value", pwdRtn);  
  16.             $("#formLogin").submit();  
  17.             return;  
  18.         }  
  19.     </script>  
  20.   
  21. </head>  
  22. <body>  
  23.     <form action="Default.aspx" id="formLogin" method="post">  
  24.     <div>  
  25.         <div>  
  26.             User Name:  
  27.         </div>  
  28.             User Name:  
  29.         </div>  
  30.         <div>  
  31.             <input id="txtUserName" name="txtUserName" value="<%=postbackUserName%>" type="text" maxlength="16" />  
  32.         </div>  
  33.         <div>  
  34.             Password:  
  35.         </div>  
  36.         <div>  
  37.             <input id="txtPassword" type="password" maxlength="16" />
相關文章
相關標籤/搜索