I'm having issues with my code.
What I am trying to do is encrypt a file using ECB Mode (meaning, encrypt blocks of text with no chaining into the next block).
It works perfectly sometimes, but sometimes it does not. The issue comes when it encrypts 128 bytes of data and writes 129 bytes. It will work perfectly up until the first time it does that, but then the decrypting will be off by a byte, and will mess everything up. I know this because when it goes wrong, you can see that cipher (on line 88, a byte array) is of length 129, not 128, and then it is written to file.
Here's an example of what I mean: Encrypt: testtesttesttesttesttesttest testtesttesttesttesttesttest testtesttesttesttesttesttest testtesttesttesttesttesttest testtesttesttesttesttesttest
Output: testtesttesttesttesttesttest testtesttesttesttesttesttest testtesttesttesttesttesttest testtesttesttesttesttesttest testtest(500 bytes of jumbled data)
I've attached my entire code; for quick run throughs, I've enabled decryption to produce to stdout right after encryption.
So simply run: -k key (will generate key.public and key.private) -e key.public -i input -o output (will encrypt some file input and store it in output, read that file, decrypt it, send to stdout).
Any help would be appreciated!
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Scanner;
import java.io.*;
import java.util.List;
import java.util.Random;
public class RSA {
public static void main(String[] args) throws UnsupportedEncodingException {
List<String> list = Arrays.asList(args);
if(list.contains("-h")) {
System.out.println("Usage:");
System.out.println("RSA -h - View command-line arguments.");
System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
} else if (list.contains("-k")) {
String key_file = "";
try {
key_file = list.get(list.indexOf("-k") + 1);
if(key_file.equals("-b")) {
System.out.println("Usage:");
System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
System.exit(1);
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage:");
System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
System.exit(1);
}
int bit_size = 0;
if(!list.contains("-b")) {
bit_size = 1024;
} else {
try {
bit_size = Integer.parseInt(list.get(list.indexOf("-b") + 1));
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Usage:");
System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
System.exit(1);
}
}
generate_key(bit_size, key_file);
} else if (list.contains("-e")) {
//get input file and output file
String input_file = "";
String key_file = "";
String output_file = "";
try {
input_file = list.get(list.indexOf("-i") + 1);
output_file = list.get(list.indexOf("-o") + 1);
key_file = list.get(list.indexOf("-e") + 1);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage:");
System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
System.exit(1);
}
String public_key = read_file(key_file);
String private_key = read_file("key.private");
BigInteger public_modulus = new BigInteger(public_key.substring(1, public_key.indexOf(',')));
BigInteger public_exponent = new BigInteger(public_key.substring(public_key.indexOf(',') + 1, public_key.length() - 1));
byte[] file = read_bytes(input_file);
byte[] cipher = new byte[128];
byte[] decrypted = new byte[128];
BigInteger d = new BigInteger(private_key.substring(1, private_key.indexOf(',')));
BigInteger modulus = new BigInteger(private_key.substring(private_key.indexOf(',') + 1, private_key.length() - 1));
write_file(output_file, "", false);
int index = 0;
while (index<file.length) {
byte[] block = Arrays.copyOfRange(file, index, index+128);
cipher = new BigInteger(block).modPow(public_exponent, public_modulus).toByteArray();
append_bytes(output_file, cipher);
index+=128;
}
byte[] encrypted = read_bytes(output_file);
index = 0;
while(index < encrypted.length) {
byte[] block = Arrays.copyOfRange(encrypted, index, index+256);
decrypted = new BigInteger(block).modPow(d, modulus).toByteArray();
System.out.println(new String(decrypted));
index+= 256;
}
} else if (list.contains("-d")) {
/*String input_file, output_file, key_file;
input_file = output_file = key_file = "";
try {
input_file = list.get(list.indexOf("-i") + 1);
output_file = list.get(list.indexOf("-o") + 1);
key_file = list.get(list.indexOf("-d") + 1);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage:");
System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
System.exit(1);
}
String private_key = read_file(key_file).toString();
BigInteger d = new BigInteger(private_key.substring(1, private_key.indexOf(',')));
BigInteger modulus = new BigInteger(private_key.substring(private_key.indexOf(',') + 1, private_key.length() - 1));
byte[] encrypted = null;
/* todo */
} else {
System.out.println("Usage:");
System.out.println("RSA -h - View command-line arguments.");
System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
}
}
private static void generate_key(int bit_size, String key_file) {
BigInteger p = BigInteger.probablePrime(bit_size, new Random());
BigInteger q = BigInteger.probablePrime(bit_size, new Random());
BigInteger one = new BigInteger("1");
BigInteger phi = new BigInteger("1");
BigInteger e = new BigInteger("65537");
boolean done = false;
while(!done) {
BigInteger temp = p.subtract(one);
BigInteger temp2 = q.subtract(one);
phi = (temp.multiply(temp2));
if(phi.gcd(e).equals(one)) {
done = true;
} else {
e = BigInteger.probablePrime(bit_size, new Random());
}
}
BigInteger public_modulus = p.multiply(q);
BigInteger public_exponent = e;
BigInteger private_key = public_exponent.modInverse(phi); //d
try {
write_file(key_file + ".public", "(" + public_modulus + "," + e + ")", false);
write_file(key_file + ".private", "(" + private_key.toString() + "," + public_modulus + ")", false);
} catch (Exception ex) {
System.out.println("Error creating key files.");
System.exit(1);
}
}
public static void write_bytes(String file_name, byte[] bytes) {
try {
FileOutputStream fos = new FileOutputStream(new File(file_name));
fos.write(bytes);
fos.close();
} catch (IOException e) {
System.out.println("Error writing bytes to file.");
System.exit(1);
}
}
public static String read_file(String file_name) {
boolean is_key = false;
if(file_name.contains(".public") || file_name.contains(".private"))
is_key = true;
Scanner sc = null;
try {
sc = new Scanner (new File(file_name));
} catch (FileNotFoundException e) {
System.out.println("Input file does not exist.");
System.exit(1);
}
StringBuilder buf = new StringBuilder("");
while (sc.hasNext ()) {
buf.append (sc.nextLine());
if(!is_key)
buf.append("\n");
}
sc.close();
return buf.toString();
}
public static byte[] read_bytes(String file_name) {
Path path = Paths.get(file_name);
byte[] encrypted = null;
try {
encrypted = Files.readAllBytes(path);
} catch (IOException e) {
System.out.println("Error reading bytes from " + file_name);
System.exit(1);
}
return encrypted;
}
public static void append_bytes(String file_name, byte[] bytes) {
try {
OutputStream fos = new FileOutputStream(file_name, true);
fos.write(bytes);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error appending bytes to file.");
System.exit(1);
}
}
public static void write_file(String file_name, String message, boolean append) {
try {
FileWriter fstream = new FileWriter(file_name, append);
BufferedWriter out = new BufferedWriter(fstream);
out.write(message);
out.close();
} catch (Exception e){
System.out.println("Error writing to file.");
System.exit(1);
}
}
}