基于解密的Java CipherInputStream行为
我使用以下代码来解密从android设备加密的文件基于解密的Java CipherInputStream行为,java,encryption,Java,Encryption,我使用以下代码来解密从android设备加密的文件 private void mDecrypt_File(FileInputStream fin, String outFile) throws Exception { FileOutputStream fout = new FileOutputStream(outFile); byte[] iv = new byte[16]; byte[] salt = new byte[16]; byte[] len = new byte[8
private void mDecrypt_File(FileInputStream fin, String outFile) throws Exception {
FileOutputStream fout = new FileOutputStream(outFile);
byte[] iv = new byte[16];
byte[] salt = new byte[16];
byte[] len = new byte[8];
byte[] FC_TAGBuffer = new byte[8];
Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE);
DataInputStream dis = new DataInputStream(fin);
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(DEFAULT_PASSWORD, salt, F_ITERATIONS);
SecretKey key = new SecretKeySpec(rfc.getBytes(32), "AES");
//decryption code
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
CipherInputStream cIn = new CipherInputStream(dis, cipher);
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
byte[] tempFC_TAGBuffer = changeByteArray(FC_TAGBuffer, 0);//new byte[8];
BigInteger ulong = new BigInteger(1, tempFC_TAGBuffer);
if (!ulong.equals(FC_TAG)) {
Exception ex = new Exception("Tags are not equal");
throw ex;
}
byte[] bytes = new byte[BUFFER_SIZE];
//determine number of reads to process on the file
long numReads = lSize / BUFFER_SIZE;
// determine what is left of the file, after numReads
long slack = (long) lSize % BUFFER_SIZE;
int read = -1;
int value = 0;
int outValue = 0;
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
// read the buffer_sized chunks
for (int i = 0; i < numReads; ++i) {
read = cIn.read(bytes, 0, bytes.length);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
// now read the slack
if (slack > 0) {
read = cIn.read(bytes, 0, (int) slack);
fout.write(bytes, 0, read);
md.update(bytes, 0, read);
value += read;
outValue += read;
}
fout.flush();
fout.close();
byte[] curHash = md.digest();
byte[] oldHash = new byte[md.getDigestLength()];
read = cIn.read(oldHash, 0, oldHash.length);
if (oldHash.length != read || (!CheckByteArrays(oldHash, curHash))) {
Exception ex = new Exception("File Corrupted!");
throw ex;
}
if (outValue != lSize) {
Exception ex = new Exception("File Sizes don't match!");
throw ex;
}
}
正确计算oldHash,但如果更改任何其他长度的文本(不是32的倍数),oldHash的最后几个值将变为零
我的意见:
请帮助我理解这种行为。同意邓肯·琼斯的观点,你的循环一团糟。尽管正确地检查了read()方法的返回值,但循环迭代假定每个read()都将返回缓冲区大小字节或上次读取的“slack”字节 如果你能正确地使用,你的代码会更好。例如,您将
FileInputStream
fin
包装在DataInputStream
中,但在这两行中使用了错误的方法:
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
相反,您应该轻松地使用方法,如中所示:
dis.readFully(iv);
dis.readFully(salt);
类似地,使用另一个DataInputStream包装CipherInputStream
cIn
也会使您受益匪浅,例如:
CipherInputStream cIn = new CipherInputStream(dis, cipher);
DataInputStream dcIn = new DataInputStream(cIn);
DataInputStream已经有了一个getLong
方法,因此您可以替换以下行:
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
与
你可以扔掉你自己开发的getLong
方法。现在,您可以继续使用dcIn.readFully(bytes)
读取下一个lSize
字节,并使代码更清晰、更短、更易于阅读和更正。同意DuncanJones的观点,您的循环一团糟。尽管正确地检查了read()方法的返回值,但循环迭代假定每个read()都将返回缓冲区大小字节或上次读取的“slack”字节
如果你能正确地使用,你的代码会更好。例如,您将FileInputStream
fin
包装在DataInputStream
中,但在这两行中使用了错误的方法:
dis.read(iv, 0, 16);
dis.read(salt, 0, 16);
相反,您应该轻松地使用方法,如中所示:
dis.readFully(iv);
dis.readFully(salt);
类似地,使用另一个DataInputStream包装CipherInputStream
cIn
也会使您受益匪浅,例如:
CipherInputStream cIn = new CipherInputStream(dis, cipher);
DataInputStream dcIn = new DataInputStream(cIn);
DataInputStream已经有了一个getLong
方法,因此您可以替换以下行:
cIn.read(len, 0, 8);
long lSize = getLong(len, 0);
cIn.read(FC_TAGBuffer, 0, 8);
与
你可以扔掉你自己开发的getLong
方法。现在,您可以继续使用dcIn.readFully(bytes)
读取下一个lSize
字节,并使您的代码更干净、更短、更易于阅读和更正。读取方法不能保证填充您的字节数组。也许你只需要再读一遍?您可以使用实用程序库(如)包装密码输入流。read
方法不能保证填充字节数组。也许你只需要再读一遍?您可以使用一个实用程序库,如包装密码输入流。