Record of some of the computer tech I deal with so that it's documented at least somewhere.

Thursday 22 September 2011

SSL Encryption in PHP Without HTTPS

This all started because the EU decided that one can't use cookies without authorisation, so how to hand state around a website without client side storage.

I investigated some things and played with SSL.

It works like this :

plain -> encryption with public key -> cipher

cipher -> decryption with private key -> plain

or

plain -> encryption with private key -> cipher

cipher -> decryption with public key -> plain

Using this mechanism one can envisage a system where two entities can communicate by first exchanging public keys and then encrypted data that only the recipient can decrypt.

First off we're going to need some keys. These are generated using the openssl command line tools.

% openssl genrsa -out private.pem 1024 % openssl rsa -in private.pem -out public.pem -outform PEM -pubout

If you're feeling fruity you can keep them both in the same file, remembering not to send it when you mean to just send the public part !

% cat private.pem public.pem | tee sslkeys.pem -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDnv6zntTRDw9r0O2wJWrzyfyeVO/++9JaXAq6M60uKKNGK/Lhe j4rrMYyN4l8arUBWJBHLaAn9VPHymXA9VdoXaPIGu+YS9fhraKUkz3eXcQhxgPXx xAkyzOMsyEbLt7E9rQ9r9cNZVJ7rQBwloY0WHjYsZGBoT2fZI8wzz1+jTwIDAQAB AoGAVnoAxCmqygqgfnhZ9Rel3/swwxAze4b7VnhKuAzpEDHxFyL8jVSU6vR/VUZ+ ZI73re0hsrws1hpHelZlOo35pgLZif230IgpNfZwYnvil4nTSa9oFXAr11ta/T0g NJwxc7HovZhtwWn9vE5abRMPiZ2HAXzL5gBXjT7DsaHuNVECQQD2Tftl08GdxtVh RNNEkHmoLHyXvfR8HLP7veGK9nGrZRhWVAqGEeKTiSw7YbMFr3Yss99o7m1fMlnP Y9e3jsxJAkEA8N8Da2hlK+p2uNnAIukslRB4Z8VyqIWA7fNYB8u2PMO8Xsxi27NU MNzmk69Yz2JCpmn+TiPY/3SSmS81qw2C1wJBAMA2SyJEBqziJlMqKtUvCkG7td+V Vd4laC/lFsYjXMGsuzljjHLkMjWArwwISnT9YPOxy39P0fqgiIXYHNgakEECP0Hc uRKleQSJF+1znRXurEIWPtYhJzjtSFPINknraekznE5PlLh+UIcL4ACB8cbDF3Zp hR/YrX0sYul//yzGhQJAaFvthOCajq0el+aa4xMCsrtNnvFSSXSLDbAZsK0HPcpF mVUe3tRX0dsTZ0ant35PMAEYMQhgxB9s9G+/Un/c/g== -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnv6zntTRDw9r0O2wJWrzyfyeV O/++9JaXAq6M60uKKNGK/Lhej4rrMYyN4l8arUBWJBHLaAn9VPHymXA9VdoXaPIG u+YS9fhraKUkz3eXcQhxgPXxxAkyzOMsyEbLt7E9rQ9r9cNZVJ7rQBwloY0WHjYs ZGBoT2fZI8wzz1+jTwIDAQAB -----END PUBLIC KEY-----

OBVIOUSLY don't use it for anything sensitive !

You can generate pem files that are passworded too, probably a good idea, when I find out how to do it, I'll post an update. The code below would then use openssl_get_privatekey($pem, $passphrase);

On to the PHP bit

All very simple really :

<?php function private_encrypt($pem, $plain) { openssl_get_privatekey($pem); openssl_private_encrypt($plain, $cipher, $pem); return $cipher; } function private_decrypt($pem, $cipher) { openssl_get_privatekey($pem); openssl_private_decrypt($cipher, $plain, $pem); return $plain; } function public_encrypt($pem, $plain) { openssl_get_publickey($pem); openssl_public_encrypt($plain, $cipher, $pem); return $cipher; } function public_decrypt($pem, $cipher) { openssl_get_publickey($pem); openssl_public_decrypt($cipher, $plain, $pem); return $plain; } ?>

You can use either the combined sslkeys.pem or the appropriate public.pem / private.pem files for $pem

Do not keep the private part or combined file in your webspace

$cipher is binary so if you want to send it over text channels you will need to base64_encode it or something

e.g.

<?php function encode($plain) { static $pem; if(!$pem) $pem = file_get_contents("/etc/ssl/sslkeys.pem"); return base64_encode(public_encrypt($pem, $plain)); } function decode($cipher) { static $pem; if(!$pem) $pem = file_get_contents("/etc/ssl/sslkeys.pem"); return private_decrypt($pem, base64_decode($cipher)); } ?> the static keyword means that the value of the variable is preserved between function calls

What to use it for

Well as it happens, I'm using it to talk to Paypal. You can sent a custom string from your Buy button and this will be sent back to you later. So I'm sending the buyer an encrypted transaction code, they send it to Paypal and then I get it back from Paypal. Like many things in the world of encryption it's easy to be fooled into thinking things are more secure than they are. But hey, at least no-one knows what I'm sending :)

Another thing that can be done is if I encrypt something with my private key, you can decrypt with my public key. By doing this you know only I (or someone who has stolen my private key :) has sent the message. If I encrypt it with your private key first then no-one else can read it except you.

I could even base64 it, upload it to pastebin, and post the URL - like so http://pastebin.com/kSnWgzHs

Then linking you and I together is much, much harder.

RIPA can lick my balls.

No comments: