RsaKeyEncryption.java for RSA Encryption Operation

This section provides a tutorial example on how to implement RSA encryption operation using the java.math.BigInteger class. The important part of the implementation is to determine the cleartext block size, ciphertext block size, and the padding of the last block.

Finally, we are ready to implement the RSA public key encryption operation using the java.math.BigInteger class. Here is my initial draft:

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

RsaKeyEncryption encryptor = new RsaKeyEncryption(keyFile);
encryptor.encrypt(input,output);
}

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

// Encrypting original message
public void encrypt(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;

while (dataSize>0) {
blocks++;
if (dataSize<clearTextSize) {
}

BigInteger clearText = new BigInteger(1,clearTextBlock);
BigInteger cipherText = clearText.modPow(e,n);
byte[] cipherTextData = cipherText.toByteArray();
putBytesBlock(cipherTextBlock,cipherTextData);
fos.write(cipherTextBlock);

}

blocks++;
BigInteger clearText = new BigInteger(1,clearTextBlock);
BigInteger cipherText = clearText.modPow(e,n);
byte[] cipherTextData = cipherText.toByteArray();
putBytesBlock(cipherTextBlock,cipherTextData);
fos.write(cipherTextBlock);
}

fis.close();
fos.close();
System.out.println("Encryption 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++;
}
}

public static void padBytesBlock(byte[] block, int dataSize) {
int bSize = block.length;
int padSize = bSize - dataSize;
for (int i=0; i<padSize; i++) {
}
}
}
```

Some notes on RsaKeyEncryption.java:

• For RSA encryption operation, I only need to read in the public key.
• The cleartext block size is calculated with "Math.min((keySize-1)/8,256)" as we decided in the previous section.
• The ciphertext block size is calculated with "1 + (keySize-1)/8" as we decided in the previous section.
• I created a method "padBytesBlock(byte[] block, int dataSize)" to pad the last block of the cleartext message.
• I used "new BigInteger(1,clearTextBlock)" to convert a byte array to a positive BigInteger by explicitly specifying the sign value.
• I used "clearText.modPow(e,n)" to compute the encrypted integer.
• I used "cipherText.toByteArray()" to dump the encrypted integer into a byte array with an extra sign bit included.
• I created a method "putBytesBlock(byte[] block, byte[] data)" to package the encrypted integer represented in a byte array into a fixed length byte block.
• The first loop in "putBytesBlock()" is to copy all magnitude bits from the integer data array into the block starting from the end of the array. The sign bit (should always be "0") is not copied, if the integer is large and its number of magnitude bits is the same as the block size in bits. Bit the sign bit is copied, if the integer is smaller.
• The second loop in "putBytesBlock()" is to pad those extra bytes at the beginning with "0x00", if the integer is small.

Testing result is presented in the next tutorial.

Last update: 2013.