我正在使用以下代碼來解密從android設備加密的文件。Java CipherInputStream解密行爲
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;
}
}
此代碼在Android上正常工作,但在Java桌面應用程序上表現奇怪。 我觀察到的是,在讀取CipherInputStream中的舊散列時,只有當要解密的數據的大小是32的倍數時,cIn才返回正確的散列值。例如,如果我加密的文本文件的長度爲32個字符或64/128/...),然後將下面的代碼
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;
}
正確地計算oldHash,但如果我更改任何其他長度(不是32的倍數)的文本,然後將oldHash的最後幾個值變爲零。
我的觀察:
- 文字大小6點焦 - 尾隨零在oldHash - 6
- 文本大小13字符 - 尾隨零在oldHash - 13
- 文本大小20個字符 - 在oldHash尾隨零 - 4點
- 文本大小32點炭 - 尾隨在oldHash零 - 0 //正確結果
- 文本大小31點炭 - 尾隨零在oldHash - 1
- 文字大小64 char - oldHash中的拖尾零 - 0 //正確結果
請幫我理解此行爲。
'read'方法不能保證填充你的字節數組。也許你只需要再讀一遍?您可以使用實用程序庫,例如['IOUtils.readFully'](http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/IOUtils.html#readFully%28java。 io.InputStream,%20byte []%29)來包裝你的密碼輸入流。 – 2013-04-27 07:44:27