Why CipherOutputStream cannot write to ByteArrayOutputStream? - java

I am trying to encrypt a string and store the encrypted bytes in primitive array of bytes using CipherOutputStream which is backed by ByteArrayOutputStream but the size of ByteArrayOutputStream object remains zero and it does not conatin any bytes after something is written to CipherOutputStream object. Here is the code.
ByteArrayOutputStream out = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(out, c);
PrintWriter pw = new PrintWriter(cos);
pw.println("Write something");
cos.flush();
out.flush();
System.out.println(out.size());
pw.close();
So I tried to make a comparison by changing the ByteArrayOutputStream to FileOutputStream using the code below. It turned out that the encrypted bytes are written to the target file. Does anyone have any idea why I cannot use ByteArrayOutputStream here? Can you suggest a solution as well?
FileOutputStream out = new FileOutputStream("/path/encrypted.txt");
CipherOutputStream cos = new CipherOutputStream(out, c);
PrintWriter pw = new PrintWriter(cos);
pw.println("Write something");
pw.close();

The only difference between these snippets is that in the first case you check the content before closing the stream, whereas in the second case - after closing. So, I guess you need to close the stream before checking.

The problem is the cipher.
Cipher cipher = Cipher.getInstance("RSA");
Has no padding.
Use
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
instead

Related

Java JCA - Input length must be multiple of 8 for padded decypher

I'm currently doing an assignment for a college course using Java's JCA.
The application takes in a file and encrypts it (or decrypts it) using DES-ECB. I am fully aware that it's not a secure encryption algorithm.
It encrypts fine, I believe, however when decrypting it blows up with a "Input length must be multiple of 8" even though the original message is being padded with PKCS5.
I have read all literature and quetions regarding this problem here on StackOverflow, but none of the answers seem to resolve this issue, which leads me to believe I am somehow corrupting the message/file...
For the encryption:
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, symmetricKey);
File file = new File(filePath);
FileOutputStream outputStream = new FileOutputStream("encrypted_"+file.getName());
CipherInputStream cipherStream = new CipherInputStream( new FileInputStream(file), cipher);
byte[] buffer = new byte[MAX_BUFFER]; //buffer para leitura
int bytes; //bytes a ler
//Encoder base64 - Apache Commons Codec
Base64 encoder = new Base64();
while ( (bytes = cipherStream.read(buffer)) != -1 ) {
byte[] encodedBuffer = encoder.encode(buffer);
outputStream.write(encodedBuffer, 0, bytes);
}
cipherStream.close();
outputStream.flush();
return outputStream;
For the decryption:
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, symmetricKey);
File file = new File(filePath);
FileInputStream cipheredStream = new FileInputStream(file);
FileOutputStream outputStream = new FileOutputStream("decrypted_"+file.getName());
CipherOutputStream cipherOutStream = new CipherOutputStream(outputStream, cipher);
byte[] buffer = new byte[MAX_BUFFER];
int bytes;
//Decoder base 64 - Apache Commons Codec
Base64 decoder = new Base64();
cipheredStream.read(buffer);
byte[] decodedBuffer = decoder.decode(buffer);
byte[] output = cipher.doFinal(decodedBuffer);
cipherOutStream.write(output);
//TODO bug here -> use this for big files
/*while ( (bytes = cipheredStream.read(buffer)) != -1 ) {
byte[] decodedBuffer = decoder.decode(buffer);
cipherOutStream.write(decodedBuffer, 0, bytes);
}*/
cipherOutStream.close();
cipheredStream.close();
return outputStream;
I've tried using AES to no avail; I've tried no padding, obviously it didn't work.
I'm just lost and would appreciate knowing what I'm doing wrong.
Thanks to #Topaco, the solution was found using Base64InputStream.
Because the deciphering was being done BEFORE decoding, it was generating that error. It was fixed by doing this encryption side:
Base64OutputStream encoder = new Base64OutputStream(outputStream);
while ( (nBytes = cipherStream.read(buffer, 0, MAX_BUFFER)) != -1 )
encoder.write(buffer, 0, nBytes);
And decryption side the exact opposite:
Base64InputStream decoder = new Base64InputStream(fileInputStream);
while ( (nBytes = decoder.read(buffer, 0, MAX_BUFFER)) != -1 )
cipherOutStream.write(buffer, 0, nBytes);

