密码输入流跳过

时间:2016-10-09 16:24:10

标签: java encryption aes inputstream seek

我想加密和解密文件。在解密时我希望跳过文件的前几个字节并仅解密其余的字节。

这里包含三个文件

  1. input_file.txt - 输入加密文本文件
  2. output_file.txt - 加密input_file.txt档案
  3. decrypted_file.txt - 解密output_file.txt档案
  4. 示例代码:

    import java.security.SecureRandom;
    import javax.crypto.Cipher;
    import javax.crypto.CipherInputStream;
    import javax.crypto.CipherOutputStream;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    
    public class FileReadWrite {
    
        public static byte[] getAESKey() {
            SecureRandom secureRandom = new SecureRandom();
            byte[] bytes = new byte[32];
            secureRandom.nextBytes(bytes);
            return bytes;
        }
    /**
     * Method used to generate a random new iv
     * 
     * @return Randomly generated iv
     */
    public static byte[] getAESIV() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] bytes = new byte[16];
        secureRandom.nextBytes(bytes);
        return bytes;
    }
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        FileInputStream fin = new FileInputStream("/Users/emp/Research/Streams/input_file.txt");
        FileOutputStream fout = new FileOutputStream("/Users/emp/Research/Streams/output_file.txt");
    
        SecretKeySpec keySpec = null;
        IvParameterSpec ivSpec = null;
        Cipher ecipher = null;
        Cipher dcipher = null;
        byte[] keyBytes = getAESKey();
        byte[] ivBytes = getAESIV();
        // Creating keyspec and ivspec for generating cipher
        keySpec = new SecretKeySpec(keyBytes,"AES");
        ivSpec = new IvParameterSpec(ivBytes);
        try {
            ecipher = Cipher.getInstance("AES/CTR/NoPadding");
            ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        } catch (Exception e) {
            System.out.println("Thus the exception occured during cipher generation is ::: "+e);
        }
    
        CipherOutputStream cout = new CipherOutputStream(fout, ecipher);
        try {
            int count = 0;
            int BUFFER_SIZE = 1024;
            byte[] bytearray = new byte[BUFFER_SIZE];
            while((count = fin.read(bytearray, 0, BUFFER_SIZE)) != -1) {
                //fout.write(bytearray, 0, count);
                cout.write(bytearray, 0, count);
            }
        } catch(Exception ex) {
            System.out.println("Thus the exception occured is ::: "+ex);
        } finally {
            fin.close();
            fout.close();
            cout.close();
        }
    
        fin = new FileInputStream("/Users/emp/Research/Streams/output_file.txt");
        fout = new FileOutputStream("/Users/emp/Research/Streams/decrypted_file.txt");
    
        try {
            dcipher = Cipher.getInstance("AES/CTR/NoPadding");
            dcipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        } catch (Exception e) {
            System.out.println("Thus the exception occured during cipher generation is ::: "+e);
        }
        //fin.skip(1024);
        CipherInputStream cin = new CipherInputStream(fin, dcipher);
        try {
            int count = 0;
            int BUFFER_SIZE = 1024;
            byte[] bytearray = new byte[BUFFER_SIZE];
    
            **//cin.read(bytearray, 0, 30);**
    
            while((count = cin.read(bytearray, 0, BUFFER_SIZE)) != -1) {
                //fout.write(bytearray, 0, count);
                fout.write(bytearray, 0, count);
            }
        } catch(Exception ex) {
            System.out.println("Thus the exception occured is ::: "+ex);
        } finally {
            fin.close();
            cin.close();
            fout.close();
        }
    
        System.out.println("File read write completed successfully !!! ");
    }
    }
    

    尝试:

    1. 密码输入流跳过 - cin.skip(no_of_bytes) - 这不起作用 - 这会解密整个文件

    2. 文件输入流跳过

       fin.skip(no_of_bytes); CipherInputStream cin = new
       CipherInputStream(fin, cipher);
      

      这不会解密文件。输出文件看起来像加密。

    3. 虚拟读取 - 从密码输入流中读取和忽略 - 这可以正常工作

      //cin.read(bytearray, 0, 30);
      
    4. 请澄清以下内容:

      1. 内部跳过和搜索输入流的内容是什么?
      2. 为什么我的密码输入流搜索不起作用?
      3. 为什么密码输入流需要从流中读取所有字节(我假设如此)才能进行解密?它是如何运作的?

1 个答案:

答案 0 :(得分:1)

参考文章,

Random access InputStream using AES CTR mode in android

使用偏移值更新iv后,解密工作正常。

这是更新后的代码

