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.
Related
So part 2 of my assignment is to find the missing byte of an encryption key. As a background I am not too familiar with this so I have no clue on where to start. I have looked around and cannot seem to find a starting place. The information I have is that the encryption key is in AES/ECB key: {'__' '7e' '15' '16' '28' 'ae' 'd2' 'a6' 'ab' 'f7' '15' '88' '09' 'cf' '4f' '3c'};
What I did try is looping through ACII values (0-255) and then getting the byte of the values and appending them to the byte array of the key. After I would attempt to decrypt the file as normal and output the new file in hopes to see a picture. However I am not seeing anything. Can you please point me to where I am going wrong?
byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();
String[] asciiArray = new String[256];
FileInputStream file = new FileInputStream(path);
Cipher aesCipher = Cipher.getInstance(transformation);
for(int i = 0;i<256; i++){
arrayInts[i] = Character.toString((char)i);
byte[] b = asciiArray [i].getBytes();
byte[] result = new byte[b.length + keyByte.length];
System.arraycopy(b, 0, result, 0, b.length);
System.arraycopy(keyByte, 0, result, b.length, keyByte.length);
FileOutputStream out = new FileOutputStream("AESencrypt_view" + String.valueOf(i)+".jpg");
SecretKeySpec key1 = new SecretKeySpec(result,"AES");
aesCipher.init(Cipher.DECRYPT_MODE, key1);
CipherOutputStream outSt = new CipherOutputStream(out,aesCipher);
byte[] buf = new byte[1024];
int read;
while((read=file.read(buf))!=-1){
outSt.write(buf, 0, read);
}
//file.close();
out.flush();
outSt.flush();
}
You have many problems with your code.
Don't store binary data in strings
This
byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();
should be reduced to
byte[] keyByte = DatatypeConverter.parseHexBinary(key);
Be aware of NullPointerExceptions
This
String[] asciiArray = new String[256];
...
asciiArray[i].getBytes();
is actually a NullPointerException, because asciiArray[i] was never initialized. When you create an array of non-primitive types, the array is always initialized with all null values.
A FileInputStream produces the file contents only once
You have the code
FileInputStream file = new FileInputStream(path);
outside of the loop, but you're reading the file inside of the loop until it is fully read. The problem is that this works only for the first iteration. In the next iteration (i == 1), there is no data to be read, so nothing to decrypt.
You should either read the file into a byte[] before the for-loop or initialize the stream inside of the for-loop in order to be able to read the file every time.
Listen for the errors
CipherInputStream and CipherOutputStream hide some exceptions. In particular, ECB mode is a non-streaming block cipher mode, so it must have some kind of padding. Usually, this padding is from PKCS#5 (= PKCS#7). You should use the Cipher and it's update method directly. When you're done writing data, then you can call the doFinal method and if the key was wrong, you will get an exception that you can catch with a probability of 255/256th (approx. 1).
Make the key iteration easier
byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");
for(int i = 0; i < 256; i++){
keyByte[0] = (byte)i;
...
}
That's it. You don't need more to change the first byte of the key.
Some example code:
byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");
Cipher aesCipher = Cipher.getInstance(transformation);
byte[] buf = new byte[1024];
for(int i = 0; i < 256; i++){
keyByte[0] = (byte)i;
FileInputStream inFileStream = new FileInputStream(path);
File outFile = new File("AESencrypt_view" + String.valueOf(i)+".jpg");
FileOutputStream outFileStream = new FileOutputStream(outFile);
SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
aesCipher.init(Cipher.DECRYPT_MODE, keySpec);
int read;
while((read = inFileStream.read(buf)) != -1){
outFileStream.write(aesCipher.update(buf, 0, read));
}
inFileStream.close();
try {
outFileStream.write(aesCipher.doFinal());
outFileStream.close();
}
catch(BadPaddingException e) {
// obviously a wrong key or broken ciphertext
outFileStream.close();
outFile.delete();
}
}
If the file is small, you don't have to read it again and again in every iteration, you can read it once before the for-loop.
That's not the way you want to iterate through the possible 256 byte values! Consider, for example, what happens when i = 137: You say Character.toString((char)137) - the output of this is the Unicode character U+0089. Calling s.getBytes() on this gives you the byte array [-62, -118]. Already we know we are in trouble since this should not be two bytes! (This is the UTF-8 interpretation of the character U+0089, FYI.)
Instead, why not just iterate through the possible byte values? There's no reason the for-loop has to iterate over int values; you can iterate directly over byte values. (NB: bytes in Java are signed, for no good reason, so the for-loop looks a little odd, but this is the right way):
for (byte b = -128; b<128; b++) {
byte[] result = new byte[keyByte.length +1];
result[0] = b;
System.arraycopy(keyByte, 0, result, 1, keyByte.length);
// yadda yadda yadda
}
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.
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 !
So I have these large files (6GB+) that I need to decrypt on a 32 bit computer. The general procedure that I used previously was to read the entire file in memory, then pass it on to the decrypt function and then write it all back to a file. This doesn't really work due to memory limitations. I did try passing the file in parts to the decrypt function but it seems to mess up around the boundaries of where I break up the file before sending it to the decrypt function.
I've tried breaking up the file in parts relative to key size but that doesnt seem to matter. I tried a byte array of size 2048 as well as a byte aray of size 294 thinking that might be the special boundary but, no luck. I can see parts of the file correctly decrypted but parts which are total gibberish.
Is it just NOT POSSIBLE to decrypt the file in chunks? If there is a way, then how?
Here is my decryption function / my attempt to decrypt in parts.
private Path outFile;
private void decryptFile(FileInputStream fis, byte[] initVector, byte[] aesKey, long used) {
//Assume used = 0 for this function.
byte[] chunks = new byte[2048]; //If this number is greater than or equal to the size of the file then we are good.
try {
if (outFile.toFile().exists())
outFile.toFile().delete();
outFile.toFile().createNewFile();
FileOutputStream fos = new FileOutputStream(outFile.toFile());
OutputStreamWriter out = new OutputStreamWriter(fos);
IvParameterSpec spec = new IvParameterSpec(Arrays.copyOfRange(initVector, 0, 16));
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, spec);
int x;
while ((x = fis.read(chunks, 0, chunks.length)) != -1) {
byte[] dec = cipher.doFinal(Arrays.copyOfRange(chunks, 0, x));
out.append(new String(dec));
}
out.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
LOG.error(ExceptionUtils.getStackTrace(e));
}
}
Consider using Cipher#update(byte[], int, int, byte[], int) instead of doFinal() for multipart operations. This will take care of part boundaries for you.
The last part of the deciphered data can be obtained by calling the doFinal(byte[] output, int outputOffset) method.
I have been doing web programming for several years now and since then I have not done any programming for desktop applications, and I have forgotten so many things. Please be patient if this is too simple.
Now I have this situation:
I am trying to store some hashed words in a file. I think I should use binary files for this (please correct me if I am wrong). But I have no idea how should I write the words to the file. I tried many ways, but when I read back the file, and try to decrypt the words, I get BadPaddingException.
Does anyone have any idea how to write the words to a file?
P.S: I use this code for encrypting/decrypting the words (I got it from another StackOverflow thread, with a few modifications):
public static byte[] encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(password));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(salt, 20));
return pbeCipher.doFinal(property.getBytes("UTF-8"));
}
public static String decrypt(byte[] property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(password));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(salt, 20));
return new String(pbeCipher.doFinal(property));
}
Well, just use FileInputStream and FileOutputStream =)
Sample writing:
// encrypted data in array
byte[] data = ...
FileOutputStream fos = ...
fos.write(data, 0, data.length);
fos.flush();
fos.close();
Sample reading:
File inputFile = new File(filePath);
byte[] data = new byte[inputFile.length()];
FileInputStream fis = new FileInputStream(inputFile);
fis.read(data, 0, data.length);
fis.close();
Above code assumes that one file holds single encrypted item. If you need to hold more than one item in the single file, you'll need to devise some format scheme for that. For example, you can store number of bytes in encrypted data as 2 bytes, before data itself. 2 bytes per item means encrypted item can not be longer than 2^16 bytes. Of course, you can use 4 bytes for length.
Saving as a text document would seem to make more sense to me, the data is already a so there's no need to convert it to a byte[] and if you need to read from the file would be pretty convenient. Unless you're saving it from the web and its already coming through a socket as a byte[]. I know it says don't provide your opinion but its strictly a matter of opinion, that was the only part of your question left unanswered by the previous two answered