sitelink1 | |
---|---|
sitelink2 | |
sitelink3 | |
sitelink4 | |
extra_vars5 | |
extra_vars6 |
Using Public Key encryption in Java
I was having a look at how hard it is to encrypt something using asymmetric encryption (that is, public key / private key encryption) using Java. Turns out that it's not too hard at all, but as with all Java stuff it's a whole load of Factories and abstractions to get there. I also discuss how this stuff can be used with Domino, just so I can make this my first "Show and Tell Thursday" article!
Introduction
Sun added the Java Cryptography Extension (JCE) as an add-on for Java 1.2 and 1.3, and built it into Java 1.4 and later. JCE provides the framework and implementation for encryption and key management. For the purposes of this brief article I will be using OpenSSL for key management and only using JCE for encryption. JCE is a very broad framework and supports asymmetric encryption (which we'll be using), as well as shared secret key and regular passphrase based encryption.
Why?
The reason for this code was I was looking into the difficulty / possibility of doing encryption using a public key in Java. This public key would come from an external source, as a file, and we would be encrypting data that would be decrypted elsewhere. I also needed to know whether this would work in Domino. I know Domino has encryption stuff built in, but I wanted to be able to encrypt data that could be decrypted by other software.
Generating the keys
This isn't an article that will teach you the basics of encyrption, so if you don't understand the concepts of RSA encryption, public keys and private keys, you'd best do some reading first - the Public Key Cryptography article on Wikipedia could be a good starting point.
Firstly you need an RSA private and public key pair, this can be generated using openssl:
openssl genrsa -aes256 -out private.pem 2048
This generates a 2048-bit private key, encrypted using AES-256 (this is to give the key a passphrase to decrypt for access).
Then we generate a public key from this private key, we need this in DER format for use with the JCE API:
openssl rsa -in private.pem -pubout -outform DER -out public.der
Okay, now we're ready to use this with Java. This is a code fragment and will require some sort of code around it to actually compile and run, but I don't want to clutter this page up with all that extra. There's also no error checking, and the filenames are hardcoded. I'm sure you're all smart enough to work it all out and adapt it to your needs.
File keyFile = new File("public.der"); byte[] encodedKey = new byte[(int)keyFile.length()];new FileInputStream(keyFile).read(encodedKey);X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);KeyFactory kf = KeyFactory.getInstance("RSA");PublicKey pk = kf.generatePublic(publicKeySpec);Cipher rsa = Cipher.getInstance("RSA");rsa.init(Cipher.ENCRYPT_MODE, pk);OutputStream os = new CipherOutputStream( new FileOutputStream("encrypted.rsa"), rsa);Writer out = new OutputStreamWriter(os);out.write("Hello World!!");out.close();os.close();
You can decrypt the resulting file using your private key:
openssl rsautl -decrypt -in encrypted.rsa -inkey private.pem
You'll need to enter the passphrase for the private key and you should see your string.
Now this is just very basic code, but at least provides a base to work from. Have a look at the javax.crypto.Cipher class for other operations you can perform, mainly on byte arrays, to encrypt data without writing to a file. Obviously using the right OutputStream you don't need to write to a file using the CipherOutputStream stuff either. Have a look around the JCE API docs, there's lots of good stuff there.
Obviously if you wanted to decrypt something the code would still be similar however you'd be using DECRYPT_MODE, CipherInputStream, a DER version of the private key. You'd need to work out how to give it the passphrase for the key, which I haven't researched. It might be a two-step process where you have to decrypt the private key using the passphrase first, and then use the decrypted key to decrypt the RSA public key encrypted data (phew!).
Using with Domino
I have found that this code works with Domino 7 (which has the Java 1.4 JVM) as-is. The RSA implementation is provided by the IBM security providers. The code above works in a Java Agent without any additional libraries required. Example usage could be where you want to encrypt the data in a document using a public key which is then exported to another system which uses the private key to decrypt it.
With Domino 6.5 you'll need to download JCE 1.2.2 as an add-on from the Sun site. It does require some extra security tweaking and I didn't get a chance to try it out, but it should theoretically work! JCE 1.2.2 includes an RSA provider. Make sure you read the INSTALL document, as it has important stuff on security policy required for JCE to work. Java 1.4+ is much, much, easier for all this!