01 March 2015

Security isn't a dirty word Blackadder

Hopefully we all understand the concepts behind asymmetric (Public / Private key) encryption. It’s something we use all the time (https, SSL etc) but I've never actually put code to screen and tried to implement it. I've always relied on standard symmetric-key algorithm. So I thought I’d give it a go in Java / Android and along the way I learned a lot. In this blog article I thought I’d outline a few things I've learned. I’ll put some code up as I go, but I’d like to try and focus a bit more on the lessons.
All security is equal, except some more equal than others
We all know in symmetric encryption DES is bad, right?
DES is now considered to be insecure for many applications
http://en.wikipedia.org/wiki/Data_Encryption_Standard#Brute_force_attack


Well in theory public / private key encryption is infinitely better as long as you never give out your private key. Easy peasy, so we choose one of these and away we go:
  • RSA
  • EIGamal
  • Diffie-Helman
So I want to take a basic string “All your base are belong to me” and I want to encrypt it using a public key and decrypt it using a private key.
Rush to code

Impatient as I am I rush to get some code in and find this code to try out:
byte[] data = readBytesFromfile(“mypublickey”);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data); 
KeyFactory kf = KeyFactory.getInstance("RSA");
pubKey = kf.generatePublic(keySpec);

Great, now I need a public and private key to test my amazing new code.

I learn a few bits about encryption

I’d heard of PGP and apparently this has no known weaknesses, perfect, I want this! So away I go and find a tool to generate my PGP public and private key. I throw these into my java code and straight away get an error. Hmmm. Something doesn't feel right here. Plus I'm not too sure about PGP and OpenPGP. OK back to wikipedia. Apparently PGP is a protocol, not an algorithm and for its asymmetric files it uses RSA anyway! Doh! So I resort to RSA and now I need to generate an RSA key.


So I've already got puttyGen installed and it I don’t know why it says SSH but it definitely says RSA right there with a big button saying “Generate”. Boom, surely this will work, nothing can stop me now!
Now I get a java error InvalidKeySpecException
Hmm, after some serious time googling I ask stack overflow
http://stackoverflow.com/questions/28218636/invalidkeyspecexception-using-public-key
Although it doesn't solve my problem, Maarten alerts me to the fact that in java I need to use the X509 format.
Hang on SSH is a protocol isn't it? (Back to wikipedia). Right ok so PGP and SSH are protocols that implement asymmetric encryption using the RSA algorithm. I don’t want a protocol, I want to just generate an encrypted string.


To do that I need a public key which java can read. So all I need is to generate a key in the right format….That makes sense.

Using KeyTool and OpenSSL to generate a 509 certificate


This doesn't take me long using java keytool and openssl to generate an x509 certificate.
keytool -genkey -keyalg RSA -keysize 1024 -keystore C:\temp\hello.keystore

keytool -importkeystore -srckeystore C:/temp/hello.keystore -destkeystore C:/temp/hello.p12 -deststoretype PKCS12

openssl pkcs12 -in C:/temp/hello.p12 -out C:/temp/hellonew.pem -nodes

openssl x509 -in C:/temp/hellonew.pem -inform PEM -out C:/temp/hellodernew.der -outform DER

Reading an X509 certificate
Now we need to adapt our code to read the key in the new format.
public static PublicKey getPublicKey(byte[] keyBytes){
    PublicKey publicKey = null;

    if(keyBytes != null) {

        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = null;
        try {
            kf = KeyFactory.getInstance("RSA");
            publicKey = kf.generatePublic(spec);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "NoSuchAlgorithmException");
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            Log.e(TAG, "InvalidKeySpecException " + e.getMessage());
            e.printStackTrace();
        }
    }

    return publicKey;
}

This means we can now use our PublicKey to encrypt our message! Wohoo


Decryption

To decrypt we use a similar function

    public static PrivateKey getPrivateKey(byte[] keyBytes){
        PrivateKey privatekey = null;

         if(keyBytes != null) {
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory kf = null;
            try {
                kf = KeyFactory.getInstance("RSA");
                privatekey = kf.generatePrivate(spec);
            } catch (NoSuchAlgorithmException e) {
                Log.e(TAG, "NoSuchAlgorithmException");
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                Log.e(TAG, "InvalidKeySpecException");
                e.printStackTrace();
            }
        }

         return privatekey;
    }


Encrypting a large file

For various reasons I've also learned you can’t just encrypt a file with your public key. This guy gives an excellent description of what you should be doing:


The basic idea is as such:
  1. Create a session key using symmetric encryption, AES for example.
  2. Then encrypt the file using this session key
  3. Using your public key encrypt the session key
  4. Send the AES encrypted file and the public key encrypted session key together
  5. Your server / recipient uses the private key they have and decrypts the session key then using that decrypts the file.


This method allows for fast encryption and secure transmission. If anyone brute forces the session key, they've only ever got one file. They need to start again for every single new file!

Anyway, that’s about what I've learned on this particular journey. I hope its of some help.