Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于解密的Java CipherInputStream行为_Java_Encryption - Fatal编程技术网

基于解密的Java CipherInputStream行为

基于解密的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

我使用以下代码来解密从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;
  }
}
正确计算oldHash,但如果更改任何其他长度的文本(不是32的倍数),oldHash的最后几个值将变为零

我的意见:

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

  • 请帮助我理解这种行为。

    同意邓肯·琼斯的观点,你的循环一团糟。尽管正确地检查了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
    方法不能保证填充字节数组。也许你只需要再读一遍?您可以使用一个实用程序库,如包装密码输入流。