package Streams;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class FileReadWrite {
    private static final int AES_BLOCK_SIZE = 16;

    public static final void jumpToOffset(final Cipher c, final SecretKeySpec aesKey, final IvParameterSpec iv, final long offset) {
        if (!c.getAlgorithm().toUpperCase().startsWith("AES/CTR")) {
            throw new IllegalArgumentException("Invalid algorithm, only AES/CTR mode supported");
        }
        if (offset < 0) {
            throw new IllegalArgumentException("Invalid offset");
        }
        final int skip = (int) (offset % AES_BLOCK_SIZE);
        final IvParameterSpec calculatedIVForOffset = calculateIVForOffset(iv, offset - skip);
        try {
            c.init(Cipher.ENCRYPT_MODE, aesKey, calculatedIVForOffset);
            final byte[] skipBuffer = new byte[skip];
            c.update(skipBuffer, 0, skip, skipBuffer);
            Arrays.fill(skipBuffer, (byte) 0);
        } catch (ShortBufferException | InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalStateException(e);
        }
    }

    private static IvParameterSpec calculateIVForOffset(final IvParameterSpec iv, final long blockOffset) {

        final BigInteger ivBI = new BigInteger(1, iv.getIV());
        final BigInteger ivForOffsetBI = ivBI.add(BigInteger.valueOf(blockOffset / AES_BLOCK_SIZE));
        final byte[] ivForOffsetBA = ivForOffsetBI.toByteArray();
        final IvParameterSpec ivForOffset;
        if (ivForOffsetBA.length >= AES_BLOCK_SIZE) {
            ivForOffset = new IvParameterSpec(ivForOffsetBA, ivForOffsetBA.length - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
        } else {
            final byte[] ivForOffsetBASized = new byte[AES_BLOCK_SIZE];
            System.arraycopy(ivForOffsetBA, 0, ivForOffsetBASized, AES_BLOCK_SIZE - ivForOffsetBA.length, ivForOffsetBA.length);
            ivForOffset = new IvParameterSpec(ivForOffsetBASized);
        }
        return ivForOffset;
    }

    public static byte[] getAESKey() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] bytes = new byte[32];
        secureRandom.nextBytes(bytes);
        return bytes;
    }
    /**
     * Method used to generate a random new iv
     * 
     * @return Randomly generated iv
     */
    public static byte[] getAESIV() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] bytes = new byte[16];
        secureRandom.nextBytes(bytes);
        return bytes;
    }
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        FileInputStream fin = new FileInputStream("/Users/emp/Research/Streams/input_file.txt");
        FileOutputStream fout = new FileOutputStream("/Users/emp/Research/Streams/output_file.txt");

        SecretKeySpec keySpec = null;
        IvParameterSpec ivSpec = null;
        Cipher ecipher = null;
        Cipher dcipher = null;
        byte[] keyBytes = getAESKey();
        byte[] ivBytes = getAESIV();
        // Creating keyspec and ivspec for generating cipher
        keySpec = new SecretKeySpec(keyBytes,"AES");
        ivSpec = new IvParameterSpec(ivBytes);
        try {
            ecipher = Cipher.getInstance("AES/CTR/NoPadding");
            ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        } catch (Exception e) {
            System.out.println("Thus the exception occured during cipher generation is ::: "+e);
        }

        CipherOutputStream cout = new CipherOutputStream(fout, ecipher);
        try {
            int count = 0;
            int BUFFER_SIZE = 1024;
            byte[] bytearray = new byte[BUFFER_SIZE];
            while((count = fin.read(bytearray, 0, BUFFER_SIZE)) != -1) {
                //fout.write(bytearray, 0, count);
                cout.write(bytearray, 0, count);
            }
        } catch(Exception ex) {
            System.out.println("Thus the exception occured is ::: "+ex);
        } finally {
            fin.close();
            fout.close();
            cout.close();
        }

        fin = new FileInputStream("/Users/emp/Research/Streams/output_file.txt");
        fout = new FileOutputStream("/Users/emp/Research/Streams/decrypted_file.txt");

        try {
            dcipher = Cipher.getInstance("AES/CTR/NoPadding");
            dcipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        } catch (Exception e) {
            System.out.println("Thus the exception occured during cipher generation is ::: "+e);
        }

        fin.skip(1024);
        jumpToOffset(dcipher, keySpec, ivSpec, 1024);
        CipherInputStream cin = new CipherInputStream(fin, dcipher);
        //cin.skip(1024);
        try {
            int count = 0;
            int BUFFER_SIZE = 1024;
            byte[] bytearray = new byte[BUFFER_SIZE];
            //cin.read(bytearray, 0, 30);
            while((count = cin.read(bytearray, 0, BUFFER_SIZE)) != -1) {
                //fout.write(bytearray, 0, count);
                fout.write(bytearray, 0, count);
            }
        } catch(Exception ex) {
            System.out.println("Thus the exception occured is ::: "+ex);
        } finally {
            fin.close();
            cin.close();
            fout.close();
        }

        System.out.println("File read write completed successfully !!! ");
    }
}