I use DES algorithm to encrypt/decrypt my text. And it works perfect with latin texts.
But when I start encrypt/decrypt cyrillic text, decrypted one is shown as ????? ???????? in my TextField form and in console. How can i fix it?
After Joachim Sauer advice I changed inputBytes = textToEnrypt.getBytes(); to inputBytes = textToEnrypt.getBytes("UTF-8"); and now I have javax.crypto.IllegalBlockSizeException. Help me, please...
package crypting;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.microedition.midlet.*;
public class Encryptor extends MIDlet {
String buffer;
public void startApp() {
String keyString = "testtest";
// encrypt("Text for encrypting", keyString);
encrypt("Привет", keyString);
decrypt(buffer, keyString);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void encrypt(String textToEnrypt, String keyString) {
Cipher cipher;
try {
cipher = Cipher.getInstance("DES");
} catch (Exception ex) {
System.out.println(ex.toString());
return;
}
byte[] keyData = keyString.getBytes();
SecretKeySpec key = new SecretKeySpec(keyData, 0, keyData.length, "DES");
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
} catch (Exception ex) {
System.out.println(ex.toString());
return;
}
int cypheredBytes = 0;
byte[] inputBytes;
try {
inputBytes = textToEnrypt.getBytes("UTF-8");
// inputBytes = textToEnrypt.getBytes();
} catch (Exception ex) {
System.out.println(ex.toString());
return;
}
byte[] outputBytes = new byte[100];
try {
cypheredBytes = cipher.doFinal(inputBytes, 0, inputBytes.length,
outputBytes, 0);
} catch (Exception ex) {
System.out.println(ex.toString());
return;
}
String str = new String(outputBytes, 0, cypheredBytes);
buffer = str;
System.out.println("Encrypted string = " + str);
}
public void decrypt(String textToDecrypt, String keyString) {
Cipher cipher;
try {
cipher = Cipher.getInstance("DES");
} catch (Exception ex) {
System.out.println(ex.toString());
return;
}
byte[] keyData = keyString.getBytes();
SecretKeySpec key = new SecretKeySpec(keyData, 0, keyData.length, "DES");
try {
cipher.init(Cipher.DECRYPT_MODE, key);
} catch (Exception ex) {
System.out.println("2. " + ex.toString());
return;
}
int cypheredBytes = 0;
byte[] inputBytes;
try {
inputBytes = textToDecrypt.getBytes("UTF-8");
// inputBytes = textToDecrypt.getBytes();
} catch (Exception ex) {
System.out.println("3. " + ex.toString());
return;
}
byte[] outputBytes = new byte[100];
try {
cypheredBytes = cipher.doFinal(inputBytes, 0, inputBytes.length,
outputBytes, 0);
} catch (Exception ex) {
System.out.println("4. " + ex.toString());
return;
}
String str = new String(outputBytes, 0, cypheredBytes);
System.out.println("Decrypted string = " + str);
}
}
I was able to make it work with the following changes.
Change the return type of encrypt method, from void to byte[]:
static public byte[] encrypt(String textToEnrypt, String keyString)
throws Exception
{
//at the end
//write this down:
byte[] newResponse = new byte[cypheredBytes];
for(int i=0;i < cypheredBytes;i++)
{
newResponse[i] = outputBytes[i];
}
return newResponse;
}
Instead of:
String str = new String(outputBytes, 0, cypheredBytes);
buffer = str;
System.out.println("Encrypted string = " + str);
My guess (and I can't do more without you showing some code) is that you're using getBytes() without a parameter and construct the String from the byte[] without a parameter as well. That means using the platform default encoding and if that can't represent cyrillic characters, then that's what you get.
It's better to use UTF-8 for both transformations, this way you can represent every Unicode character.
DES uses a 64-bit (8-byte) block size. You have to make sure that the data you're encrypting is a multiple of 8 bytes, i.e. pad it out with zero bytes or whatever to ensure that it is. Otherwise you'll get an IllegalBlockSizeException. You'll need to do this after you convert the string to UTF-8, of course....
One problem is the line
String str = new String(outputBytes, 0, cypheredBytes);
in your encrypt method. You cannot use String as a container for binary data. Encrypted data should not be converted to a String unless it is a requirement, and then you need to use an appropriate codec such as base64.
Related
I have a client/server application that encrypts or decrypts a message both on the client-side and server-side. However on decryption I keep getting the following error from the StackTrace
Input length must be multiple of 8 when decrypting with padded cipher
Following is the code from both the Server and Client classes.
The thing is I have tried using ("DES/CBC/PKCS5Padding") and ("UTF-8") but still haven't been able to fix said issue.
Any help would be appreciated thanks?
public class ServerApp {
public static byte[] encrypt(String input, Key k) {
try {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception ex) {
return null;
}
}
public static String decrypt(byte[] cipher, Key k) {
try {
Cipher cipher1 = Cipher.getInstance("DES");
cipher1.init(Cipher.DECRYPT_MODE, k);
byte[] original = cipher1.doFinal(cipher);
return new String(original);
} catch (Exception ex) {
return null;
//Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws NoSuchAlgorithmException {
try {
Key key=KeyGen.getSecretKey();
ServerSocket ser = new ServerSocket(3333);
System.out.println("Server Started");
Socket client = ser.accept();
DataInputStream in = new DataInputStream(client.getInputStream());
DataOutputStream out = new DataOutputStream(client.getOutputStream());
Scanner scan = new Scanner(System.in);
// SecretSocket sc = new SecretSocket(client, KeyGen.getSecretKey());
String serMsg, cliMsg, plain;
// OutputStream sout = sc.getOutputStream();
// InputStream sin = sc.getInputStream();
do {
System.out.print("You say: ");
serMsg = scan.nextLine();
// sout.write(serMsg.getBytes());
// System.out.println("cli server "+sin.read());
byte[] ci = encrypt(serMsg, KeyGen.getSecretKey());
System.out.println("encrypt " +ci.toString());
out.writeUTF(ci.toString());
plain = decrypt(ci, KeyGen.getSecretKey() );
System.out.println("decrypt " + plain);
} while (!serMsg.equals("end"));
client.close();
ser.close();
} catch (IOException ex) {
Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class ClientApp {
public static byte[] encrypt(String input, Key k) {
try {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception ex) {
return null;
}
}
public static String decrypt(byte[] cipher, Key k) {
try {
Cipher cipher1 = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher1.init(Cipher.DECRYPT_MODE, k);
byte[] original = cipher1.doFinal(cipher);
return new String(original);
} catch (Exception ex) {
return null;
//Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
try {
Socket s = new Socket("localhost", 3333);
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
Scanner scan = new Scanner(System.in);
String serMsg, cliMsg, plain;
do {
System.out.println("server server "+in.readUTF());
serMsg = in.readUTF();
System.out.println("enc: " + serMsg);
plain = decrypt(serMsg.getBytes("UTF-8"), KeyGen.getSecretKey());
System.out.println("Server says: " + plain);
} while (!serMsg.equals("end"));
s.close();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
Using DES without IV you are implicitly using DES/ECB/PKCS5Padding.
do not print a byte array directly. Java will output only printable characters. Always encode and decode a byte array when printing (Hex or Base64 are the most common encodings)
Here is an example project
Base64.getEncoder().encodeToString(byteArray)
I hope you are aware DES is considered a weak cipher today and should be used only for backward compatibility.
I see this "Input length must be multiple of 16 when decrypting with padded cipher" error when I run the program
RealEchoServer.java
import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RealEchoServer {
public static void main(String[] args) {
int i = 1;
try {
ServerSocket s = new ServerSocket(9003);
for (;;) {
Socket incoming = s.accept();
System.out.println("Spawning " + i);
new RealEchoHandler(incoming, i).start();
i++;
}
} catch (Exception e) {
System.out.println(e);
}
}
}
class RealEchoHandler extends Thread {
DataInputStream in;
DataOutputStream out;
private Socket incoming;
private int counter;
public RealEchoHandler(Socket i, int c) {
incoming = i;
counter = c;
}
public void run() {
try {
String key1 = "1234567812345678";
byte[] key2 = key1.getBytes();
SecretKeySpec secret = new SecretKeySpec(key2, "AES");
String msg = "Singapore Malaysia Japan India Indonesia HongKong Taiwan China England";
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] encrypted = cipher.doFinal(msg.getBytes());
in = new DataInputStream(incoming.getInputStream());
out = new DataOutputStream(incoming.getOutputStream());
boolean done = false;
String str = "";
out.writeUTF("Connected!\n");
out.flush();
while (!done) {
out.writeUTF(">");
out.flush();
str = in.readUTF();
System.out.println(in + ":" + str);
if (str == null) {
done = true;
} else {
System.out.println("Sending Ciphertext : " + new String(encrypted));
out.writeUTF(new String(encrypted));
out.flush();
}
}
incoming.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
RealSocketTest.java
import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
class RealSocketTest {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String str = "";
String str2 = "";
DataOutputStream out;
DataInputStream in;
try {
Socket t = new Socket("127.0.0.1", 9003);
in = new DataInputStream(t.getInputStream());
out = new DataOutputStream(t.getOutputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
boolean more = true;
System.out.println(in.readUTF());
while (more) {
str = in.readUTF();
System.out.print(str);
str2 = br.readLine();
out.writeUTF(str2);
out.flush();
str = in.readUTF();
System.out.println("Encrypted Info: " + str);
try {
String key1 = "1234567812345678";
byte[] key2 = key1.getBytes();
SecretKeySpec secret = new SecretKeySpec(key2, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secret);
byte[] decrypted = cipher.doFinal(str.getBytes());
System.out.println("Decrypted Info: " + new String(decrypted));
} catch (BadPaddingException e) {
System.out.println("Wrong Key!");
} catch (InvalidKeyException f) {
System.out.println("Invalid Key!");
}
}
} catch (IOException e) {
System.out.println("Error");
}
}
}
I've read a similar problem here Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher , but I don't understand how I could change mine, because it looks very different from mine.
So what should be added/changed to get it decrypted?
The problem is that ciphertexts may contain every possible byte value. Many byte values on the other hand are not printable and therefore not a valid UTF-8 encoding. When you make a String out of it new String(encrypted), it will silently drop some bytes and you won't be able to successfully decrypt the ciphertext.
Two possible fixes:
Encode the ciphertext as Base64 or Hex to be used in a text-based protocol.
Use the DataOutputStream::write() method to make it a binary protocol without encoding it.
Other security stuff:
Always specify the complete String for the expected Cipher instance. Different providers might have different defaults and it may happen that client and server don't use the same method. Example: AES/ECB/PKCS5Padding.
Never use ECB mode. It is not semantically secure. At least use CBC with a random IV (prepend the IV in front of the ciphertex or write it to the stream in order).
Check your ciphertext for manipulation. This is easily done, by employing an authenticated mode like GCM (AES/GCM/NoPadding with GCMParameters). If you don't want that, then at least try to implement an encrypt-then-MAC scheme where you HMAC the ciphertext (with a different key) and check it before decryption.
Could anyone tell me how I would decrypt data (using Java) that has been encrypted with this PHP function?
PHP Code
public function pad($data, $blocksize = 16) {
$pad = $blocksize - (strlen($data) % $blocksize);
return $data . str_repeat(chr($pad), $pad);
}
public function decryptECB($data) {
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, self::BLOB_ENCRYPTION_KEY, self::pad($data), MCRYPT_MODE_ECB);
}
public function encryptECB($data) {
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, self::BLOB_ENCRYPTION_KEY, self::pad($data), MCRYPT_MODE_ECB);
}
I have tried most of the things here but most of them are without padding and even when I add padding they don't work.
Edit 1:
(From PHP)
The input looks like this: http://pastebin.com/2cyig9nh
Key is this:
M02cnQ51Ji97vwT4
And output is this: http://pastebin.com/XcA50UGH
(The Java code)
public class Mcrypt {
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "M02cnQ51Ji97vwT4";
public Mcrypt() {
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}
public String encrypt(String text) throws Exception {
if (text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec );
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e) {
throw new Exception("[encrypt] " + e.getMessage());
}
return Base64.encodeBase64String(encrypted);
}
public byte[] decrypt(String code) throws Exception {
if (code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec );
decrypted = cipher.doFinal(new Base64().decode(code.getBytes()));
} catch (Exception e) {
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
private static String padString(String source) {
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
}
You are encoding and decoding to Base64 in your Java code, but your PHP code does not seem to perform any encoding/decoding whatsoever. This seems to be confirmed by what you posted on Pastebin. If you want to use strings instead of bytes - bytes are the only input accepted by modern ciphers - then you should make sure that the (character) encoding is correct on both sides. If you just want to use bytes, don't decode the binary in Java - the input is already in bytes, not text.
First time posting this so don't go too hard on me (although I've been read this forum quite for some time)
The problem that I encounter using AES in Java is like this.
First, I need to encrypt a string and write it into a text file then compress it, no problem with this. I'm using AES encryption and I define my own key e.g "123"
Second, I need to decompress the file (or extract it?) and decrypt it using the same key that I used on 1st step.
What happen in here is : First step is good but the 2nd one failed on decrypting the file even though the string result is the same, total character, word, etc
Here is the code to write the file
private static void inputKeFile(String input) throws IOException
{
FileWriter fstream = new FileWriter("C:/Users/Sactio/Desktop/tyo/txtToZip.txt",false);
BufferedWriter out = new BufferedWriter(fstream);
out.write(input);
//Close the output stream
out.close();
}
to zip the file
private static void doZip() {
try {
String filename ="C:/Users/Sactio/Desktop/tyo/txtToZip.txt";
String zipfilename="C:/Users/Sactio/Desktop/OutputZipWrite";
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);
long length = file.length();
byte[] buf = new byte[(int)length];
fis.read(buf,0,buf.length);
CRC32 crc = new CRC32();
ZipOutputStream s = new ZipOutputStream(new FileOutputStream(zipfilename));
s.setLevel(9);
ZipEntry entry = new ZipEntry(filename);
entry.setSize((long)buf.length);
crc.reset();
crc.update(buf);
entry.setCrc( crc.getValue());
s.putNextEntry(entry);
s.write(buf, 0, buf.length);
s.finish();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
and this is the encryption
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class JcaTest {
private Cipher ecipher;
private Cipher dcipher;
JcaTest(SecretKey key) {
try {
ecipher = Cipher.getInstance("AES");
dcipher = Cipher.getInstance("AES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (Exception e) {
System.out.println("Failed in initialization");
}
}
public String encrypt(String str) {
try {
byte[] utf8 = str.getBytes("UTF-8");
byte[] enc = ecipher.doFinal(utf8);
return new sun.misc.BASE64Encoder().encode(enc);
} catch (Exception e) {
System.out.println("Failed in Encryption");
}
return null;
}
public String decrypt(String str) {
try {
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF-8");
} catch (Exception e) {
System.out.println("Failed in Decryption");
}
return null;
}
and last, the extractor for zip
private static void bacaZip(String zipfilename) throws IOException
{
ZipInputStream zinstream = new ZipInputStream(
new FileInputStream(zipfilename));
File file = new File(zipfilename);
FileInputStream fis = new FileInputStream(file);
long length = file.length();
byte[] buf = new byte[(int)length];
ZipEntry zentry = zinstream.getNextEntry();
System.out.println("Name of current Zip Entry : " + zentry + "\n");
while (zentry != null) {
String entryName = zentry.getName();
System.out.println("Name of Zip Entry : " + entryName);
FileOutputStream outstream = new FileOutputStream("C:/Users/Sactio/Desktop/OutputZipWrite.txt");
int n;
while ((n = zinstream.read(buf, 0, buf.length)) > -1) {
outstream.write(buf, 0, n);
}
System.out.println("Successfully Extracted File Name : "
+ entryName);
outstream.close();
zinstream.closeEntry();
zentry = zinstream.getNextEntry();
}
}
private static void extractZip(String jsonString) throws FileNotFoundException
{
try {
bacaZip(jsonString);
} catch (IOException e1) {
// TODO Auto-generated catch block
System.err.println("Exception: "+e1);
}
StringBuffer contents = new StringBuffer();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("C:/Users/Sactio/Desktop/OutputZipWrite.txt"));
String text = null;
// repeat until all lines is read
while ((text = reader.readLine()) != null) {
contents.append(text)
.append(System.getProperty(
"line.separator"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// show file contents here
System.out.println("HASIL: "+contents.toString());
}
If I skip compression and file steps, AES works good, but if I send the string into a file and compress it, AES encryption fail for some reason. Does anyone have any idea for this problem?
The file you decrypt must be byte-for-byte the same as the output from the encryption process. You say "even though the string result is the same, total character, word, etc" To me that indicates you are treating the encrypted file as text, 'character'. It isn't text, it is bytes. Treating it as text is a recipe for disaster because of the many different ways characters can be expressed as bytes. You need to check byte-for-byte identity and always treat the cyphertext as bytes, not characters.
As #Thilo pointed out, compressing encrypted data is useless. Use the sequence compress -> encrypt -> decrypt -> expand.
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).");
}
}
}
}
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.
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!