Issues with reading & decrypting very LARGE files, in bytes, in Java

When reading from a very large encrypted file in Java, I am using the following code:
FileInputStream in = new FileInputStream("file.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(saveLocation), "utf-8"));
int read;
byte buffer[] = new byte[16384];
byte getData[] = new byte[16384];
while((read = in.read(buffer)) != -1)
{
baos.write(buffer, 0, read);
Cipher cipher = Cipher.getInstance(symCipher);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initVecBytes);
cipher.init(Cipher.DECRYPT_MODE, originalKey, ivParameterSpec);
byte[] original = cipher.doFinal(baos.toByteArray());
String s = new String(original);
writer.append(s);
baos.reset();
}
writer.close();
As the file is very large (too large for me to load into memory in one go) I am reading it into a small buffer, then encrypting the small bytes of data and finally, writing them to a file.
However, when I do this, some of the data looks to be corrupted:
</AddressLine><_��SR����_�hEE</AddressLine></AddressLines><Postcode>
When I use a smaller file that isn't 16k it works fine, I only seem to get small amounts of corrupted data at the start of a new array read, then it's fine again until the next array read, and so on.
Anyone got any idea why this isn't working properly?
It's not working because most ciphers are stateful. Specifically, in cipher block chaining mode the plaintext must be XOR-ed with previous cipher text block. But every 16k, you are XORing it with the IV instead. You can't re-initialize the Cipher in the middle of a decryption operation.
Here are the five lines of code to which EJP alluded.
Cipher cipher = Cipher.getInstance(symCipher);
cipher.init(Cipher.DECRYPT_MODE, originalKey, new IvParameterSpec(initVecBytes));
try (InputStream in = Files.newInputStream(Paths.get("file.txt"))) {
Files.copy(new CipherInputStream(in, cipher), Paths.get(saveLocation));
}
Get rid of the ByteArrayOutputStream and the Writer and write the decrypted arrays directly to a FileOutputStream.
Use the same Cipher for the whole file, both when encrypting and decrypting, and initialize it once, not once per read.
You can do all this in about five lines of code with a CipherInputStream.

Java Decryption Returns Blank

