Click here to Skip to main content
15,884,176 members
Articles / Web Development / ASP.NET
Article

Client/Server Encryption plus extras

Rate me:
Please Sign up or sign in to vote.
4.77/5 (26 votes)
19 Aug 20056 min read 288.3K   3.3K   103   116
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:

C#
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.

C#
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:
JavaScript
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:

HTML
<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:

C#
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


Written By
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

 
GeneralWhy not use the Capicom.dll from MSFT Pin
jreddy19-Aug-05 9:05
jreddy19-Aug-05 9:05 
GeneralRe: Why not use the Capicom.dll from MSFT Pin
Domenic22-Aug-05 3:01
Domenic22-Aug-05 3:01 
GeneralObject reference not set to an instance of an object Pin
wormbyte18-Aug-05 2:01
wormbyte18-Aug-05 2:01 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic18-Aug-05 7:41
Domenic18-Aug-05 7:41 
GeneralRe: Object reference not set to an instance of an object Pin
Anonymous18-Aug-05 9:32
Anonymous18-Aug-05 9:32 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic18-Aug-05 9:46
Domenic18-Aug-05 9:46 
GeneralRe: Object reference not set to an instance of an object Pin
wormbyte22-Aug-05 1:21
wormbyte22-Aug-05 1:21 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic22-Aug-05 2:36
Domenic22-Aug-05 2:36 
I can't imagine what it might be then. It works fine on my PC. The only thing I can think of is that the namespace inadvertantly changed or the file is not an embedded resource. Try putting code like this to find out what the resources are. There should be one called DJD.Security.BigInt.js. If there is not take a look at the project and look at the properties for that file within the DJD.Security project. Make sure that BuildAction is set to Embedded Resource.

If there's something similar listed, with a different namespace then you'll need to resolve the namespace conflict by either editing the GetJavaScriptClientCode function, or resetting the project to use the DJD.Security namespace. Good luck!

Here's the code to see the embedded resources:

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim f As System.Reflection.Assembly = System.Reflection.Assembly.GetAssembly(GetType(DJD.Security.Authentication))
Dim str() As String = f.GetManifestResourceNames
Dim strDisplay As String = f.GetName.Name & " has the following resources: " & vbCrLf & vbCrLf
For Each s As String In str
strDisplay &= s & vbCrLf
Next
MsgBox(strDisplay)
End Sub
GeneralRe: Object reference not set to an instance of an object Pin
wormbyte22-Aug-05 2:48
wormbyte22-Aug-05 2:48 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic22-Aug-05 2:57
Domenic22-Aug-05 2:57 
GeneralRe: Object reference not set to an instance of an object Pin
wormbyte22-Aug-05 3:21
wormbyte22-Aug-05 3:21 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic22-Aug-05 3:59
Domenic22-Aug-05 3:59 
GeneralRe: Object reference not set to an instance of an object Pin
wormbyte22-Aug-05 4:15
wormbyte22-Aug-05 4:15 
GeneralRe: Object reference not set to an instance of an object Pin
Domenic22-Aug-05 4:48
Domenic22-Aug-05 4:48 
Generalstring str = sec.GetJavaScriptClientCode(); error Pin
Member 1360532-Aug-05 4:03
Member 1360532-Aug-05 4:03 
GeneralRe: string str = sec.GetJavaScriptClientCode(); error Pin
Domenic4-Aug-05 2:24
Domenic4-Aug-05 2:24 
GeneralRe: string str = sec.GetJavaScriptClientCode(); error Pin
Member 1360539-Aug-05 2:24
Member 1360539-Aug-05 2:24 
GeneralExcellent Pin
Ahmed Erarslan17-Jun-05 23:37
Ahmed Erarslan17-Jun-05 23:37 
GeneralRe: Excellent Pin
Domenic20-Jun-05 2:30
Domenic20-Jun-05 2:30 
General1024 bit and ASP Pin
Member 16595601-Mar-05 1:23
Member 16595601-Mar-05 1:23 
GeneralRe: 1024 bit and ASP Pin
Domenic20-Jun-05 2:28
Domenic20-Jun-05 2:28 
GeneralRe: 1024 bit and ASP Pin
IPC200022-Aug-05 2:46
IPC200022-Aug-05 2:46 
GeneralRe: 1024 bit and ASP Pin
Domenic22-Aug-05 3:50
Domenic22-Aug-05 3:50 
GeneralFurther information Pin
Kreyten18-Nov-04 15:32
Kreyten18-Nov-04 15:32 
QuestionWhy not use the MS RSA objects? Pin
Kreyten16-Nov-04 22:53
Kreyten16-Nov-04 22:53 

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

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