Click here to Skip to main content
6,295,667 members and growing! (9,980 online)
Email Password   helpLost your password?
General Programming » Cryptography & Security » Security     Intermediate

Client/Server Encryption plus extras

By Domenic

Shows how to implement an RSA encryption algorithm on a server and client environement, even through a web browser!
C#.NET 1.1, Win2K, WinXP, Win2003, ASP.NET, Visual Studio, Dev
Posted:20 Oct 2003
Updated:19 Aug 2005
Views:116,246
Bookmarked:89 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
24 votes for this article.
Popularity: 6.15 Rating: 4.45 out of 5

1
2 votes, 8.3%
2
1 vote, 4.2%
3
4 votes, 16.7%
4
17 votes, 70.8%
5

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 ; 
 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


Member
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
Occupation: Web Developer
Location: United States United States

Other popular Cryptography & Security articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 112 (Total in Forum: 112) (Refresh)FirstPrevNext
GeneralFile not found Pinmembergaurav_misra3:24 5 Jul '08  
GeneralRe: File not found PinmemberDomenic3:20 7 Jul '08  
GeneralNice article, need some suggestions. Pinmemberspinoza0:50 16 Jan '07  
GeneralRe: Nice article, need some suggestions. PinmemberDomenic3:28 16 Jan '07  
Question.NET framework ? Pinmemberstixoffire10:46 14 Jul '06  
GeneralString length Pinmemberitobob14:43 30 Jun '06  
GeneralDoenst work on a mac PinmemberEntDevGuy14:26 25 Apr '06  
General0A0B0C -> Encrypt -> decrypt -> A0B0C Pinmemberzoltix22:42 14 Feb '06  
GeneralRe: 0A0B0C -> Encrypt -> decrypt -> A0B0C PinmemberDomenic3:25 28 Feb '06  
AnswerRe: 0A0B0C -> Encrypt -> decrypt -> A0B0C [modified] PinmemberDan Randolph7:02 22 May '09  
GeneralRe: 0A0B0C -> Encrypt -> decrypt -> A0B0C PinmemberScarfish0:40 13 Feb '07  
GeneralAny benchmark data Pinmemberhanofee6:51 3 Feb '06  
GeneralRe: Any benchmark data PinmemberDomenic6:55 3 Feb '06  
Generalplease help me Pinmemberaaku7:48 21 Dec '05  
GeneralRe: please help me PinmemberDomenic7:52 21 Dec '05  
GeneralWhy not use the Capicom.dll from MSFT Pinmemberjreddy10:05 19 Aug '05  
GeneralRe: Why not use the Capicom.dll from MSFT PinmemberDomenic4:01 22 Aug '05  
GeneralObject reference not set to an instance of an object Pinmemberwormbyte3:01 18 Aug '05  
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic8:41 18 Aug '05  
GeneralRe: Object reference not set to an instance of an object PinsussAnonymous10:32 18 Aug '05  
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic10:46 18 Aug '05  
GeneralRe: Object reference not set to an instance of an object Pinmemberwormbyte2:21 22 Aug '05  
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic3:36 22 Aug '05  
GeneralRe: Object reference not set to an instance of an object Pinmemberwormbyte3:48 22 Aug '05  
GeneralRe: Object reference not set to an instance of an object PinmemberDomenic3:57 22 Aug '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 19 Aug 2005
Editor: Smitha Vijayan
Copyright 2003 by Domenic
Everything else Copyright © CodeProject, 1999-2009
Web19 | Advertise on the Code Project