RSA encryption in Java (ctd)
On the previous page, we introduced RSA encryption,
a form of asymmetric encryption.
We saw how to generate an RSA key pair in Java.
The key pair consisted of a public key that we gave to all clients, and a private key
that we kept secret on the server. Thus, any client can generate a message that our server— and
only our server (or somebody who has access to the private key)— can decrypt.
Encryption
The Java code to perform RSA encryption uses a Cipher object, just as with
AES encryption. However, this time, we want to initialise the cipher
with the public key that we previously saved to file. We use a KeyFactory as before,
reversing the process we went through when saving the key. So we'll pull out the two BigIntegers
from the file, wrap an RSAPublicKeySpec object around them,
and run that through a KeyFactory instance to generate a corresponding Key object:
PublicKey readKeyFromFile(String keyFileName) throws IOException {
InputStream in =
ServerConnection.class.getResourceAsStream(keyFileName);
ObjectInputStream oin =
new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
Then, we can use this PublicKey object to initialise a Cipher
and encrypt some data. Note that this time, we specify RSA as the required
cipher algorithm. Then, we proceed as with symmetric encryption:
we initialise the cipher in encryption mode with our key (in this case, the RSA
public key), and call doFinal(), passing in the data to be encrypted:
public byte[] rsaEncrypt(byte[] data) {
PublicKey pubKey = readKeyFromFile("/public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(src);
return cipherData;
}
The resulting cipherData is the encrypted data and can be safely sent
over the wire to the client.
Decryption
The server goes through a very similar process, and the code is trivially similar
to the client's. The server reads in its modulus and
exponent from its private key file and constructs a corresponding
RSAPrivateKeySpec object, using a KeyFactory to translate it into a
PrivateKey. This PrivateKey can then be used to initialise
a Cipher in DECRYPT_MODE.
Next: key sizes
We now have more or less all the information we need to use RSA encryption.
However, one important issue that we've glossed over so far is key length.
On the next page, we'll discuss RSA key length
and how to choose an appropriate size.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.