Шифрование и дешифрование файлов не работает в java

Я хочу наиболее эффективно зашифровать большой видеофайл с именем largefile.mp4, а затем снова его расшифровать, но он не работает должным образом.

на самом деле ошибки нет, и файлы генерируются. но новый сгенерированный файл слишком мал, чем основной файл.

здесь largefile.mp4 — 100 МБ, но newEncryptedFile.txt — 107 КБ, а newDecryptedFile.mp4 — 210 байт.

В чем проблема ?

package fileenc;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

public class FileEncrypterDecrypter {
    
    SecretKey key;
    Cipher cipher;
    
    public FileEncrypterDecrypter() {
        
        try {
            
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            
            key = keygen.generateKey();
            
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            
            System.out.println(e);
        }
        
    }
    
    public boolean fileEncrypt(String plainFile) {
        
        try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(plainFile))){
                        
            
            
            cipher.init(Cipher.ENCRYPT_MODE, key);
            FileOutputStream fs = new FileOutputStream("newEncryptedFile.txt");
            CipherOutputStream out = new CipherOutputStream(fs, cipher);
            
            
            byte[] byteSize = new byte[1024];
            
            int numberOfBytedRead;
            
            while ( (numberOfBytedRead = fis.read(byteSize)) != -1 ) {
                out.write(numberOfBytedRead);
            }
            
            fis.close();
            out.flush();
            out.close();
            
            
            System.out.println("Encryption done...");
            
            return true;
            
        } catch (IOException | InvalidKeyException e) {
            
        }
        
        return false;
    }
    
    public boolean fileDecrypt(String encryptedFile) {
    
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("newDecryptedFile.mp4"))){
            
            cipher.init(Cipher.DECRYPT_MODE, key);
            FileInputStream fis = new FileInputStream(encryptedFile);
            CipherInputStream in = new CipherInputStream(fis, cipher);
            
            
            
            byte[] byteSize = new byte[1024];
            
            int numberOfBytedRead;
            
            while ( (numberOfBytedRead = in.read(byteSize)) != -1) {
                bos.write(numberOfBytedRead);
            }
            
            System.out.println("Decryption done...");
            
            
            bos.flush();
            bos.close();
            in.close();
            
            return true;
            
        } catch (IOException | InvalidKeyException e) {
            
        }
        
        return false;
    }
    
    public static void main(String[] args) throws FileNotFoundException, IOException {
            
        
        FileEncrypterDecrypter fed = new FileEncrypterDecrypter();
        
        fed.fileEncrypt("largefile.mp4"); // about 100 mb
        fed.fileDecrypt("newEncryptedFile.txt");
        
        
    }
}

Что вы ожидаете и что происходит на самом деле?

tgdavies 15.12.2020 10:39

Я хочу зашифровать видеофайл largefile.mp4 методом fileEncrypt и снова расшифровать его методом fileDecrypt. Я вручную закодировал, но я не знаю, в чем проблема, так как он не работает.

Muhammad 15.12.2020 10:41

Что именно вы подразумеваете под "не работает"?

tgdavies 15.12.2020 10:42

Что вы имеете в виду под тем, что он не работает? Зашифрованный файл не создается? Является ли расшифрованный результат неправильным?

Turamarth 15.12.2020 10:42

Я не знаю, почему некоторые пытаются закрыть мой вопрос, хотя это проблема для меня, и просят помощи, чтобы не закрыть

Muhammad 15.12.2020 10:43

@тгдэвис. Я имею в виду, что шифрование не работает, пока нет ошибки

Muhammad 15.12.2020 10:43

Я проголосовал за то, чтобы закрыть ваш вопрос, потому что в его текущем состоянии на него нельзя ответить, так как недостаточно информации о проблеме, с которой вы столкнулись. Если ваш вопрос закрыт, отредактируйте его, указав комментарии, и он будет открыт повторно. См. Как спросить.

tgdavies 15.12.2020 10:44

файл создан, но размер зашифрованного файла составляет 107 КБ, а размер основного файла - 100 МБ.

Muhammad 15.12.2020 10:44

Как вы думаете, что именно делает это утверждение: out.write(numberOfBytedRead);?

tgdavies 15.12.2020 10:46

с помощью out.write(numberOfBytedRead) я пытаюсь записать зашифрованный файл в новый файл с именем newEncryptedFile

Muhammad 15.12.2020 10:47
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
11
718
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне жаль, что я не проверил ваш код, потому что вы используете ECB режима UNSECURE, который больше не следует использовать в новых проектах.

