Java File Encryption missing bytes
I'm trying to write a simple program to encrypt and decrypt files using the AES algortihm. The intention later is to use split the simple program into encryption and decrytion methods in a more complex program. He is the encryption part of the program:
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey key = kg.generateKey();
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis; FileOutputStream fos; CipherOutputStream cos;
fis = new FileInputStream("FileTo.encrypt");
fos = new FileOutputStream("Encrypted.file");
//write encrypted to file
cos = new CipherOutputStream(fos, c);
byte[] b = new byte[16];
int i = fis.read(b);
while (i != -1) {
cos.write(b, 0, i);
i = fis.read(b);
}
cos.close();
//write key to file
byte[] keyEncoded = key.getEncoded();
FileOutputStream kos = new FileOutputStream("crypt.key");
kos.write(keyEncoded);
kos.close();
Here's the decryption part:
//Load Key
FileInputStream fis2= new FileInputStream("a.key");
File f=new File("a.key");
long l=f.length();
byte[] b1=new byte[(int)l];
fis2.read(b1, 0, (int)l);
SecretKeySpec ks2=new SecretKeySpec(b1,"AES");
Cipher c1 = Cipher.getInstance("AES");
c1.init(Cipher.DECRYPT_MODE, ks2);
FileInputStream fis1=new FileInputStream("Encrypte开发者_Go百科d.file");
CipherInputStream in= new CipherInputStream(fis1,c1);
FileOutputStream fos0 =new FileOutputStream("decrypted.file");
byte[] b3=new byte[1];
int ia=in.read(b3);
while (ia >=0)
{
c1.update(b3); //<-------remove this
fos0.write(b3, 0, ia);
ia=in.read(b3);
}
in.close();
fos0.flush();
fos0.close();
Now the problem is the decryption part is not decrypting the last bits, some bits are missing. It seems to me that it only decrypts every 16 bytes, but the variable in(cipherinputstream) returns -1 when it should be returning the last bytes. How do I get the last bits?
Thanks in advance
Edited: Added comment to point out what has to be removed. Here's some code to properly (i.e., without loading the entire file in java) encrypt and decrypt a file in Java using AES. It's possible to add additional parameters (padding, etc.) but here's the basic code.
You just need to remove this line in your code and it'll work fine:
c1.update(b3);
Since you're using a CipherInputStream
you don't need to update the Cipher
manually. It handles that for you, and by calling it you're interfering with the decryption.
On a side note, for efficiency you should increase the size of your byte[] b
and byte[] b3
arrays. Typically 8192 is a good size for buffering.
Here's some DES example code I dug up, which might be helpful... especially the calls to doFinal.
package forums;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
/**
This program tests the DES cipher. Usage:
java DESTest -genkey keyfile
java DESTest -encrypt plaintext encrypted keyfile
java DESTest -decrypt encrypted decrypted keyfile
*/
public class DESTest
{
private static void usage() {
System.err.print(
"This program tests the javax.crypto DES cipher package.\n"
+ "usage: java DESTest -genkey keyfile\n"
+ "java DESTest -encrypt plaintext encrypted keyfile\n"
+ "java DESTest -decrypt encrypted decrypted keyfile\n"
);
}
public static void main(String[] args) {
if ( args.length < 2 || args.length > 4
|| !args[0].matches("-genkey|-encrypt|-decrypt")
) {
usage();
return;
}
try {
if ("-genkey".equals(args[0])) {
KeyGenerator keygen = KeyGenerator.getInstance("DES");
SecureRandom random = new SecureRandom();
keygen.init(random);
SecretKey key = keygen.generateKey();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]));
out.writeObject(key);
out.close();
} else {
int mode;
if ("-encrypt".equals(args[0])) {
mode = Cipher.ENCRYPT_MODE;
} else { //-decrypt
mode = Cipher.DECRYPT_MODE;
}
ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
Key key = (Key) keyIn.readObject();
keyIn.close();
InputStream in = new FileInputStream(args[1]);
OutputStream out = new FileOutputStream(args[2]);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(mode, key);
crypt(in, out, cipher);
in.close();
out.close();
}
} catch (IOException exception) {
exception.printStackTrace();
} catch (GeneralSecurityException exception) {
exception.printStackTrace();
} catch (ClassNotFoundException exception) {
exception.printStackTrace();
}
}
/**
Uses a cipher to transform the bytes in an input stream
and sends the transformed bytes to an output stream.
@param in the input stream
@param out the output stream
@param cipher the cipher that transforms the bytes
*/
public static void crypt(InputStream in, OutputStream out, Cipher cipher)
throws IOException, GeneralSecurityException
{
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
System.out.println(outLength);
} else {
more = false;
}
}
if (inLength > 0) {
outBytes = cipher.doFinal(inBytes, 0, inLength);
} else {
outBytes = cipher.doFinal();
}
System.out.println(outBytes.length);
out.write(outBytes);
}
}
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESTest {
public static String asHex (byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static void main(String[] args) throws Exception {
String keyString = "ssssssssssssssss";
// 546578746F2070617261207465737465 (Hex)
byte[] key = keyString.getBytes();
System.out.println(asHex(key).toUpperCase());
String clearText = "sdhhgfffhamayaqqqaaaa";
// ZXNzYXNlbmhhZWhmcmFjYQ== (Base64)
// 6573736173656E686165686672616361 (Hex)
byte[] clear = clearText.getBytes();
System.out.println(asHex(clear).toUpperCase());
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
// PKCS5Padding or NoPadding
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
System.out.println(asHex(encrypted).toUpperCase());
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
System.out.println(original);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));
}
}
精彩评论