Click here to Skip to main content
Click here to Skip to main content

Client/Server Encryption plus extras

, 19 Aug 2005
Rate this:
Please Sign up or sign in to vote.
Shows how to implement an RSA encryption algorithm on a server and client environement, even through a web browser!

Introduction

Today, security on our applications is a big issue. Companies have dedicated personnel whose sole job is to critique your code and make sure that the best of the best hackers can’t break into your site or application. On a recent project, my Information Security Officer (ISO), days from implementation, sprung on me that a password could be seen being sent across the network using Microsoft’s Network Monitor (or NetMon, as it is more commonly known). Because my work was not limited to this single application, I needed a way to securely pass plain text values from a client to a server in both EXE applications and web application. Oh, and there wasn’t any money to buy an SSL certificate… that would have been an easy way out.

Two-way encryption for executables has been increasingly easier to do with the Cryptography classes of the .NET framework. However, when I found no easy way to use these cryptography classes on a web client. You may be thinking why not just use the .NET cryptography classes then? Well, believe me, I tried. But when we need to execute code through a web browser on a client’s PC, you can understand the challenge. I would have had to come up with some way of guaranteeing that the client PC had the .NET framework installed, and even if they did, how do I execute the code? Because of that simple reason, I had to come up with my own version of the RSA algorithm (with much help from Paul Johnston).

In a nutshell, here is what I came up with… a complied .NET DLL (with COM Interop) that can encrypt data on a web client with JavaScript using a public key of a derivative of the known RSA encryption algorithm. In addition, the dll can be used by .NET executable application, COM executable applications and even COM web applications!

Now that you know why I had to re-write the RSA algorithm, let’s take a look at it...

Code

To begin, any algorithms I know of that have to do with encryption handle incredibly large numbers, even higher than a 64 bit long integer. To handle these long numbers, I used a version of the BigInteger class (slightly altered to handle a larger radix), found here on The Code Project. You can see how that works at the link above but I wanted to give credit where credit is due, plus, now you know what BigInteger is in the code below.

If you check out Paul Johnston’s site, you’ll understand that there’s 3 parts to an RSA public/private key pair. N and E are known as your public Key, E and D are known as your private key. You can encrypt with N and E, but can only decrypt if you have the part D. Below is one of the overloads in the dll to create this key pair:

public Encryption(int bitSize)

{if (!((bitSize == 8) | (bitSize == 16) | (bitSize == 32) | (bitSize == 64) | 
(bitSize == 128) | (bitSize == 256) | (bitSize == 512)))
{
throw new ArgumentException("Encryption supports only 8, 16, 32, " + 
    "64, 128, 256, 512 bit encryption");
};
 // I only want to allow certain bit lengths. Note that the higher the
 // bit length the longer the computation time

 BigInteger q;
 BigInteger p;
 BigInteger m;
 
 p = BigInteger.genPseudoPrime(bitSize,10,new System.Random()); 
 do
 {
 q = BigInteger.genPseudoPrime(bitSize,10, new System.Random());
 }
 while(p == q); 
 _key.N = (p*q);
 m = (p-1)*(q-1); 
 _key.E = new BigInteger("10001", 16);
 _key.D = _key.E.modInverse(m);
}

Now, that I have a key pair, I can encrypt and decrypt virtually anything. For a web application, you can store all 3 parts in the session variable, and use N and E to encrypt, where the server has access to D to do the decryption!

So how do we encrypt? Here’s where it gets tricky? First I’ll show you how to it’s done mathematically in the dll. Then I’ll show you how this can be done on the client.

public BigInteger[] Encrypt(string message )
{
 if ((_key.E == 0) || (_key.N == 0)) {

   throw new ApplicationException("Invalid Key");};
 int i ;
 byte[] temp = new byte[1] ; 
 byte[] digits = System.Text.ASCIIEncoding.ASCII.GetBytes(message); 
 BigInteger[] bigdigits = new BigInteger[digits.Length] ; 
 for( i = 0 ; i < bigdigits.Length ; i++ )
 {
temp[0] = digits[i] ;
bigdigits[i] = new BigInteger( temp ) ;
 } 
 BigInteger[] encrypted = new BigInteger[bigdigits.Length] ; 
 for( i = 0 ; i < bigdigits.Length ; i++ )
encrypted[i] = bigdigits[i].modPow( _key.E,_key.N) ; 

 return( encrypted ) ;
}
So how do we do this on the client? Good old JavaScript. You may be thinking: hey, I can view JavaScript source code in a web browser. How is that secure? You’re right you can see the JavaScript code through a web browser, but all we are going to do on the client is encryption. To encrypt we only need the public key: E and N. The missing part D is hidden from the user at all times. The code behind, or ASP, or any other server code has access to this D variable through the session state to do all the decryption. At this point you may ask: Why use the session state? Why not create a key pair, and use that all the time to make it more efficient? Well, that was my initial thought too until a colleague pointed out that he could easily capture the encrypted values from the form as it is posted back to the server, and use those same values at a later time to post back to the server. That would have worked fine because the hacker could have just made a simple script to POST that encrypted data to the web login page, and it would have been decrypted properly because the private key never changed. By using the session variables, any time a new session starts, that client has it’s own unique public and private key pair. Now even if you captured the encrypted values, they would be worthless because the private key would be different when a new session is opened. 99% of the code is how JavaScript implements the BigInteger class. This code came from http://www.leemon.com/. I won’t publish that here, because you can get it from the source files. To encrypt though, here’s what we do. We’ve opened our session to the web site, new keys are made for us. My server code page calls the GetJavaScriptClientCode from the DLL which can be used to write out to the client page. This includes all the BigInteger code and the small piece for encryption:
function Encrypt (str, n, e) {
 var n=str2bigInt(n,16,0);
 var x=str2bigInt(str,95,n.length);
 var y=str2bigInt(e,16,0);
 powMod(x,y,n,0);
 x = bigInt2str(x,16);
 return x;
 }