Ниже вы найдете пример кода для шифрования и дешифрования файлов с помощью AES в режиме CBC. Программа генерирует случайный ключ для шифрования и дешифрования (с выходом ключа в кодировке base64 для лучшего хранения), генерирует случайный вектор инициализации (IV), который записывается в начале зашифрованного файла.

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

Шифрование выполняется порциями по 8192 байта с любезной помощью CipherOutput-/InputStream.

Предупреждение безопасности: код не имеет обработки исключений и предназначен только для образовательных целей. Обратите внимание, что для большей безопасности вы можете перейти на аутентифицированное шифрование (например, защищенное с помощью HMAC или с использованием режима GCM).

выход:

AES CBC 256 file encryption with CipherOutputStream
encryption key in base64 encoding: vTsd0E8MX3arfLRFjxZ58FSjkKxKYe32+rT5zCnJPVY=
result encryption: true
result decryption: true

код:

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class AesCbcEncryptionWithRandomKeyCipherOutputStreamSoExample {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IOException,
            InvalidKeyException, InvalidAlgorithmParameterException {
        System.out.println("AES CBC 256 file encryption with CipherOutputStream");
        String uncryptedFilename = "plaintext.txt";
        String encryptedFilename = "encrypted.enc";
        String decryptedFilename = "decrypted.txt";

        // generate random aes 256 key
        byte[] encryptionKey = new byte[32];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(encryptionKey);
        System.out.println("encryption key in base64 encoding: " + base64Encoding(encryptionKey));
        boolean result;
        // encryption
        result = encryptCbcFileBufferedCipherOutputStream(uncryptedFilename, encryptedFilename, encryptionKey);
        System.out.println("result encryption: " + result);
        // decryption
        result = decryptCbcFileBufferedCipherInputStream(encryptedFilename, decryptedFilename, encryptionKey);
        System.out.println("result decryption: " + result);
    }

    public static boolean encryptCbcFileBufferedCipherOutputStream(String inputFilename, String outputFilename, byte[] key)
            throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
        // generate random iv
        SecureRandom secureRandom = new SecureRandom();
        byte[] iv = new byte[16];
        secureRandom.nextBytes(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        try (FileInputStream in = new FileInputStream(inputFilename);
             FileOutputStream out = new FileOutputStream(outputFilename);
             CipherOutputStream encryptedOutputStream = new CipherOutputStream(out, cipher);) {
            out.write(iv);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] buffer = new byte[8096];
            int nread;
            while ((nread = in.read(buffer)) > 0) {
                encryptedOutputStream.write(buffer, 0, nread);
            }
            encryptedOutputStream.flush();
        }
        if (new File(outputFilename).exists()) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean decryptCbcFileBufferedCipherInputStream(String inputFilename, String outputFilename, byte[] key) throws
            IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
        byte[] iv = new byte[16];
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        try (FileInputStream in = new FileInputStream(inputFilename);
             CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
             FileOutputStream out = new FileOutputStream(outputFilename))
        {
            byte[] buffer = new byte[8192];
            in.read(iv);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            int nread;
            while ((nread = cipherInputStream.read(buffer)) > 0) {
                out.write(buffer, 0, nread);
            }
            out.flush();
        }
        if (new File(outputFilename).exists()) {
            return true;
        } else {
            return false;
        }
    }

    private static String base64Encoding(byte[] input) {
        return Base64.getEncoder().encodeToString(input);
    }
}

Большое спасибо, этот ответ сэкономил мое время. Но, пожалуйста, у меня есть несколько вопросов относительно вашего ответа. как я вижу, вы только что позвонили .flush(), мне все еще нужен метод .close()? также здесь FileOutputSteam и FileInputStream никогда не закрывались, нам нужно их закрыть?

Muhammad 15.12.2020 11:23

Потоки открываются в режиме «попробовать с ресурсами», который автоматически закрывает их, и вы не можете «забыть» закрыть их. Пожалуйста, отметьте мой ответ как принятый, когда вы будете рады его использовать :-)

Michael Fehr 15.12.2020 11:48

Большое спасибо, откуда мы знаем, что AES 256, означает ли 32-битный ключ 256 AES?

Muhammad 15.12.2020 12:22

В Java надежность алгоритма определяется длиной ключа. Использование 32-байтового ключа = 32 * 8 = 256 бит означает AES 256 [16-байтовый ключ = 16 * 8 = 128 бит = AES 128]. Другие фреймворки, такие как PHP/OpenSSL, определяют силу алгоритма путем присвоения имени и преобразования слишком длинного или слишком короткого ключа в соответствующий ключ.

Michael Fehr 15.12.2020 12:34

Другие вопросы по теме