Monday 17 December 2007

Form submit weirdness in Opera 9.20

Here's one for you:

I have a few input form elements on a page, one of them is of type 'submit'. Because I don't use a form to submit this information, I set an event listener for one of the inputs like so: onkeypress="if(event.keyCode==13)myAction()" so that if enter is pressed, an action is performed. Similarly for the 'submit' input onclick="myAction()", so if the button is clicked the same action will be performed.

Here's what happens: if the enter key is pressed in the text control, myAction is executed twice. It's executed only once if I click on the button...

I investigated the problem and here are a few observations:

  • If the type of the submit element is changed to 'button' the action is performed only once when enter is pressed, as expected

  • If I remove the event listener from the text input element and leave the type of the 'submit' element unchanged, myAction is executed only once, as expected

  • What happens in myAction does not affect the form elements in any way, myAction can be replaced with alert

  • This behaviour doesn't happen in Firefox

  • In Firefox, only if the elements are in a form (and they are not in my case) then the form is submitted when enter is pressed in one of the text input elements



My conclusion: Opera detects a 'submit' element and launches a click event on it when enter is pressed in one of the text input elements, assuming that they're all part of a form. I think this is not something a web developer would expect, would you?

I need the event listeners for Firefox, so I'm going to change the submit element to 'button' which is more appropriate anyway.

Sunday 16 December 2007

RSA encryption

I recently started to develop a new web application. I want this one to run many windows, only one web page loaded fully at the beginning: index.php. Once this is loaded all the communication will take place AJAX style through the httpRequest object.

One of the challenges was authentication. SSL is out of the question, because I don't want any page refreshing or browser redirection and I also want to enable the user to keep the state of their windows in case the session expires. The logging in must happen through a window that asks for the user name and the password, sends the information to the server and if the credentials match, log the user in, keeping all the previously opened windows with all the data in them. Of course if a different user logs in, only public information will be kept in the browser, not information marked as private by the previous user.

I don't want the password to travel on the internet in plain text, I want to encrypt just the password. I don't want to slow down the interaction by using some very slow encryption algorithm that takes a lot of time to complete.

Before I made my decision, I had searched for some ways to encrypt information with JavaScript and I had found a lot of websites (here's an example) that provide encryption algorithms that require keys. I don't understand what's the purpose of these algorithms, if they require a key which needs to be sent to the client on the internet, then an attacker can intercept the key as well and decrypt the information with no problem. Perhaps they are designed just for use by one person offline to encrypt some data and store it somewhere along with the key?!?

One secure way to authenticate people to my web application could have been, MD5 encryption on the client side and sent to the server to compare to the stored MD5 of the password. There are several problems with this method:

  1. the md5 can be intercepted and sent in the future by the attacker to log in as the victim.

  2. if you have an md5 hash and you want to know the text it represents, find a site that stores md5 hashes and search for it, if the password is pretty weak, it's a good chance you'll decrypt it.

  3. we use LDAP to log in people and ldap requires plain text password to be sent to it, so storing just the md5 is out of the question.



RSA is by far the most popular cryptosystem and it's very secure. Because even though it requires some key exchange, there's a private key involved that doesn't travel between the server and the client. The most comprehensive and complete web site I found on this subject is this. I'm not going to talk too much about RSA, about how it works and why it's secure. Gaurav Saini's article explains everything.

The code Gaurav provided in his article encrypts and decrypts a number. What you need more is a way to generate the keys and a way to transform texts to numbers. As I said, I wanted something good enough without sacrificing speed (I'm not developing web applications for banks and the data used in this future web application is not very sensible). So instead of working with huge prime numbers as SSL does and generating them on demand, I chose to take a big list of prime numbers from this website, making sure that their product won't exceed JavaScript's integer upper limit. That saves a lot of processing time and to be sure they're not easy to guess, they are chosen randomly and assigned to either p or q with each request to the log in form.

I had to create a php version for the decrypt function as well, because their product and the 'phi' value is sent to the client from the server, the client encrypts the password and the server decrypts it upon receiving the information from the client. The password is then sent to the LDAP server along with the user name.

Transforming the text into numbers is the easy part. There are many ways, but I chose to use text.charCodeAt(i) to get the unicode code of each character, encrypt it using the key provided earlier by the server, put the codes together with a char delimiter, decrypt each code on the server and transform it to character using html_entity_decode('&#'.$code.';',ENT_NOQUOTES,'UTF-8');.

I had a tiny problem with php because php's upper limit on integers is a lot smaller than JavaScrpt's. I wanted to use the GMP library to work with large numbers, but unfortunately php5-gmp can not be installed on Ubuntu JeOS :-( so I found another one that comes bundled with PHP5, MCMath which worked like a charm.

A more complete RSA implementation that works with large numbers can be found at this address, but it's not very well explained. This version is interesting, instead of encrypting each character, it uses a key of a fixed length, takes chunks of the text transformed to the digit code, adds the bit shifted value of the corresponding position of the key to make a large string of digits which is treated as a number and encrypted. However this algorithm relies on a Delphi library to generate the key, which needs to be changed depending on what you use on the server side.

Please tell me about your unique and innovative way of sending passwords from client to server.