How to encrypt data transferred between web browser and server using RSA

บทนำ (Overview)

จุดประสงค์เพื่อต้องการเข้ารหัส (Encryption) ข้อมูลระหว่าง “Web browser” เช่น Internet Explorer และ “Firefox” เป็นต้น เนื่องจากการส่งผ่านข้อมูลโดยใช้ “HTTPs” โปรโตคอลนั้น ไม่สามารถป้องกันโปรแกรมประเภท “Proxy” ได้ เพื่อ “HTTPs” นั้นป้องกันในระดับชั้น “Transport”

หลักการ (Concepts)

โดยหลักการนั้น เราจะให้ “Server” ทำการสร้าง “Key” คู่โดยให้ “Public” ส่งไปยัง “Web browser” เสียก่อน จากนั้นเรียกใช้ “JavaScript” สำหรับเข้ารหัสข้อมูลจาก “Public key” ที่สร้างไว้ เมื่อข้อมูลเข้ารหัสเสร็จสิ้นก็จะส่งคืนกลับไปยัง “Server” และ “Server” จะทำหน้าที่ถอดรหัสโดยใช้ “Private key” เพื่อนำไปประมวลผลต่อไป

ขันตอน (Step)

  1.  สร้าง “Public key” และ “private key” ที่ฝั่ง “server” จากนั้นทำการจัดเรียง “Format” ของกุญแจโดยใช้ “Hex”
    public string getPubKey()
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            HttpRuntime.Cache["KeyPair"]= rsa.ToXmlString(true);
            RSAParameters param = rsa.ExportParameters(false);
    
            string keyToSend= ToHexString(param.Exponent) + "," +
                 ToHexString(param.Modulus);
            return keyToSend;
        }
    
    public static string ToHexString(byte[] byteValue)
    {
    	char[] lookup = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
    	'B', 'C', 'D', 'E', 'F' };
    	int i = 0, p = 0, l = byteValue.Length;
    	char[] c = new char[l * 2];
    	while (i < l)
    		{
    			byte d = byteValue[i++];
    			c[p++] = lookup[d / 0x10];
    			c[p++] = lookup[d % 0x10];
    		}
    	return new string(c, 0, c.Length);
    }
    
  2. ส่ง “Public Key” ให้ “web browser” โดยอาจส่งไปใน “hidden field” ของ “HTML” เพื่อสำหรับให้ “JavaScript” ทำการเข้ารหัสข้อมูล
    public partial class Login : System.Web.UI.Page
    {
        		protected void Page_Load(object sender, EventArgs e)
        		{
            	LoginService service = new LoginService();
            	txtPubKey.Text = service.getPubKey();
        		}
    }
    
  3. เข้ารหัสข้อมูลด้วย “Public Key” โดยใช้ “JavaScript” เมื่อเสร็จสิ้น ก็ส่งข้อมูลกลับไปประมวลผลที่ “server” สามารถดดาวน์โหลด Library ได้ที่ไปที่ URL(http://www-cs-students.stanford.edu/~tjw/jsbn/)
    function validateUser() {
    		    var pkey = $('#<%=txtPubKey.ClientID %>').val().split(',');
    			var rsa = new RSAKey();
    			rsa.setPublic(pkey[1], pkey[0]);
    			var username = rsa.encrypt($('#<%=UserName.ClientID %>').val());
    		    var pass = rsa.encrypt($('#<%=Password.ClientID %>').val());
    
    			$.ajax({
    				type: "POST",
    				url: "Services/LoginService.asmx/ValidateUser",
    				data: "{'encUsername':'" + username + "','encPassword':'" + pass + "'}",
    				contentType: "application/json; charset=utf-8",
    				dataType: "json",
    				success: function(data, status) { OnSuccessLogin(data, status); },
    				error: OnErrorLogin
    			});
    		}
    
  4. จากนั้นที่ “server” เราสามารถถอดรหัสด้วย “Private Key” จากที่ได้จำเอาไว้
       public string validateUser(string encUsername, string encPassword)
        {
            //read Key Pair (Public + Private Key) from Server-cache
            string domainKey = (string)HttpRuntime.Cache["KeyPair"];
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(domainKey);
            string username = Encoding.UTF8.GetString(rsa.Decrypt(ToHexByte(encUsername), false));
            string password = Encoding.UTF8.GetString(rsa.Decrypt(ToHexByte(encPassword), false));
    
            string r = "User (encrypted):" + Environment.NewLine + encUsername + Environment.NewLine;
            r = r + "User (plain-text):" + username + Environment.NewLine;
            r = r + "Password (encrypted):" + Environment.NewLine + encPassword + Environment.NewLine;
            r = r + "Password (plain-text):" + password + Environment.NewLine;
            return r;
        }
    
        public static byte[] ToHexByte(string str)
        {
    			byte[] b = new byte[str.Length / 2];
    			for (int y = 0, x = 0; x < str.Length; ++y, x++)
    			{
    				byte c1 = (byte)str[x];
    				if (c1 > 0x60) c1 -= 0x57;
    				else if (c1 > 0x40) c1 -= 0x37;
    				else c1 -= 0x30;
    				byte c2 = (byte)str[++x];
    				if (c2 > 0x60) c2 -= 0x57;
    				else if (c2 > 0x40) c2 -= 0x37;
    				else c2 -= 0x30;
    				b[y] = (byte)((c1 << 4) + c2);
    			}
    			return b;
        }
    

 สรุป (Conclusion)

จากการทดสอบผลว่าข้อมูลจะถูก Encrypted ดังรูปภาพ

rsa-web
ตัวอย่างการเข้ารหัส username และ password ด้วย RSA

ใส่ความเห็น