I'd like to implement a simple encryption/decryption tool in java.
Therefore I found a little tutorial on: http://www.codejava.net/coding/file-encryption-and-decryption-simple-example
I changed some lines of code, to guarantee the encryption of large files.
Now I got the problem, that the decryption doen't work.
I got the following error message/exception:
Error encrypting/decrypting file
at Algorithmus.Encryptor.doCrypto(Encryptor.java:71)
at Algorithmus.Encryptor.decrypt(Encryptor.java:39)
at GUI.MainWindow$encryptThread.run(MainWindow.java:838)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at Algorithmus.Encryptor.doCrypto(Encryptor.java:60)
... 2 more
I tried to change the Transoformation parameter to AES/CBC/PKCS5Padding but that has no effect. Does anyone know, how to optimize the given code?
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES";
public static void encrypt(String key, File inputFile, File outputFile)
throws ExtendedException {
doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}
public static void decrypt(String key, File inputFile, File outputFile)
throws ExtendedException {
doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}
private static void doCrypto(int cipherMode, String key, File inputFile,
File outputFile) throws ExtendedException {
try {
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = new FileInputStream(inputFile);
CipherOutputStream out = new CipherOutputStream(new FileOutputStream(outputFile), cipher);
byte[] buffer = new byte[8192];
byte[] outputBytes = null;
FileOutputStream outputStream = new FileOutputStream(outputFile);
int count;
while ((count = inputStream.read(buffer)) > 0)
{
out.write(buffer, 0, count);
outputBytes = cipher.doFinal(buffer);
}
inputStream.close();
outputStream.close();
} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException ex) {
throw new ExtendedException("Error encrypting/decrypting file", ex);
}
}
Just use the CipherOutputStream. Do not invoke cipher.doFinal(buffer) and don't forget to close the output stream.
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream fileout = new FileOutputStream(outputFile);
CipherOutputStream out = new CipherOutputStream(fileout , cipher);
try {
byte[] buffer = new byte[8192];
int count;
while ((count = inputStream.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
out.close();
inputStream.close();
}
The CipherOutputStream manages the cipher for you. It invokes doFinal when the stream will be closed and flushes the internal buffer.
Related
Hi guys I have to do this and I can encrypt file according to the des algorithm but I can not decyrpt again file ,I recieve error messaje like that :
javax.crypto.BadPaddingException Given final block not properly padded
I can not decrypt file I couldnt find why. Can u help me please
Thank you guys.
JAVA CODE :
public class Sifreleme {
public static void encrypt(){
try {
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
FileOutputStream fosKey = new FileOutputStream("..\\KEY");
SecretKeyFactory keyfac = SecretKeyFactory.getInstance("DES");
DESKeySpec keyspec = (DESKeySpec) keyfac.getKeySpec(key, DESKeySpec.class);
fosKey.write(keyspec.getKey());
fosKey.close();
Cipher crypt = Cipher.getInstance("DES");
crypt.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis = new FileInputStream("C:\\Users\\akif\\Desktop\\zilsesi.mp3");
FileOutputStream fos = new FileOutputStream("C:\\Users\\akif\\Desktop\\sifrelenenzilsesi.mp3");
byte[] arrayBytes = new byte[8];
int bytesReads;
while ((bytesReads = fis.read(arrayBytes)) != -1) {
fos.write(crypt.doFinal(arrayBytes), 0, bytesReads);
}
fis.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void decrypt(){
try {
FileInputStream fisKey = new FileInputStream("..\\KEY");
byte[] arrayKey = new byte[fisKey.available()];
fisKey.read(arrayKey);
SecretKey key = new SecretKeySpec(arrayKey, "DES");
Cipher decrypt = Cipher.getInstance("DES");
decrypt.init(Cipher.DECRYPT_MODE, key);
FileInputStream fis = new FileInputStream("C:\\Users\\akif\\Desktop\\sifrelenenzilsesi.mp3");
byte[] encText = new byte[16];
int bytesReads;
while ((bytesReads = fis.read(encText)) != -1) {
fis.read(decrypt.doFinal(encText), 0, bytesReads);
}
fis.close();
System.out.println(new String(encText));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String []args) throws IOException{
encrypt();
decrypt();
}
Your code here:
while ((bytesReads = fis.read(encText)) != -1) {
fis.read(decrypt.doFinal(encText), 0, bytesReads);
}
Is rather obviously wrong: you need to write the plaintext generated by calling decrypt.doFinal just like you do during encryption. Currently you are overwriting the generated plaintext by the next block(s) of ciphertext because you call read twice in the loop.
Furthermore, depending on your DES Cipher implementation, you forgot about the IV.
A lot of other things are wrong as well, including:
the stream handling using getAvailable();
the use of the 56 bit DES cipher;
the use of ECB mode;
the repeated calls to doFinal (which results in a very large overhead and insecure code);
not using the CipherInputStream and CipherOutputStream (etcetera);
using a string as the key;
forgetting to close your streams when an exception occurs (use the try with resources);
the printStackTracke() exception handling;
the use of static fields as variables.
Using the platform encoding within new String(encText) is only likely wrong.
Note that using the wrong key / ciphertext combination will likely also result in this error.
I am trying to develop a system that will decrypt a file then allows the authorized user to view it without saving the decrypted file. This is to ensure that the other user won't be able to open the decrypted file.
The following codes produced a file output.
public NewJFrame() {try{
String key = "squirrel123";
FileInputStream fis2 = newFileInputStream("encrypted.mui");
FileOutputStream fos2 = new FileOutputStream("decrypt.rar");
decrypt(key, fis2, fos2);
Desktop dk=Desktop.getDesktop();
File f = new File("decrypt.rar");
dk.open(f);
}
catch (Throwable e) {
JOptionPane.showMessageDialog(null, e);
}}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for SunJCE
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
How can I decrypt a file without using FileOutputStream then allows the authorized user to view it after the decryption?
If you don't want to write it to a Physical File, but just present the data instead, you may use a different writer then FileOutputStream.
For example, you can create a pair of PipedStream, decrypt and then read the result.
String key = "squirrel123";
FileInputStream fis2 = newFileInputStream("encrypted.mui");
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis);
decrypt(key, fis2, pis);
BufferedReader reader = new BufferedReader(new InputStreamReader(pis));
String line;
while( (line=reader.readLine()) != null ){
System.out.println(line);
}
I have a problem to read the file (for example *.zip) and encrypt it with 3DES, using secretKey which one generated from name of encrypted file.
Then I need to decrypt this file, and write it on HDD.
I tried to resolve thhis problem, but stuck when was decrypting file.
Here is code of encryptor
public class Encryptor {
private static String inputFilePath = "D:/1.txt";
public static void main(String[] args) {
FileOutputStream fos = null;
File file = new File(inputFilePath);
String keyString = "140405PX_0.$88";
String algorithm = "DESede";
try {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] fileByteArray = new byte[fileInputStream.available()];
fileInputStream.read(fileByteArray);
for (byte b : fileByteArray) {
System.out.println(b);
}
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
ObjectOutputStream objectOutputStream = new ObjectOutputStream
(new CipherOutputStream
(new FileOutputStream
("D:/Secret.file"), cipher));
objectOutputStream.writeObject(fileByteArray);
objectOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static SecretKey getKey(String message) throws Exception {
String messageToUpperCase = message.toUpperCase();
byte[] digestOfPassword = messageToUpperCase.getBytes();
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
return key;
}
}
And here is code of decryptor
public class Decryptor {
public static void main(String[] args) {
try {
File inputFileNAme = new File("d:/Secret.file");
FileInputStream fileInputStream = new FileInputStream(inputFileNAme);
FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
ObjectInputStream objectInputStream = new ObjectInputStream
(new CipherInputStream(fileInputStream, cipher));
System.out.println(objectInputStream.available());
while (objectInputStream.available() != 0) {
fileOutputStream.write((Integer) objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
}
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
objectInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static SecretKey getKey(String message) throws Exception {
String messageToUpperCase = message.toUpperCase();
byte[] digestOfPassword = messageToUpperCase.getBytes();
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
return key;
}
}
When i try to decrypt my file, i dont get anything in output file.
I tryed make debug, and saw, that objectInputStream.available() always contains 0.
Please tell me, how can I resolve this problem, and why it happens.
The usage
byte[] fileByteArray = new byte[fileInputStream.available()];
is specifically warned against in the Javadoc: " It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream."
Files should be processed a record or a buffer at a time.
The line:
fileInputStream.read(fileByteArray);
isn't guaranteed to fill the buffer. You have to check the return value: for -1, meaning end of file, or > 0, meaning the number of bytes that were actually transferred. See the Javadoc.
Similarly
while (objectInputStream.available() != 0) {
is not a valid test for end of stream. You should call readObject() until it throws EOFException.
As a quickfix, this works :
try {
File inputFileNAme = new File("d:/Secret.file");
FileInputStream fileInputStream = new FileInputStream(inputFileNAme);
FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
SecretKey secretKey = getKey(keyString);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
ObjectInputStream objectInputStream = new ObjectInputStream
(new CipherInputStream(fileInputStream, cipher));
System.out.println(objectInputStream.available());
fileOutputStream.write((byte[]) objectInputStream.readObject());
fileOutputStream.flush();
fileOutputStream.close();
fileInputStream.close();
objectInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
What I did is remove the ".available() while loop" and remove the cast to Integer that was wrong.
I agree with EJP answer, especially regarding the use of .available().
You may also use http://www.jasypt.org/ that provides a more simple API to crytpo stuff.
I encrypted a text file in AES algorithm. I am not able to decrypt it. I used the same key and the whole process is running in the same method body.
At first, the input.txt file is being encrypted into encrypted.txt file. Then the decoder, decrypt the encrypted.txt into decrypted.txt
Here is the code. Thank you for your help.
public static void main(String[] args) throws IOException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException {
Scanner sc = new Scanner(System.in);
String filename = sc.nextLine();
sc.close();
System.out.println("The file requested is " + filename);
File file = new File(filename);
if (file.exists())
System.out.println("File found");
File to_b_encf = new File("encrypted.txt");
if (!to_b_encf.exists())
to_b_encf.createNewFile();
System.out.println("encrypting");
Cipher encipher = Cipher.getInstance("AES");
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecretKey key = keygen.generateKey();
encipher.init(Cipher.ENCRYPT_MODE, key);
FileOutputStream output = new FileOutputStream(to_b_encf);
FileInputStream input = new FileInputStream(filename);
CipherInputStream cis = new CipherInputStream(input, encipher);
int read;
while ((read = cis.read()) != -1) {
output.write(read);
output.flush();
}
input.close();
output.close();
System.out.println("done");
System.out.println("decrypting");
Cipher decipher = Cipher.getInstance("AES");//initiate a cipher for decryption
decipher.init(Cipher.DECRYPT_MODE, key);//decrypt the file
File sourcefile = new File("encrypted.txt");
File destfile = new File("decrypted.txt");
if (!destfile.exists())
destfile.createNewFile();
FileInputStream decf = new FileInputStream(sourcefile);
CipherInputStream c_decf = new CipherInputStream(decf,decipher);
FileOutputStream destf = new FileOutputStream(destfile);
cout = new CipherOutputStream(destf,decipher);
while ((read = c_decf.read()) != -1) {
cout.write(read);
cout.flush();
}
c_decf.close();
destf.close();
cout.close();
decf.close();
System.out.println("done");
}
You messed with InputStream, OutputStream and whatnot. I made a simplfied version of your code (no files, all in-memory I/O) that illustrates the main concepts:
public class EncDec {
public static void main(String[] args) throws IOException
, InvalidKeyException, NoSuchAlgorithmException
, NoSuchPaddingException {
final String MESSAGE = "I'm a secret message";
final Charset CHARSET = Charset.defaultCharset();
Cipher cipher = Cipher.getInstance("AES");
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
cipher.init(Cipher.ENCRYPT_MODE, key);
// Encrypt the message
InputStream plainIn = new ByteArrayInputStream(
MESSAGE.getBytes(CHARSET));
ByteArrayOutputStream encryptedOut = new ByteArrayOutputStream();
copy(plainIn, new CipherOutputStream(encryptedOut, cipher));
// Decrypt the message
cipher.init(Cipher.DECRYPT_MODE, key);
InputStream encryptedIn = new CipherInputStream(
new ByteArrayInputStream(encryptedOut.toByteArray()), cipher);
ByteArrayOutputStream plainOut = new ByteArrayOutputStream();
copy(encryptedIn, plainOut);
System.out.println(new String(plainOut.toByteArray(), CHARSET));
}
private static void copy(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[4096];
while ( in.read(buffer) > -1) {
out.write(buffer);
}
out.flush();
}
}
The Java I/O API is inspired by the decorator pattern. Encryption/decription libraries provide a decorator CipherInputStream for reading encrypted content and a decorator CipherOutputStream to encrypt a plain source and write it to the decorated output destination.
CipherInputStream c_decf = new CipherInputStream(decf,decipher);
FileOutputStream destf = new FileOutputStream(destfile);
cout = new CipherOutputStream(destf,decipher);
while ((read = c_decf.read()) != -1) {
cout.write(read);
cout.flush();
}
It looks like you're deciphering it twice.
I have the following code. However the files b.xlsx and c.xlsx are of 0 bytes. Why is CipherOuputSteam not working?
public static void main(String[] args) throws Exception {
KeyPair keys = KeyPairGenerator.getInstance("RSA").generateKeyPair();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, keys.getPublic());
FileInputStream fis;
FileOutputStream fos;
CipherOutputStream cos;
fis = new FileInputStream("C:/temp/a.xlsx");
fos = new FileOutputStream("C:/temp/b.xlsx");
cos = new CipherOutputStream (fos, cipher);
byte[] block = new byte[8];
int i;
while ((i = fis.read(block)) != -1) {
cos.write(block, 0, i);
}
cos.close();
fos.close();
cipher.init(Cipher.DECRYPT_MODE, keys.getPrivate());
CipherInputStream cis1, cis2;
fis = new FileInputStream("c:/temp/b.xlsx");
CipherInputStream cis = new CipherInputStream(fis, cipher);
fos = new FileOutputStream("c:/temp/c.xlsx");
while ((i = cis.read(block)) != -1) {
fos.write(block, 0, i);
}
fos.close();
fis.close();
cis.close();
}
The problem lies in your usage - which is incorrect and in the implementation of CipherOutputStream which masks a very important exception - IllegalBlockSizeException.
The problem is that you cannot use an RSA key to encrypt data which is longer than the size of the key (which is 128 bytes in your example).
you should use a symmetric encryption algorithm for large blocks of data - e.g. AES.
If you want to use asymmetric keys for a reason (safe transmition of data for example) - you can find a good example on this SO answer.