RSA: Encrypting in JavaScript and Decrypting in PHP

I came across a really cool JavaScript library a while back that allows you to do client-side RSA encryption & decryption. If you don’t know much about RSA, read up on it here. Essentially, it’s an algorithm for public/private key encryption/decryption. You encrypt using the Public Key and Modulus and decrypt using the Private Key and Modulus.

More often than not, you would want to encrypt client-side (browser) and decrypt server-side. For my purposes, I wanted to encrypt passwords 13 characters or less in JavaScript and decrypt them in PHP. The creator of the RSA library also created a convenient Windows application that generates RSA keys for you. Using that program I created the following 128bit keys:

e = Public Key = 553799486327459813656784787218239817 (6aa86c39bbe678f7f7967a587a1149)
d = Private key = 1401845535567450041611005523755666809 (10dfc5235ef69148bdfdc6832860d79)
m = Modulus = 11570601966616835094916890432003700913 (8b46ab8a951615d07b66bdd2420f8b1)

By default the RSA library outputs encrypted strings in Hex, but because there is no built in PHP function to convert from Hex to Binary, I decided to modify the RSA.js file slightly (within the encryptedString function – line 62) to output the full Integer:

var text = key.radix == 16 ? biToDecimal(crypt)/*biToHex(crypt)*/ : biToString(crypt, key.radix);

The Key Generator also conveniently creates the JavaScript needed to create the new key pair. I’ve removed the decryption (Private) key:

setMaxDigits(19);
key = new RSAKeyPair(“6aa86c39bbe678f7f7967a587a1149″, “”, “8b46ab8a951615d07b66bdd2420f8b1″);
w.value = encryptedString(key,”1234567890123″ + “\x01″);

The trick here is adding “\x01″ to the end of the string you want to encrypt. The PEAR library used to decrypt the encrypted string will look for this, and throws an error if not found. That said, the above encrypted string is:

1276850306890326374886324100793107985

The PEAR package used to decrypt this string is called Crypt_RSA. You install this just like any other PEAR package:

PEAR install Crypt_RSA

The package depends on one of 3 Math libraries (BCMath, GMP or big_int), of which BCMath is slowest but installed by default (at least in my version of PHP 5.2.0-8+etch13 & XAMPP-win). The Crypt_RSA package works in binary, so the keys and encrypted text needs to be converted before calling the package. The following code converts the Integers to Binary and performs the decryption. Bare in mind your dealing with very large numbers, so you need to use one of the above Math libraries to work with them.

require_once ‘Crypt/RSA.php’;
//
$wrapper_name = “BCMath”;
$math_obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name);
//
$d = $math_obj->int2bin(“1401845535567450041611005523755666809″);
$m = $math_obj->int2bin(“11570601966616835094916890432003700913″);
//
$pk = new Crypt_RSA_Key($m, $d, “private”, $wrapper_name);
$rsa_obj = new Crypt_RSA;
$rsa_obj->setParams(array(‘dec_key’ => $pk));
$dec = $rsa_obj->decryptBinary($math_obj->int2bin(“1276850306890326374886324100793107985″));
echo $dec;

You can download my sample code here.

Related Articles:

Have a second? Check out this great Canadian Health & Living Store based in Toronto

