Why Don’t You Use Public Key Encryption To Protect Your Data Sent From the Browser?

I recently asked a software developer why they didn’t encrypt sensitive data back to the back-end application. “Well, we use https, so…

Why Don’t You Use Public Key Encryption To Protect Your Data Sent From the Browser?

I recently asked a software developer why they didn’t encrypt sensitive data back to the back-end application. “Well, we use https, so it’s okay”. “But, before we get to the tunnel, and after it, anyone and anything can read the data. How can you know it is a trusted API you are dealing with?”. “Well, it’s not my problem, it’s up to https to do that”. Unfortunately we rely too much on machine-to-machine tunnels such as with SSL/TLS. These do not protect data from a malicious proxy running on the client machine or on the server.

“Why don’t you encrypt data in the browser?”, I then said. “But it will take too long!”, “Is a few thousandths of second a long time?”, “No, but we support mobile phones, and it’s not going to work”, So I demo’ed my Samsung S9 phone encrypting and decrypting in 27 ms using 1,024-bit RSA:

So while the key pair generation is certainly a time consuming process, the actual encryption and decryption in the browser (or on the server) can be done fairly quickly, and will thus protect the data from its source to the back-end application. No other entity on the way will then be able to read the data, and only the private key would decrypt the data.

Background

If I told you my RSA public key was:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmHGjSaciFL/20WAglW8WdGF0c
BbPsH6Q3m9Yw1sXSB7jqYvpWZR+GhQ2m54bLqSi7QcfpdeS9qYvG9ieBZXQ/r6eR
0vULpJ7AwKKdUGU5AWnx2D13b6O7snY2aIUg+gk2U3g+0/nSOBEODv8jhbLDDMhy
bBMOYp6CjrEONzclMwIDAQAB
-----END PUBLIC KEY-----

And you created a cipher message of:

ndVRez/bTbaCmx7ti/JuSJ5cfnU2kIUfzmLLee3tNr7N0TwgSjFiwj+ZwfuVOdCSDgMCabo9u1kQKwerYqLt2+/J3udGkGTCizoWhxMH89KNNe6n5VGNRrAnE5/xliHacp9vY4scNXQsHK5V+BQbVuBTuP7w6ZzwA2i6BSaXeDs=

Would you know how I would decipher it? Well, that’s the kinda thing we do on our MSc, and challenge our students to use public key encryption. The answer is, of course, to use my private to decrypt it. In this case my private key is:

-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgQCmHGjSaciFL/20WAglW8WdGF0cBbPsH6Q3m9Yw1sXSB7jqYvpW
ZR+GhQ2m54bLqSi7QcfpdeS9qYvG9ieBZXQ/r6eR0vULpJ7AwKKdUGU5AWnx2D13
b6O7snY2aIUg+gk2U3g+0/nSOBEODv8jhbLDDMhybBMOYp6CjrEONzclMwIDAQAB
AoGAVMpZo1ZF+d5mZaEt/0vaEnd2R7CNh/Ea1Rvh+KoY7j3s4Q/G80TJE9RlBJZY
Uys01Gkej4gTS9D4vYW24rET5f3jAFXkbBLXyAsqUKEi/lR/uDGU6RECLUjQ+wio
urUn2fbSnCeMmXkxGZMnQxLgl3RQdrd/awTROlrl3+YOX8ECQQDsEUv8uyG9sCDq
SXqbXiM07j9rVTR8Dc62FbzRIl42/pWyrZtgrdeAXKVbpAqxq8uJcCcSZd2Yone2
pXjlL+hhAkEAtCL4cKIUhFiBbyikoNfbmuzPs6GR9ues6UoXrCA+AbgWHLhHvcPy
p0crwvffYTA0Ku+VpiO5allZKqUWPjqmEwI/dDAPNlTkRnhpuuZvcgjjSyn4DNvi
+SvSkcwhIs3HkUm8ZDUORIdLieIPgQs8ODZV908769I3Pui4Ay1uU19BAkBZVqqu
ecQBKz/uWFLlroismlwcc7pHoPkBrox1AnyeL6VP0xlJhT/4NHUAuhxgQB7vWGl4
v2j61JtDaiLQ9BdfAkBnIz2VM9X0yZeVgNR1/yd18+4sD23p7vDshlpdcwRnKX5C
/VilnduGxO3VyuW7vJG29R67pYn5G/OyPyDjqhQT
-----END RSA PRIVATE KEY-----

And I get back “hello”.

And in the browser this time …

But you say. So can I do this is a browser? Yes. It’s quite easy. With the magic of JavaScript we can create our RSA key pair, and then encrypt and decrypt:


function trsa(word) {

var keySize =1024;

var dt = new Date();
var time = -(dt.getTime());
var crypt = new JSEncrypt({ default_key_size: keySize });

crypt.getKey();
dt = new Date();
time += (dt.getTime());

document.getElementById("key").innerHTML="";
document.getElementById("key").innerHTML += 'Key generated in ' + time + ' ms';
document.getElementById("key").innerHTML += "\nPrivate key:\n" +crypt.getPrivateKey();
document.getElementById("key").innerHTML += "\nPublic key:\n" +crypt.getPublicKey();

var dt = new Date();
var time = -(dt.getTime());

var cipher = crypt.encrypt(word);
var decipher = crypt.decrypt(cipher);
dt = new Date();
time += (dt.getTime());

document.getElementById("hash").innerHTML="";
document.getElementById("hash").innerHTML += 'Encrypt/decrypt in ' + time + ' ms';
document.getElementById("hash").innerHTML += "\nText:\t" +word;

document.getElementById("hash").innerHTML += "\nEncrypt with public key:\t" +cipher;
document.getElementById("hash").innerHTML += "\nDecrypt with private key:\t"+ decipher;


}


</script>

<script type="text/javascript" src="https://travistidwell.com/jsencrypt/bin/jsencrypt.js"></script>

I have used the Travisidwell.com JavaScript integration. You can find my demo here:

In our real code, we just add our public key, and encrypt our data, and send it back to the back-end application, and which has the private key to decrypt it.

Conclusions

Go on … generate those key pairs, and get encrypting your data in the browser. OpenSSL works great for generating the key pair, and you can just pop the public key into the JavaScript of your browser, and you’ll be one step toward living in a GDPR-era.

And if you don’t like RSA, then use ECC. And, if you support devices which will struggle with RSA and ECC, you just default something more simple. And simple test can determine if the device can use public key encryption or not. While public key encryption is not use for large amounts of data, for data posted from a form, it will normally be acceptable in its operation.