Пропуск входного потока шифра

Я хотел бы зашифровать и расшифровать файлы. При расшифровке я хочу пропустить первые несколько байтов файла и расшифровать только остальные.

Здесь содержится три файла

  1. input_file.txt - входной текстовый файл для шифрования
  2. output_file.txt - зашифрованный input_file.txt файл
  3. decrypted_file.txt - расшифрованный output_file.txt файл

Образец кода:

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. Dummy read - Чтение и игнорирование входного потока шифрования - это работает

    //cin.read(bytearray, 0, 30);
    

Прошу разъяснить мне следующее:

  1. Что пропускает и ищет входной поток внутри?
  2. Почему поиск входного потока моего шифра не работает?
  3. Почему входной поток шифрования требует, чтобы все байты были прочитаны из потока (я так предполагаю) для расшифровки? Как это работает?

person Tom Taylor    schedule 09.10.2016    source источник
comment
Да, если вы пропустите большое количество байтов в зашифрованном файле, все должно быть расшифровано с помощью CipherInputStream, даже если режим CTR позволяет пропустить (ограничение реализации). См. также: stackoverflow.com/questions/23743842/   -  person Robert    schedule 11.10.2016
comment
Так что dummy read единственное решение?   -  person Tom Taylor    schedule 11.10.2016
comment
Вы прочитали ответ, который я связал? Он показывает, как пропустить в режиме CTR. Он требует расшифровки фиктивных данных, но не требует чтения зашифрованного файла.   -  person Robert    schedule 11.10.2016
comment
Да, Роберт, только что прочитал статью полностью.. Было действительно очень полезно..   -  person Tom Taylor    schedule 11.10.2016


Ответы (1)


Со ссылкой на статью,

Произвольный доступ к InputStream с использованием режима AES CTR в 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 !!! ");
    }
}
person Tom Taylor    schedule 11.10.2016
comment
Привет всем, ранее в вопросе не было много информации. Итак, за него проголосовали. Я отредактировал свой вопрос с достаточным количеством информации и обновил его. Но по-прежнему есть отрицательный голос, и учетная запись stackoverflow говорит: «Извините, мы больше не принимаем вопросы от этой учетной записи, когда я пытаюсь задать новый вопрос. Кто-нибудь, пожалуйста, помогите мне с этим. - person Tom Taylor; 13.10.2016