23 Responsesto “RSA: Encrypting in JavaScript and Decrypting in PHP”

  1. hiren says:

    I need to encrypt my html form data by public key which is then stored in database in encrypted form & when user wants to view it , the data will fetch from database and decrypted on browser by user’s private key.

    How can I achieve it? can yoy please help mw out?

    With Regards
    Hiren

  2. Eun says:

    Is it posible without the pecl package? Maybe with a class like http://www.phpclasses.org/browse/package/4121.html ?

  3. dennis says:

    I have try your sample code. it work fine. but original data seems can’t exceed 13 bytes.
    I want send about 100 bytes to server. How can I change the limitation.

    Best regards

    Dennis

  4. George A. Papayiannis says:

    Dennis, I hear you – I’m not sure – if you find out, let me know…

  5. Steven says:

    To encrypt longer strings you have to insert the “\x01″ in at the end of every chunk.
    Try this in the Javescript:

    setMaxDigits(19);
    // Put this statement in your code to create a new RSA key with these parameters
    key = new RSAKeyPair(
    "6aa86c39bbe678f7f7967a587a1149",
    "",
    "8b46ab8a951615d07b66bdd2420f8b1"
    );
    s = trim("supersuperlongstringtoencrypt");
    sl = s.length;
    var i = 0;
    var a = "";
    while (i < sl)
    {
    if ((i+1) % key.chunkSize == 0)
    a += "\x01";
    a += s.charAt(i);
    i++;
    }
    if ((i+1) % key.chunkSize != 0)
    a += "\x01";

    w.value = encryptedString(key, a);

  6. panda says:

    thanks for your share! i really need such informations!

  7. Zashkaser says:

    I’m glad that after surfing the web for uch a long time I have found out this information. I’m really lucky.

  8. Roberto says:

    Steven, I’m not able to have your advice for long string running correctly! Anyone encountered the same problem and has a solution?

  9. Emmanuel says:

    Thanks, I’ve been looking for this..

  10. George A. Papayiannis says:

    Hi Roberto,

    I wasn’t able to get Steven’s code to work exactly either – I changed it around a bit and managed to now be able to encrypt string less than 24 – 26(?) characters (check that). Here is the function directly from a JS class that I made – if anyone knows how to make this work for any size string please post the code.


    encrypt: function(s) {
    setMaxDigits(19);
    var key = new RSAKeyPair("", "", "");
    var sl = s.length;
    var i = 0;
    var j = 1;
    var a = "";
    while (i < sl) {
    if ((i+1) % key.chunkSize == 0) {
    a += "\x01";
    j++;
    }
    a += s.charAt(i);
    i++;
    }
    if ((i+1) % key.chunkSize != 0 || (i+1) == (key.chunkSize * j)) {
    a += "\x01";
    }
    return encryptedString(key,a);
    },

  11. Hristo says:

    Hello,

    i’m trying to do following:
    1.) Create private and public key pairs with PEAR Crypt_RSA
    2.) Sign a dummy message using the public key from 1.) but in C# application (i’m using base64_encode($public_key->getModulus()) and base64_encode($public_key->getExponent()) in php and after that manually creating an .NET xml private key using the two strings for Modulus and Exponent xml nodes)
    3.) Decrypt the message encrypted from C# app. but again in PHP and PEAR Crypt_RSA from 2.)

    I’m stuck at point 3.)…… Crypt_RSA aways says that the tail is invalid

    the code which i use in my C# app. is:

    // I did adding of “\x01″ in the end of the string as you are advising above
    string inputString = “hello\x01″;
    string xmlString = “r+7rlF0e/v2n9Pj1muEkyxnrLqMsWf9AWWSwx3RY9QfuD71u1xfLmuu46HuATZtxxq3QVqGwKF6Fm5Z4ATUSjg==AQAB”;
    RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
    rsaCryptoServiceProvider.FromXmlString(xmlString);
    // The length of certificate is 1024 so i do not need here to try split the input string to chunks
    byte[] resultByteArray = rsaCryptoServiceProvider.Encrypt(Encoding.ASCII.GetBytes(inputString), false);
    return Convert.ToBase64String(resultByteArray);

    Please, if anyone can give a hand here – do it i’m almost tired to do tests with no luck :-)

    Thanks in advanced & cheers!

  12. shrui says:

    Thanks for your share, George. Now I generate key-pair with Crypt_RSA. The code like this:
    function genKey($keylen){
    require_once(‘Crypt/RSA.php’);
    $wrapper = “GMP”;//or other
    $math_obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper);
    $key_pair = new Crypt_RSA_KeyPair($keylen);
    if (!$key_pair->isError()){
    $public_key = $key_pair->getPublicKey();
    $private_key = $key_pair->getPrivateKey();
    $e = gmp_strval($math_obj->bin2int($public_key->getExponent()));
    $d = gmp_strval($math_obj->bin2int($private_key->getExponent()));
    $m = gmp_strval($math_obj->bin2int($public_key->getModulus()));
    mysql_query(“update conftab set e=’”.$e.”‘,d=’”.$d.”‘,m=’”.$m.”‘”);
    }
    }
    Another function converts e and m to hex string for JavaScript’s encrypt
    function. The MaxDigits depeneds on $keylen in PHP code.
    function gmp_dechex($num){
    $result = ”;
    do{
    $result = sprintf(‘%02x’,intval(gmp_mod($num,256))).$result;
    $num = gmp_div($num, 256);
    }while(gmp_cmp($num, 0));
    return ltrim($result,’0′);
    }

    Best regards

    shrui

  13. shrui says:

    to coutomize my own encrypt exponent, with a little change to the original code:

    function generate($key_len = null, $pubexp = null)//apply the second parameter
    //...
    //original code in KeyPair.php(CRYPT_RSA-1.0.0): line 245~271{
    if($pubexp != null&&$this->_math_obj->cmpAbs($pubexp,2)>0)
    $e = $this->_math_obj->nextPrime($this->_math_obj->dec($pubexp));
    else{
    while(true){
    $e = $this->_math_obj->getRand($q_len, $this->_random_generator);
    if ($this->_math_obj->cmpAbs($e,2)_math_obj->nextPrime($this->_math_obj->dec($e));
    break;
    }
    }
    do{
    $p = $this->_math_obj->getRand($p_len, $this->_random_generator, true);
    $p = $this->_math_obj->nextPrime($p);
    do{
    do{
    $q = $this->_math_obj->getRand($q_len, $this->_random_generator, true);
    $tmp_len = $this->_math_obj->bitLen($this->_math_obj->mul($p, $q));
    if ($tmp_len $key_len) $q_len--;
    } while ($tmp_len != $key_len);
    $q = $this->_math_obj->nextPrime($q);
    $tmp = $this->_math_obj->mul($p, $q);
    } while ($this->_math_obj->bitLen($tmp) != $key_len);
    // $n - is shared modulus
    $n = $this->_math_obj->mul($p, $q);
    // generate pubexp ($e) and private ($d) keys
    $pq = $this->_math_obj->mul($this->_math_obj->dec($p), $this->_math_obj->dec($q));
    }while($this->_math_obj->cmpAbs($this->_math_obj->mod($pq,$e),0)==0);//mod() is a new method
    //original code in KeyPair.php(CRYPT_RSA-1.0.0): line 245~271}

  14. shrui says:

    [code] destroy code....
    function generate($key_len = null, $pubexp = null)//add the second parameter $
    //...
    //original code in KeyPair.php(CRYPT_RSA-1.0.0): line 245~271{
    if($pubexp != null&&$this->_math_obj->cmpAbs($pubexp,2)>0)
    $e = $this->_math_obj->nextPrime($this->_math_obj->dec($pubexp));
    else{
    while(true){
    $e = $this->_math_obj->getRand($q_len, $this->_random_generator);
    if ($this->_math_obj->cmpAbs($e,2)_math_obj->nextPrime($this->_math_obj->dec($e));
    break;
    }
    }
    do{
    $p = $this->_math_obj->getRand($p_len, $this->_random_generator, true);
    $p = $this->_math_obj->nextPrime($p);
    do{
    do{
    $q = $this->_math_obj->getRand($q_len, $this->_random_generator, true);
    $tmp_len = $this->_math_obj->bitLen($this->_math_obj->mul($p, $q));
    if ($tmp_len $key_len) $q_len--;
    } while ($tmp_len != $key_len);
    $q = $this->_math_obj->nextPrime($q);
    $tmp = $this->_math_obj->mul($p, $q);
    } while ($this->_math_obj->bitLen($tmp) != $key_len);
    // $n - is shared modulus
    $n = $this->_math_obj->mul($p, $q);
    // generate pubexp ($e) and private ($d) keys
    $pq = $this->_math_obj->mul($this->_math_obj->dec($p), $this->_math_obj->dec($q));
    }while($this->_math_obj->cmpAbs($this->_math_obj->mod($pq,$e),0)==0);//mod() is a new method
    //original code in KeyPair.php(CRYPT_RSA-1.0.0): line 245~271}

  15. elsehair says:

    Using what essentially amounts to null padding on plaintexts means that the techniques described here are about as secure as ECB mode for block ciphers. ie. it’s not all that secure. Personally, I think OAEP padding ought to be used. PEAR’s long since abandoned Crypt_RSA doesn’t support it but phpseclib’s Crypt_RSA does:

    http://phpseclib.sourceforge.net/

  16. fie says:

    php, hex to bin
    $bin_str = pack(“H*” , $hex_str);

  17. Mike says:

    Is it possible to link your javascript to working with this library?
    http://phpseclib.sourceforge.net/

    Is there a way to specify the key size when generating the public & private keys? 128bit is very insecure for an assymetric algorithm.
    http://en.wikipedia.org/wiki/Key_size#Asymmetric_algorithm_key_lengths

  18. franck says:

    It seems to work well, thanks for this good script. I am going to use it when submitting passwords to authenticate users without SSL. I am truying to change keys each time, but you have done the hardest work.

  19. Zaid Crowe says:

    none of the examples above seem to work for strings over 13 chars – and I can’t for the life of me work out why.

    Any one have any ideas/explanations?

  20. Tola Anjorin says:

    Please am having trouble decrypting the string in php.

    I think my problem is with the

    $m = $math_obj->int2bin(“11570601966616835094916890432003700913″);

    i think $m is supposed to be a string of binary, however, i get weird characters like y �2h�ߋi�5R� 

    please any idea?

  21. haleema says:

    hey,
    i was trying to encrypt in php & decrypt in javascript using the same method. but decryption in javascript is not giving back the proper output ,it is giving some special characters. can anybody pls tell me how to get bak de string in original format ?

  22. haleema says:

    encrypting in javascript & decrypting in php is working for me.

  23. tarcard says:

    Got some issues with the PHP libraries, since they are based on PHP4 and im currently using PHP5.2 … here’s the issue:

    Strict Standards: Non-static method Crypt_RSA_MathLoader::loadWrapper() should not be called statically, assuming $this from incompatible context in C:\xampp\php\PEAR\Crypt\RSA\Key.php on line 159
    Strict Standards: Only variables should be assigned by reference in C:\xampp\php\PEAR\Crypt\RSA\Key.php on line 159
    Strict Standards: Non-static method PEAR::isError() should not be called statically, assuming $this from incompatible context in C:\xampp\php\PEAR\Crypt\RSA\ErrorHandler.php on line 150
    Strict Standards: Non-static method Crypt_RSA_MathLoader::loadWrapper() should not be called statically, assuming $this from incompatible context in C:\xampp\php\PEAR\Crypt\RSA.php on line 191
    Strict Standards: Non-static method Crypt_RSA_MathLoader::loadWrapper() should not be called statically, assuming $this from incompatible context in C:\xampp\php\PEAR\Crypt\RSA\MathLoader.php on line 98

    Problem appears to be that PHP5 doesn’t like all those static calls to functions… Is there any easy way to handle this problem or changing the code in the libraries are the only option?

Leave a Reply

Line and paragraph breaks automatic.
XHTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>