+44 (0) 7918 168 992

Online Solutions Development Blog   |  

RSS

PHP RSA encryption and decryption

posted by ,
Categories: PHP
Taggs , , , , ,

In this post I will give you a simple example of RSA encryption and decryption using php. I guess that if you searched for this you already know what RSA is. If you don’t there’s a great article on it on wikipedia.

You will find yourself sometimes in need of an encryption algorithm that would allow anyone to encrypt some data but only a certified authority to decrypt it. This is one of the usages for this algorithm and it’s one of the best for this.

Requirements

In order to keep this script as simple as possible you will need php’s gmp extension.

This will help you to handle big numbers.

Algorithm

The most important/hard part of this algorithm is getting the public and private keys. And for this all we need is to “translate” the steps you can find in that wikipedia article to php. I won’t even bore you with this here, you will find the function called get_rsa_keys inside a full working example available for download at the end of this post.

You will also need another function to get the modular multiplicative inverse of a number. I must say that I got the function from the same wikipedia some time ago (it’s not available now for some reason) and changed it a bit as it had a bug.

This other function will also be available in the code provided and it will have the name modinverse.

RSA Encryption

This will be very easy. After you will have the needed keys (public and private) anyone that knows the public key can use it to encrypt a secret using this function:

function rsa_encrypt($message, $public_key_d, $public_key_n)
{
	$resp = gmp_powm($message, $public_key_d, $public_key_n);
	return $resp;
}

So he just needs to pass the message and the public key and that simple function will do everything. Yes, that simple.

RSA Decryption

Now it’s your part: the guy that has the private key. Someone should have provided you an encrypted string generated using your public key and you are the only one that can decrypt this to get the original secret. You will need to use this function:

function rsa_decrypt($value, $private_key_e, $public_key_n)
{
	$resp = gmp_powm($value, $private_key_e, $public_key_n);
	return $resp;
}

Just as simple as the encryption.

Usage

The typical usage for this algorithm is to generate the keys once, save the private key so that you are the only one to have access to it, and provide the public key to the people that want to send you encrypted messages (or use them in another algorithm on your application).

Notice that the values returned by the get_rsa_keys are d, e, n.

  • n will be part of both the public and the private key.
  • Any of the two values e and d can be the other part of the keys.

In this script I recommended d as a public key because it is bigger (and the public key must be bigger than the secret).

For more details on the security and different usages of this algorithm check the wikipedia article.

In this full working example you will find everything you need to run this algorithm in just 80 lines. Don’t worry, only 3 of them are there for using the algorithm, you can just copy the functions in your project an call them.

The first one – getting the keys:

list($public_key_n, $public_key_d, $private_key_e) = get_rsa_keys();

The second one – encrypt a secret message:

$encrypted = rsa_encrypt($secret, $public_key_d, $public_key_n);

The third and last – decrypt the message using the private key

$decrypted = rsa_decrypt($encrypted, $private_key_e, $public_key_n);

Update: after following the work of Igor Feghali (check the comments below) that wanted to make more than just an example from this I found out that I must warn you about security threats caused by this approach. If you follow his link available below you will come at some point to this page that shows why this sample can’t be used in “real” applications. This post will be available here for learning purposes only but the comments are closed as of now and I don’t encourage you to use this script for anything more than testing or learning.

If you liked this post
you can buy me a beer