I'm currently working on an encryption program, and I'm having an issue when decrypting. The resulting file is blank, and I have been trying to find the reason for this for about an hour. My decryption code is below...
Can someone please tell me why my data might come out blank?
file = x;
FileInputStream fis = new FileInputStream(file.getAbsolutePath());
file = new File(file.getAbsolutePath().substring(0,
file.getAbsolutePath().length() - 4));
FileOutputStream fos = new FileOutputStream(file);
byte k[] = Hash.MD5(password).getBytes("UTF-8");
SecretKeySpec key = new SecretKeySpec(k, "AES");
Cipher cipher = Cipher.getInstance(algorithm);
byte[] iv = batchIV;
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
CipherInputStream cin = new CipherInputStream(fis,
cipher);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = cin.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
fos.flush();
fos.close();
cin.close();
Links go to larger code portions.
Decrypt Method Here: http://pastebin.com/2p2juUTa
Full Class Here: http://pastebin.com/hgZHT4wg
I've found that the CipherInputStream is returning -1 when you try to read from it... I'm still unsure as to what might cause this, if anyone can help.
You don't state what Hash.MD5() and Hash.MD5R() do, let alone supply the source code, but evidently MD5() returns a String, which is already an error (see below), and that MD5R() only returns the input argument, which is basically pointless. Unless you think you've discovered a way to reverse MD5? You haven't.
If you make the following changes to your code:
change MD5() to return the byte[] resulting from the MessageDigest.digest() operation that it must perform, instead of wrapping that in a String, and make the corresponding adjustments at the callings sites (i.e. remove .toByteArray("UTF-8") in a couple of places, and
change MD5R() to return the input argument, or just remove the method,
you will find that your code works.
NB:
Repeat after me: 'String is not a container for binary data'.
flush() before close() is redundant.
The File variable file should be method-local, not static.
You don't need all those File.getAbsolutePath() method calls. getPath() will work just as well in most cases, or just the File object itself in others.

Decrypting image using java

I take this code from YouTube video.From this code I encrypt image correctly but could not decrypt that image..
Can anyone help me???
Encrypt code
FileInputStream file = new FileInputStream("src/image/A.jpg");
FileOutputStream output = new FileOutputStream("src/image/AA.jpg");
byte j[]="12345678".getBytes();
SecretKeySpec kye = new SecretKeySpec(j,"DES");
System.out.println(kye);
Cipher enc = Cipher.getInstance("DES");
enc.init(Cipher.ENCRYPT_MODE,kye);
CipherOutputStream cos = new CipherOutputStream(output, enc);
byte[] buf = new byte[1024];
int read;
while((read=file.read(buf))!=-1){
cos.write(buf,0,read);
}
file.close();
output.flush();
cos.close();
Decrypt code
FileInputStream file = new FileInputStream("src/image/AA.jpg");
FileOutputStream output = new FileOutputStream("src/image/AAA.jpg");
byte j[]="12345678".getBytes();
SecretKeySpec kye = new SecretKeySpec(j,"DES");
System.out.println(kye);
Cipher enc = Cipher.getInstance("DES");
enc.init(Cipher.DECRYPT_MODE,kye);
CipherOutputStream cos = new CipherOutputStream(output, enc);
byte[] buf = new byte[1024];
int read;
while((read=file.read(buf))!=-1){
cos.write(buf,0,read);
}
file.close();
output.flush();
cos.close();
thank you
It is a relativly old post but I think I can help.
First, you should encode the Image into a ASCII representation. I would recommend Base64. It is much easier and less error attached when encrypting Base64. (Maybe not as strong but that depends on your needs)
The benefit of Base64 is the Alphabet it is using. No weird symbols at all.
1) Convert the image into a ByteArrayOutputStream by writing it with the ImageIO Class into one.
2) Encode the byte array into a Base64 String
3) Encrypt like you did above (Do not forget the flush).
4) Save bytes to new File. Delete old one.
Decrypt accordingly .....
Be aware, encoding into Base64 will blow up your memory and the file will be much bigger because of the Base64 AND the Encryption overhead.
Hope that helps !

CipherInputStream never throws exception

I have a method like. It works fine but the problem is when I try to decrypt a file which is having wrong padding or even which is not encrypted at all. Usually I believe cipher.doFinal(..) usually throws some exception related to IllegalBlockSizeException,
BadPaddingException. I believe its due to masking of those exception as in here. My question is can I detect those exceptions cases?
public myDecryptMethod(byte[] sessionKey, FileInputStream encryptedFileStream) throws Exception{
....
SecretKeySpec symmKeySpec = new SecretKeySpec(sessionKey, "AES/CBC/PKCS5Padding");
Cipher symmCipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
IvParameterSpec ivParameterSpec = new IvParameterSpec("0000000000000000".getBytes());
symmCipher.init(Cipher.DECRYPT_MODE, symmKeySpec, ivParameterSpec);
CipherInputStream cis = new CipherInputStream(encryptedFileStream, symmCipher);
byte[] inputByteArray = new byte[10240];
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while (true) {
int length = cis.read(inputByteArray);
if (length < 0)
break;
outStream.write(inputByteArray, 0, length);
}
outStream.close();
byte[] data = outStream.toByteArray();
InputStream inStream = new ByteArrayInputStream(data);
cis.close();
return inStream;
}
There have been discussions about this in bouncycastle-dev and openjdk-security. Oracle thinks this is intended behavior and with JCE's ciphers which do not do the authentication check on close the consider it safe.
BC ciphers act differently as they allow to stream and (and release unauthenticated data).
Your option would be to use BCs stream org.bouncycastle.crypto.io.CipherInputStream instead. They fixed the stream (>1.50). Phillipp wrote a good blog about all that.

Categories

Resources