With this blog post I release an object-oriented PHP implementation of the RSA public key algorithm. The implementation is based on Edsko de Vries’ non-object-oriented implementation. Additionally to the object-orientation I reimplemented the signature methods which are now based on encrypted hashes instead of encrypting the whole message. This post shows you how to use this cryptographic PHP module, called rsa4php, and where to download it. Feel free to use it in your own programs under the terms of the GNU General Public Licence (GPL).
Get rsa4php
You can download the RSA distribution, called rsa4php, from files.oliver-mueller.com/pub/rsa4php as ZIP file and as tarball.
The licensing information you find inside the ZIP file and the tarball respectively as file gpl-2.0.txt
or alternatively at these sites:
http://www.gnu.org/licenses/gpl-2.0.txt
http://oliver-mueller.com/files/gpl-2.0.txt
Generating Keys
The RSA module does not contain any key generating functions yet (and maybe never will). To generate a key pair you can use OpenSSL. It is very easy with the Unix shell script genkey.sh
which is part of my rsa4php distribution.
This script expects the key length in bits as argument. To generate a RSA key pair with a key length of 2048 bits simply execute this command on your shell:
./genkey.sh 2048
This will create a file keyconf.php
which contains the key parameters. The content of such a file looks like this:
$ cat keyconf.php
<?php
$nx = "009d47d39934b6e1fc2e0e0e8b99c45f3e1736b817372df842f96f11c643e47e7065e7886b2399edfd04f74e71bdcc1dcc26a3bc96355b2ec510c19d4810e006d2460d7a2d33d0ef7e619b93d169d786fa0f26a0c22a46febbb944e6a5ce85810e468790dd576811cc7da02f572c7b499c457b863d49272057106d8b3afa3fcd71679c06619b97c666f01096a317de08c0cbb7330195b1a5276a8e317ce6d7c45ab12cd45b295f1e97c8603bbea91d21df516b3a8dd0d15a59a9adbf9e025879f5059a93950c8dd9926323e42c4a35fb1e6a48efc6ca3d8158184cfe60b56edc281abc37e975b0659ee71a7f8a3bb4211fc218257103d6e448dfd6bd178cdea999";
$ex = "010001";
$dx = "6dc7077324ef0d36c6327b8686d220a426f1c37638c67644d0f2ec56156733b561fb44257bd8e1dabb8f9e0a17ae9391bdda8533d6940945f5171e9f815fcc8311f03039c2b3efa5a79d3e84693accf45684e0aa05763e306af52383d16d2f91f63a832b6ae9b19aa88898e260a2c0d339502977374afef0a5ffbfb16f9ffed5335f5f400ca38576a171d01f5ce04a1896d3d66db7adf9561533bacfa74fa74c1982646b0aaccd4e21db19c451a826e8f00ad81728e10c5ac30d72593baba598e41d1c0bf2c57cb1172aaf9f7cd23f88344ddf686f17d4f725d8565cefa481af28a94c51215b73534942978c8fe0fc13f5f8c29540ba33d47d86904abcfd7a";
$lx = 2048;
?>
These four variables define a valid RSA public key pair. Variable nx
contains the modulus, ex
the public exponent, and dx
the private exponent. Last but not least variable lx
tells the key’s length in bits.
Creating an RSA Object
Based on the variables created by genkey.sh
you can create an RSA object. On a system providing 5.4 or later you can directly create the RSA object as follows:
$mykey = new RSA(hex2bin($ex), hex2bin($dx), hex2bin($nx), $lx);
If you are using an earlier PHP 5.x release you will have to use the following function to convert the hexadecimal strings to binary data:
function hex2bin($hex_str) {
$bin = '';
for($i = 0; $i < strlen($hex_str); $i+=2)
$bin .= chr(hexdec($hex_str[$i] . $hex_str[$i+1]));
return $bin;
}
With this function you can use exactly the same syntax as on PHP 5.4 and later where hex2bin()
is available by default.
If you want to create an RSA object representing a public key only, you will have to set the private exponent to "00"
:
$mypubkey = new RSA(hex2bin($ex), "00", hex2bin($nx), $lx);
Note: This is a simple workaround. Do not try to decrypt or sign messages with such a public-key-only object! It won’t work, of course, and the module will simply calculate rubbish without throwing some error indicating this special situation!
Encrypting and Decrypting Messages
Encrypting a message is very simple. You call the method encrypt()
of your RSA object with the message to be encrypted as parameter:
$cipher = $mykey->encrypt("Hello, world!");
To decrypt a cipher text to retrieve the plaintext again:
$plaintext = $mykey->decrypt($cipher);
Signing Messages and Verification of Signatures
Signing a message is an expensive operation if you use the whole message as input for signing. Therefore it is common to calculate a hash of the message and encrypt this hash with the private key. The resulting cryptogram is used as digital signature.
All these operations – calculating the hash and encrypting it – is done by method sign()
. This is a major change to the original implementation by Edsko de Vries. rsa4php’s method sign()
expects two parameters – the message to sign and a hashing algorithm.
The name of the hash algorithm is a string like "sha1"
, "sha256"
or "
snefru256
"
. A complete list of supported hash algorithm returns the PHP function hash_algos()
.
To sign a message use a call like this:
$signature = $mykey->sign($message, "sha256");
The following statement verifies a signature:
$match = $key->verify($message, $signature, "sha256");
$match
is a Boolean value indicating whether the signature matches (value true
) the message or not (false
).
How does this compare to phpseclib’s Crypt_RSA?:
http://phpseclib.sourceforge.net/rsa/intro.html
The RSA implementation of phpseclib is a full-featured cryptographic library. It supports several key formats such as PuTTY ssh keys, OpenSSH keys, and PKCS certificates. It also integrates well into different application scenarios.
The PHP module, which I released, is a simple small and lightweight implementation. I had demand for it in the context of a proof of concept and an essay about it. Caused by the fact that this module bases upon a free software implementation I gave my modifications back to the community–following the open-source idea.
If you ask about comparisons of the two implementations regarding performance or security issues I will have to confess I did not compare the two implementations (yet).
Thanks for all your efforts that you have put in this. Very interesting info. “Knowledge of what is possible is the beginning of happiness.” by George Santayana.
Nice work, but (there is always a ‘but’) why don’t you use base_convert($key, 16, 10) instead of first using hex2bin($key) and then using binary_to_number($key)?
Forgett my last comment…. I tried it and it does’nt work for big numbers… sorry 🙂
Yes, indeed. base_convert() works for “normal” integers only. Big integers make life always a bit harder… 🙂