Thursday, March 3, 2011

Can you figure out why this program is triggering a IllegalStateException?

all files in ~/Cipher/nsdl/crypto can be found here java files compiled with gcj, see compile.sh

nmint@nqmk-mint ~/Cipher/nsdl/crypto $ echo test | ./cryptTest encrypt deadbeefdeadbeefdeadbeefdeadbeef deadbeef Blowfish CBC > test
null
Exception in thread "main" java.lang.IllegalStateException: cipher is not for encrypting or decrypting
   at javax.crypto.Cipher.update(libgcj.so.81)
   at javax.crypto.CipherOutputStream.write(libgcj.so.81)
   at nsdl.crypto.BlockCrypt.encrypt(cryptTest)
   at nsdl.crypto.cryptTest.main(cryptTest)

BlockCrypt.java:

package nsdl.crypto;

import java.io.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class BlockCrypt {
Cipher ecipher;
Cipher dcipher;
byte[] keyBytes;
byte[] ivBytes;
SecretKey key;
AlgorithmParameterSpec iv;
byte[] buf = new byte[1024];

BlockCrypt(String keyStr, String ivStr, String algorithm, String mode) {
 try {
  ecipher = Cipher.getInstance(algorithm + "/" + mode + "/PKCS5Padding");
  dcipher = Cipher.getInstance(algorithm + "/" + mode + "/PKCS5Padding");

  keyBytes = hexStringToByteArray(keyStr);
  ivBytes = hexStringToByteArray(ivStr);

  key = new SecretKeySpec(keyBytes, algorithm);
  iv = new IvParameterSpec(ivBytes);

  ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
  dcipher.init(Cipher.DECRYPT_MODE, key, iv);
 } catch (Exception e) {
  System.err.println(e.getMessage());
 }
}

public void encrypt(InputStream in, OutputStream out) {
 try {
  // out: where the plaintext goes to become encrypted
  out = new CipherOutputStream(out, ecipher);

  // in: where the plaintext comes from
  int numRead = 0;
  while ((numRead = in.read(buf)) >= 0) {
   out.write(buf, 0, numRead);
  }
  out.close();
 } catch (IOException e) {
  System.err.println(e.getMessage());
 }
}

public void decrypt(InputStream in, OutputStream out) {
 try {
  // in: where the plaintext come from, decrypted on-the-fly
  in = new CipherInputStream(in, dcipher);

  // out: where the plaintext goes
  int numRead = 0;
  while ((numRead = in.read(buf)) >= 0) {
   out.write(buf, 0, numRead);
  }
  out.flush();
  out.close();
 } catch (IOException e) {
  System.err.println(e.getMessage());
 }
}
public static byte[] hexStringToByteArray(String s) {
 int len = s.length();
 byte[] data = new byte[len / 2];
 for (int i = 0; i < len; i += 2) {
  data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
  + Character.digit(s.charAt(i+1), 16));
 }
 return data;
}
}

cryptTest.java:

package nsdl.crypto;

import nsdl.crypto.BlockCrypt;

public class cryptTest {

public static void main (String args[]) {
 if (args.length != 5) {
  System.err.println("Usage: cryptTest (encrypt|decrypt) key iv algorithm mode");
  System.err.println("Takes input from STDIN. Output goes to STDOUT.");
 } else {
  String operation = args[0];
  String key = args[1];
  String iv = args[2];
  String algorithm = args[3];
  String mode = args[4];
  BlockCrypt blockCrypt = new BlockCrypt(key, iv, algorithm, mode);
  if (operation.equalsIgnoreCase("encrypt")) {
   blockCrypt.encrypt(System.in, System.out);
  } else if (operation.equalsIgnoreCase("decrypt")) {
   blockCrypt.decrypt(System.in, System.out);
  } else {
   System.err.println("Invalid operation. Use (encrypt|decrypt).");
  }
 }
}
}
From stackoverflow
  • Perhaps looking at the source for javax.crypto.Cipher helps this make sense? I couldn't really figure it out, even finding the error message in the source. Good luck!

  • The Cipher, ecipher, is not initialized, and it throws an IllegalStateException when you try to use it as if it were initialized in ENCRYPT_MODE.

    Note your catch block in the constructor of BlockCrypt. It is catching an exception with no message, and printing "null" to System.err. Rather than aborting execution—perhaps by throwing an exception from the constructor—you keep sailing.

    Replacing System.err.println(e.getMessage()) with e.printStackTrace() or at least System.err.println(e) should give you more detail. My guess is that ecipher.init() is throwing an exception because you're providing a 32-bit IV instead of 64 bits.

    InsDel : Thanks for taking the time to answer. If I make sure the IV is 64bits, the program works perfectly! You'll get in the credits when I finish my science fair project. (I don't really know what else I can do to thank you - I'm only an eighth grader.)

0 comments:

Post a Comment