gpt4 book ai didi

解密时的 Java CipherInputStream 行为

转载 作者:行者123 更新时间:2023-11-30 07:17:23 24 4
gpt4 key购买 nike

我正在使用以下代码来解密从 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];
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 的最后几个值变为零。

我的观察:

  1. 文本大小 6 个字符 - oldHash 中的尾随零 - 6
  2. 文本大小 13 个字符 - oldHash 中的尾随零 - 13
  3. 文本大小 20 个字符 - oldHash 中的尾随零 - 4
  4. 文本大小 32 个字符 - oldHash 中的尾随零 - 0//正确结果
  5. 文本大小 31 个字符 - oldHash 中的尾随零 - 1
  6. 文本大小 64 个字符 - oldHash 中的尾随零 - 0//正确结果

请帮助我理解这种行为。

最佳答案

同意 DuncanJones 的观点,您的循环一团糟。尽管您正确检查了 read() 方法的返回值,但您的循环迭代假定每个 read() 都会为最后一次读取返回 BUFFER_SIZE 字节或“松弛”字节。

如果您正确使用 DataInputStream,您的代码会好得多.例如,您将 FileInputStream fin 包装在 DataInputStream 中,但随后在这两行中使用了错误的方法:

dis.read(iv, 0, 16);
dis.read(salt, 0, 16);

相反,您应该使用 readFully 方法,如下所示:

dis.readFully(iv);
dis.readFully(salt);

同样,您可以将 CipherInputStream cIn 与另一个 DataInputStream 包装在一起,例如:

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);

long lSize = dcIn.getLong()
dcIn.readFully(FC_TAGBuffer);

然后您将放弃自己开发的 getLong 方法。现在您可以继续使用 dcIn.readFully(bytes) 以正好 BUFFER_SIZE 的 block 读取下一个 lSize 字节并使您的代码更简洁、更短、更易于阅读,并且正确。

关于解密时的 Java CipherInputStream 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16248435/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com