To understand this application, we should understand the basic concept of Asymmetric Encryption.
In symmetric encryption, it has only one key and the same key is used to encrypt and decrypt the text.
But, in asymmetric encryption, it has 2 keys as,
o Public Key and
o Private Key.
If the Public key is used to encrypt the text, then it should be decrypted using Private Key.
If the Private Key is used to encrypt the text, then it should be decrypted using Public Key.
Can you imagine that how it is possible to encrypt the text using one key and decrypt it using another key? There should be a relationship in order to achieve it! Yes, there is a relationship in between Private Key and Public Key. That is, Public Key is generated using the Private Key.
To understand see Generation of RSA Key Pair
The application contains 3 Java classes as follows.
- · GenerateKeys.java – Handles all the key related functions.
- · Cryptography.java – Handles all the encryption and decryption processes.
- · Main.java – An Interface to interact with the user.
First will focus on GenerateKeys.java class.
It requires some other packages to be imported in order to do its’ tasks.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
Following variables were initialized as instance variables.
private KeyPairGenerator keyGen;
private KeyPair pair;
private PrivateKey privateKey;
private PublicKey publicKey;
Initialize the properties of the keys such as key length and key algorithm (RSA) in the constructor of GenerateKeys class.
public GenerateKeys(int keylength) throws NoSuchAlgorithmException,
NoSuchProviderException {
this.keyGen = KeyPairGenerator.getInstance("RSA");
this.keyGen.initialize(keylength);
}
Create the keys.
public void createKeys() {
this.pair = this.keyGen.generateKeyPair();
this.privateKey = pair.getPrivate();
this.publicKey = pair.getPublic();
}
Return the private key.
public PrivateKey getPrivateKey() {
return this.privateKey;
}
Return the public key.
public PublicKey getPublicKey() {
return this.publicKey;
}
Save the keys to a file in given path.
public void writeToFile(String path, byte[] key) throws IOException {
File f = new File(path);
f.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(f);
fos.write(key);
fos.flush();
fos.close();
}
Next, will focus on Cryptography.java class.
It also requires some other packages to be imported in order to do its’ tasks.
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.codec.binary.Base64;
Following variable is initialized as instance variables to store the encryption mode. (RSA)
private Cipher cipher;
Initialize the encryption mode to the above variable in the constructor of Cryptography class.
public Cryptography() throws NoSuchAlgorithmException, NoSuchPaddingException {
this.cipher = Cipher.getInstance("RSA");
}
Get the private key and public key created and stored earlier using GenerateKeys class.
//https://docs.oracle.com/javase/8/docs/api/java/security/spec/PKCS8EncodedKeySpec.html
public PrivateKey getPrivate(String filename) throws Exception {
byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
//https://docs.oracle.com/javase/8/docs/api/java/security/spec/X509EncodedKeySpec.html
public PublicKey getPublic(String filename) throws Exception {
byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
Encrypt the plain text to cipher text using Private Key
public String encryptText(String msg, PrivateKey key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException, IllegalBlockSizeException,
BadPaddingException, InvalidKeyException {
this.cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.encodeBase64String(cipher.doFinal(msg.getBytes("UTF-8")));
}
Decrypt the ciphertext to plain text using Public Key (Previously encrypted using Private Key)
public String decryptText(String msg, PublicKey key)
throws InvalidKeyException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
this.cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(Base64.decodeBase64(msg)), "UTF-8");
}
Above 2 functions were overridden to
· Encrypt the plain text to cipher text using Public Key
· Decrypt the cipher text to plain text using Private Key (Previously encrypted using Public Key)
Finally, in the Main.java class, an interface is created to invoke the above functions when it is needed.
Get the source code here! You can run it using NetBeans IDE.