19 Responses to PHP RSA encryption and decryption

  1. But how can I encrypt simple strings such as email addresses or other strings? Your code returns me a simple zero!

    Thanks

    • Thanks for your comment.
      Yes, that script will return zeros when you will use strings and that’s because it was written to encrypt numbers only.
      That’s what the RSA algorithm is meant for.
      So in order to use it for strings you will need a way to “transalate” your string to a big number.
      You can use the ascii values for each character in your string with php’s function ord.
      If you do this be careful about the length of each character’s representation.
      As you can see here http://www.asciitable.com/index/asciifull.gif 3 digits can be used to save any character.
      Long story short:
      Take your string, for each character get its ascii value, if that value is less than 100 add some 0 before (1 or 2 depending on the character), create a big number (in fact a string with all these values concatenated) and use that as your secret.
      When you want to read the decryption output you must do the reverse: for each 3 characters in the number you get use php’s function chr
      I hope this helps. Fell free to ask if you need more details.

  2. If you want to encode/decode from strings:


    $secret = gmp_init('0x'.bin2hex('your secret message'));

    $encrypted = rsa_encrypt($secret, $public_key_d, $public_key_n);
    $decrypted = rsa_decrypt($encrypted, $private_key_e, $public_key_n);

    $decrypted_string = pack('H*', gmp_strval($decrypted, 16));

  3. bin2hex can also be replaced by:


    $secret = gmp_init('0x'.implode(unpack('H*', 'your secret message')));

    • Hello, Igor. Thank you for your contribution in this discussion by pointing out these solutions. After your suggestion I updated the sample script and uploaded a new version of it here.

  4. Would you mind if I rewrite/pack your code into a PEAR package and release it (keeping proper credits) ?

    • Sure, no problem. If you say that you will keep the credits I would be more than happy to have a contribution to your package. Please post a link here when you complete your work for us to see it also.

      • Great, thank you. Please email me with the name and email address which I should give the credits. I will post the link as soon as I have filled the package proposal.

  5. hi, thank u .it`s perfect 🙂

    • I am glad it helps 🙂

      • I have some problem . I want to create dual signature.
        so I need to encrypt, hash data ! but data encrypted with your function cant decrypt again!!!

        • Hello, Afsane.
          Sorry, but I don’t know what you mean. I have two problems in understanding what you want to do:
          1) you say that you want to hash the data after you encrypt it. From what I know you can’t reverse a hash algorithm (hash functions are just ways to map large sets of data to smaller, constant length blocks)
          2) even if the above issue was a misunderstanding: let’s say you encrypt a string A with the above algorithm and you get a string B. At this point if you use another algorithm to get a string C from B as long as you are able to get back B from C, you should be able to get A from B also, since the algorithms are independent.
          The above examples were tested and I did not find any problems, so if you found one please be more specific.
          Also, if you want to use this algorithm on text please use the solution provided by Igor Feghali in one of the comments above.

  6. HI Mishu.
    this is what I want to do:
    Dual Signature = rsa[ H(H(PI) || H(OI)) ]
    H = SHA1()
    DS = dual signature
    PI= payment information
    OI = order information
    rsa = (I use of your founction )
    || = contact
    but I think problem is because of longest result of sha1().
    I used of Lgor solution. It work perfect for small texts but SHA1 returns long result that your function cant manage that.
    I don`t know why!!!

    • Hello, Afsane.
      You can see in the article, in the usage paragraph, that “the public key must be bigger than the secret”.
      When using this type of algorithms to encrypt large sets of data you need to split it into blocks of a constant size. It was not the object of this article to cover every way this algorithm can be used as there are a lot, but I am sure that you can find a way to split your secret in pieces in such a way that you would know at the time of the decryption how to get the initial value back.

      • Hi Mishu , ya i had seen before u said me.
        I supposed you can find a solution for that 🙂
        In any case, thank u so much for your function and replies 😉

  7. hi
    I wrote this code for my prob and it`s work nice , everybody can use this after hash with SHA1() because SHA1() create same length string all of the times 🙂 :

    $signature = sha1(sha1($data['peymanet']) . sha1($data['order']));
    $secret = str_split($signature, strlen($signature)/2);
    $secrets[0] = gmp_init('0x'.bin2hex($secret[0])); // set a secret to encrypt/decrypt
    $secrets[1] = gmp_init('0x'.bin2hex($secret[1])); // set a secret to encrypt/decrypt

    $encrypted1 = rsa_encrypt($secrets[0], $public_key_d, $public_key_n); // apply the encryption
    $encrypted2 = rsa_encrypt($secrets[1], $public_key_d, $public_key_n); // apply the encryption
    echo "encrypt1:".gmp_strval($encrypted1) . ''; // show the encrypted output
    echo "encrypt2:".gmp_strval($encrypted2) . ''; // show the encrypted output
    $decrypted1 = rsa_decrypt($encrypted1, $private_key_e, $public_key_n); // decrypt knowing the secret key
    $decrypted2 = rsa_decrypt($encrypted2, $private_key_e, $public_key_n); // decrypt knowing the secret key
    echo "decrypt:" . pack('H*', gmp_strval($decrypted1, 16)) . pack('H*', gmp_strval($decrypted2, 16));// and this should match the secret.. and it does :)