RsaKeyDecryption.java for RSA Decryption Operation

This section provides a tutorial example on how to implement RSA decryption operation using the java.math.BigInteger class. The important part of the implementation is to use the same block sizes and padding schema as the encryption operation.

Before testing RsaKeyEncryption.java, let's finish the implementation of RSA decryption operation first. Here is my initial draft:

```/* RsaKeyDecryption.java
*/
import java.math.BigInteger;
import java.io.*;
class RsaKeyDecryption {
private BigInteger n, d;
public static void main(String[] a) {
if (a.length<3) {
System.out.println("Usage:");
System.out.println("java RsaKeyDecryption key input output");
return;
}
String keyFile = a[0];
String input = a[1];
String output = a[2];

RsaKeyDecryption encryptor = new RsaKeyDecryption(keyFile);
encryptor.decrypt(input,output);
}

// Reading in RSA private key
RsaKeyDecryption(String input) {
try {
while (line!=null) {
if (line.indexOf("Modulus: ")>=0) {
n = new BigInteger(line.substring(9));
}
if (line.indexOf("Private key: ")>=0) {
d = new BigInteger(line.substring(13));
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Modulus: "+n);
System.out.println("Key size: "+n.bitLength());
System.out.println("Private key: "+d);
}

// Decrypting cipher text
public void decrypt(String intput, String output) {
int keySize = n.bitLength();                       // In bits
int clearTextSize = Math.min((keySize-1)/8,256);   // In bytes
int cipherTextSize = 1 + (keySize-1)/8;            // In bytes
System.out.println("Cleartext block size: "+clearTextSize);
System.out.println("Ciphertext block size: "+cipherTextSize);
try {
FileInputStream fis = new FileInputStream(intput);
FileOutputStream fos = new FileOutputStream(output);
byte[] clearTextBlock = new byte[clearTextSize];
byte[] cipherTextBlock = new byte[cipherTextSize];
long blocks = 0;
int dataSize = 0;
blocks++;
BigInteger cipherText = new BigInteger(1,cipherTextBlock);
BigInteger clearText = cipherText.modPow(d,n);
byte[] clearTextData = clearText.toByteArray();
putBytesBlock(clearTextBlock,clearTextData);

dataSize = clearTextSize;
if (fis.available()==0) {
dataSize = getDataSize(clearTextBlock);
}
if (dataSize>0) {
fos.write(clearTextBlock,0,dataSize);
}
}
fis.close();
fos.close();
System.out.println("Decryption block count: "+blocks);
} catch (Exception ex) {
ex.printStackTrace();
}
}

// Putting bytes data into a block
public static void putBytesBlock(byte[] block, byte[] data) {
int bSize = block.length;
int dSize = data.length;
int i = 0;
while (i<dSize && i<bSize) {
block[bSize-i-1] = data[dSize-i-1];
i++;
}
while (i<bSize) {
block[bSize-i-1] = (byte)0x00;
i++;
}
}

// Getting data size from a padded block
public static int getDataSize(byte[] block) {
int bSize = block.length;
}
}
```

Some notes on RsaKeyDecryption.java:

• For RSA decryption operation, I only need to read in the private key.
• In order to recover the original cleartext, we have to use the same block sizes that were used in the encryption operation.
• I used "new BigInteger(1,cipherTextBlock)" to convert a byte array to a positive BigInteger by explicitly specifying the sign value.
• I used "cipherText.modPow(d,n)" to compute the decrypted integer.
• I used "clearTextData.toByteArray()" to dump the decrypted integer into a byte array with an extra sign bit included.
• The same method "putBytesBlock(byte[] block, byte[] data)" is used to package the decrypted integer value represented in a byte array into a fixed length byte block.
• I created a method "getDataSize(byte[] block)" to calculate the data size in the last block by excluding padded bytes.

Testing result is presented in the next tutorial.

Last update: 2013.