Home » Java » bit manipulation – How to use XOR to develop a ​OTPInputStream​ in Java-Exceptionshub

bit manipulation – How to use XOR to develop a ​OTPInputStream​ in Java-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment

Questions:

I want to develop a ​OTPInputStream ​in Java that extends the ​InputStream ​and takes another input stream of key data and provides a stream encrypting / decrypting input stream.I need to develop a test program to show the use of ​OTPInputStream​ that uses XOR and arbitrary data.

I tried with this code but I have problem that is

java.io.FileInputStream cannot be cast to java.lang.CharSequence

What should I do here?

public class Bitwise_Encryption {

    static String file = "" ;
    static String key = "VFGHTrbg";

    private static int[] encrypt(FileInputStream file, String key) {
        int[] output = new int[((CharSequence) file).length()];
        for(int i = 0; i < ((CharSequence) file).length(); i++) {
            int o = (Integer.valueOf(((CharSequence) file).charAt(i)) ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
            output[i] = o;
        }
        return output;        
    }


    private static String decrypt(int[] input, String key) {
        String output = "";        
        for(int i = 0; i < input.length; i++) {
            output += (char) ((input[i] - 48) ^ (int) key.charAt(i % (key.length() - 1)));
        }
        return output;
    }


    public static void main(String args[]) throws FileNotFoundException {  
        FileInputStream file = new FileInputStream("directory");

        encrypt(file,key);
        //decrypt();
        int[] encrypted = encrypt(file,key);

        System.out.println("Encrypted Data is :");
        for(int i = 0; i < encrypted.length; i++)
            System.out.printf("%d,", encrypted[i]);

        System.out.println("");
        System.out.println("---------------------------------------------------");
        System.out.println("Decrypted Data is :");
        System.out.println(decrypt(encrypted,key));  

    }
}
How to&Answers:

Think what you want is just file.read() and file.getChannel().size() to read one character at a time and get the size of the file

Try something like this:

private static int[] encrypt(FileInputStream file, String key) {
  int fileSize = file.getChannel().size();
  int[] output = new int[fileSize];
  for(int i = 0; i < output.length; i++) {
    char char1 = (char) file.read();
    int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
    output[i] = o;
  }
  return output;        
}

Will have to do some error handling because file.read() will return -1 if the end of the file has been reached and as pointed out reading one byte at a time is lot of IO operations and can slow down performance. You can keep the data in a buffer and read it another way like this:

private static int[] encrypt(FileInputStream file, String key) {
  int fileSize = file.getChannel().size();
  int[] output = new int[fileSize];

  int read = 0;
  int offset = 0;
  byte[] buffer = new byte[1024];
  while((read = file.read(buffer)) > 0) {
    for(int i = 0; i < read; i++) {
      char char1 = (char) buffer[i];
      int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
      output[i + offset] = o;
    }
    offset += read;
  }
  return output;        
}

This will read in 1024 bytes at a time from the file and store it in your buffer, then you can loop through the buffer to do your logic. The offset value is to store where in our output the current spot is. Also you will have to make sure that i + offset doesn’t exceed your array size.

UPDATE

After working with it; i decided to switch to Base64 Encoding/Decoding to remove non-printable characters:

  private static String encrypt(InputStream file, String key) throws Exception {
    int read = 0;
    byte[] buffer = new byte[1024];
    try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
      while((read = file.read(buffer)) > 0) {
        baos.write(buffer, 0, read);
      }
      return base64Encode(xorWithKey(baos.toByteArray(), key.getBytes()));
    }
  }

  private static String decrypt(String input, String key) {
    byte[] decoded = base64Decode(input);
    return new String(xorWithKey(decoded, key.getBytes()));
  }

  private static byte[] xorWithKey(byte[] a, byte[] key) {
    byte[] out = new byte[a.length];
    for (int i = 0; i < a.length; i++) {
      out[i] = (byte) (a[i] ^ key[i%key.length]);
    }
    return out;
  }

  private static byte[] base64Decode(String s) {
    return Base64.getDecoder().decode(s.trim());
  }

  private static String base64Encode(byte[] bytes) {
    return Base64.getEncoder().encodeToString(bytes);
  }

This method is cleaner and doesn’t require knowing the size of your InputStream or do any character conversions. It reads your InputStream into an OutputStream to do the Base64 Encoding as well to remove non printable characters.

I have tested this and it works both for encrypting and decrypting.

I got the idea from this answer:

XOR operation with two strings in java