We can now add a password box for the password the user enters, and a hidden field that will have the encrypted data:

<INPUT type="submit" value="Login" OnClick="var s = txtPassword.value; 
password.value=Encrypt(s,'<%=Session("n")%>','<%=Session("e")%>'); 
var strStar = ''; for (i = 0; i < s.length; i++) {strStar = strStar + '*';}  
txtPassword.value = strStar">
<input id="password" type="hidden" name="password">
This code calls the JavaScript encrypt function, replaces the value of the original password with a bunch of *’s, and assigns another hidden variable the actual encrypted password. I did the * thing to make the encryption invisible to the user. If I replaced the password that they typed with the encrypted values, the lengths would be obviously different. The little function above simply replaces their password in the textbox they typed it in with * characters the same length as the password they entered. Then end result is 2 parameters being posted to the form: password which will be equal to the actual encrypted password, and txtPassword, which is merely a bunch of * characters. The server code will care about the password variable.

Decrypting is a little more complex than then encryption, but follows the general RSA algorithm rules. Here’s the code for the decrypt function, which resides in the DLL:

public string Decrypt( BigInteger[] encrypted )
{
 if (_key.D == 0) {throw new ApplicationException("Invalid key");};
 int i ; 

 BigInteger[] decrypted = new BigInteger[encrypted.Length] ;
 
 for( i = 0 ; i < decrypted.Length ; i++ ) 
decrypted[i] = encrypted[i].modPow((_key.D),(_key.N)) ; 
 char[] charArray = new char[decrypted.Length] ; 
 for( i = 0 ; i < charArray.Length ; i++ )
charArray[i] = (char) ( (byte)decrypted[i].IntValue() ) ; 
 return( new string( charArray ) ) ;
}

Conclusion

Security can be a difficult task to tackle in many applications. I hope that this article and my code help you in your applications, and whatever requirements they have.

Updates

  • 1/16/04 - Added sample source code for web implementation in source download file
  • 1/16/04 - Added a feature to the forms control to load machine name if no domains are available.
  • 1/16/04 - Fixed an issue with namespace inconsistencies (see thread below).
  • 8/19/05 - Latest update (version 1.2.2.0) has the ability to query user properties and change passwords within ActiveDirectory or LDAP.

Extras!

Also included in the DLL code, is a class called Authentication. The methods in this class talk to directory services or LDAP (LDAP wasn’t tested), to authenticate a user in a specified domain, as well as get whatever properties for the user. It also allows you to get SID’s of users, and other cool stuff. Also, there is a windows control (see image) that can be used on any .NET exe to implement a universal logon screen for your applications. That control obviously is integrated with the Authentication class. If you want an article on any of these please ask by posting to this article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Domenic
Web Developer
United States United States
I've been writing software applications since the early 90's from ASP and VB5 to C# and ASP.NET. I am currently working on law enforcement and criminal justice applications delivered over the web. I've always been astounded by the fact that the only 2 industries that refer to customers as "users" are narcotics and software development. Wink | ;-)

Comments and Discussions

 
QuestionDecryption? PinmemberMember 989676016-Mar-13 4:05 
Generaldouble or more encryption Pinmemberchuxs2-Sep-10 1:25 
GeneralRe: double or more encryption PinmemberDomenic2-Sep-10 2:15 
GeneralRe: double or more encryption Pinmemberchuxs2-Sep-10 7:38 
GeneralFile not found Pinmembergaurav_misra5-Jul-08 2:24 
GeneralRe: File not found PinmemberDomenic7-Jul-08 2:20 
GeneralNice article, need some suggestions. Pinmemberspinoza15-Jan-07 23:50 
GeneralRe: Nice article, need some suggestions. PinmemberDomenic16-Jan-07 2:28 
Question.NET framework ? Pinmemberstixoffire14-Jul-06 9:46 
GeneralString length Pinmemberitobob130-Jun-06 3:43 
GeneralDoenst work on a mac PinmemberEntDevGuy25-Apr-06 13:26 
General0A0B0C -> Encrypt -> decrypt -> A0B0C Pinmemberzoltix14-Feb-06 21:42 
GeneralRe: 0A0B0C -> Encrypt -> decrypt -> A0B0C PinmemberDomenic28-Feb-06 2:25 
AnswerRe: 0A0B0C -&gt; Encrypt -&gt; decrypt -&gt; A0B0C [modified] PinmemberDan Randolph22-May-09 6:02 
GeneralRe: 0A0B0C -> Encrypt -> decrypt -> A0B0C PinmemberScarfish12-Feb-07 23:40 
GeneralAny benchmark data Pinmemberhanofee3-Feb-06 5:51 
GeneralRe: Any benchmark data PinmemberDomenic3-Feb-06 5:55 
Generalplease help me Pinmemberaaku21-Dec-05 6:48 
GeneralRe: please help me PinmemberDomenic21-Dec-05 6:52 
GeneralWhy not use the Capicom.dll from MSFT Pinmemberjreddy19-Aug-05 9:05 
GeneralRe: Why not use the Capicom.dll from MSFT PinmemberDomenic22-Aug-05 3:01 
GeneralObject reference not set to an instance of an object Pinmemberwormbyte18-Aug-05 2:01 
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic18-Aug-05 7:41 
GeneralRe: Object reference not set to an instance of an object PinsussAnonymous18-Aug-05 9:32 
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic18-Aug-05 9:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 19 Aug 2005
Article Copyright 2003 by Domenic
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid