Используя шифр в Java, как сделать длину зашифрованного файла кратной 16? - PullRequest
0 голосов
/ 11 мая 2018

Ошибка: javax.crypto.IllegalBlockSizeException: длина ввода должна быть кратна 16 при расшифровке с использованием шифра с добавлением

Пробные решения: я пытался изменить padding на"AES/ECB/NoPadding", "AES/ECB/PKCS5", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding" и все еще получил ту же ошибку или ошибку, указывающую только AES или Rijndael требуется.Затем я попытался заставить ключ использовать параметр «AES», а ALGO установить на «AES/CBC/PKCS5Padding», но я получил ошибку отсутствующего параметра, которую пытался исправить, добавив new IvParameterSpec(new byte[16]) к cipher.init.Это все еще привело к 16-битной проблеме.Так что я застрял сейчас.

import java.util.Scanner;
import java.io.File;
import java.io.IOException;

import java.io.BufferedReader;
import java.io.FileReader;

import java.security.Key;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.*;

import java.io.PrintWriter;
import java.io.FileWriter;

import java.util.*;
import java.io.*;  

// Don't forget to import any supporting classes you plan to use.

public class Crypto
{
  private Scanner fileText; 
  private PrintWriter fileEncrypt;
  private Scanner inputFile;
  private PrintWriter outputFile;

  private static final String ALGO = "AES/CBC/PKCS5Padding";
  private byte[] keyValue;

  public Crypto(String key)
      {
        keyValue = key.getBytes();
      }

  public String encrypt(String Data) throws Exception 
      {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
      }

  public String decrypt(String encryptedData) throws Exception
      {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decodedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
      }

  public Key generateKey() throws Exception
      {
        Key key = new SecretKeySpec(keyValue, "AES");
        return key;
      }

   // encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
   // encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")

  public void encrypt_decrypt(String function_type , String source_file , String 
  target_file)
  {
    String lineValue = ""; 
    String convertedValue = "";
    try
    {
      inputFile = new Scanner(new File(source_file));
    } 
    catch(Exception e)
    {
      System.out.println("( " + source_file + ") - File Opening Error");
    }
    try
    {
      outputFile = new PrintWriter(new FileWriter(target_file));
    }
    catch(Exception e)
    {
      System.out.println("( " + target_file + ") - File Opening Error");
    }

    while(inputFile.hasNext())
    { 
      lineValue = inputFile.nextLine();
      System.out.println("Source Line: " + lineValue);

      try
      {
        if (function_type == "ENCRYPT")
        {
          convertedValue = encrypt(lineValue);
        }
        else if (function_type == "DECRYPT")
        {
          convertedValue = decrypt(lineValue);
        }
      }
      catch(Exception e)
      {
        System.out.println(e);
      }
      System.out.println("Converted Line : " + convertedValue);

      outputFile.write(convertedValue);
    }

    inputFile.close();
    outputFile.close();
  }  

 public static void main( String args[] ) throws IOException
 {

      // Write your code here...
      // You will read from CryptoPlaintext.txt and write to 
      CryptoCiphertext.txt.
      Crypto c = new Crypto("dk201anckse29sns");
      c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" 
      );
      c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", 
      "CryptoDeciphered.txt");
      //
      // And then read from CryptoCiphertext.txt and write to 
      CryptoDeciphered.txt.
      //
      // DON'T forget your comments!
      // =============================== DO NOT MODIFY ANY CODE BELOW HERE 
       ==============================

     // Compare the files

      System.out.println(compareFiles() ? "The files are identical!" : "The 
      files are NOT identical.");   
 }

 /**  
  *  Compares the Plaintext file with the Deciphered file.
  *
  *    @return  true if files match, false if they do not
  */

  public static boolean compareFiles() throws IOException
  {

       Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the 
       plaintext file
       Scanner dc = new Scanner(new File("CryptoDeciphered.txt"));  // Open the 
       deciphered file

       // Read through the files and compare them record by record.
       // If any of the records do not match, the files are not identical.

       while(pt.hasNextLine() && dc.hasNextLine())
         if(!pt.nextLine().equals(dc.nextLine())) return false;

       // If we have any records left over, then the files are not identical.

       if(pt.hasNextLine() || dc.hasNextLine()) return false;

       // The files are identical.

       return true;




  }
}

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

В вашем коде есть две ошибки:

  1. Вы забыли сгенерировать случайный IV и добавить его к своему зашифрованному тексту (перед кодированием в base 64). Вам нужно будет найти IV из вашего зашифрованного текста и затем вернуть его снова во время расшифровки.

Обратите внимание, что для кода CBC требуется IV, неотличимый от случайного. Вы можете создать его, используя new SecureRandom (конечно, только во время шифрования) и IvParameterSpec. Код, вероятно, будет работать без этого в качестве реализации по умолчанию в Java по умолчанию на IV с нулем. Возможно, этого достаточно для этого задания.

Но это не то, что порождает ошибку; это гораздо больше банальности:

  1. Вы звоните outputFile.write вместо outputFile.println, что означает, что переводы строки не вставляются, и все кодировки base 64 помещаются в одну строку.

Обратите внимание, что вы не должны использовать какие-либо классы из sun.misc. Они являются частными для реализации Java и не являются частью Java API . В новых версиях Java java.util.Base64 для вашего удобства. На самом деле, версия sun.misc может вставлять окончания строк в кодировке base 64, что нарушит ваш код для более длинных строк.


Например:

package nl.owlstead.stackoverflow;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Key;
import java.util.Base64;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Crypto {
    private Scanner inputFile;
    private PrintWriter outputFile;

    private static final String ALGO = "AES/CBC/PKCS5Padding";
    private byte[] keyValue;

    public Crypto(String key) {
        keyValue = key.getBytes();
    }

    public String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key,
                new IvParameterSpec(new byte[c.getBlockSize()]));
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = Base64.getEncoder().encodeToString(encVal);
        return encryptedValue;
    }

    public String decrypt(String encryptedData) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key,
                new IvParameterSpec(new byte[c.getBlockSize()]));
        byte[] decodedValue = Base64.getDecoder().decode(encryptedData);
        byte[] decValue = c.doFinal(decodedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    public Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, "AES");
        return key;
    }

    public void encrypt_decrypt(String function_type, String source_file,
            String target_file) {
        String lineValue = "";
        String convertedValue = "";
        try {
            inputFile = new Scanner(new File(source_file));
        } catch (Exception e) {
            System.out.println("( " + source_file + ") - File Opening Error");
        }
        try {
            outputFile = new PrintWriter(new FileWriter(target_file));
        } catch (Exception e) {
            System.out.println("( " + target_file + ") - File Opening Error");
        }

        while (inputFile.hasNext()) {
            lineValue = inputFile.nextLine();
            System.out.println("Source Line: " + lineValue);

            try {
                if (function_type == "ENCRYPT") {
                    convertedValue = encrypt(lineValue);
                } else if (function_type == "DECRYPT") {
                    convertedValue = decrypt(lineValue);
                }
            } catch (Exception e) {
                System.out.println(e);
            }
            System.out.println("Converted Line : " + convertedValue);

            outputFile.println(convertedValue);
        }

        inputFile.close();
        outputFile.close();
    }

    public static void main(String args[]) throws IOException {

        Crypto c = new Crypto("dk201anckse29sns");
        c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt",
                "CryptoCiphertext.txt");
        c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt",
                "CryptoDeciphered.txt");

        System.out.println(compareFiles() ? "The files are identical!"
                : "The files are NOT identical.");
    }

    /**
     * Compares the Plaintext file with the Deciphered file.
     *
     * @return true if files match, false if they do not
     */

    public static boolean compareFiles() throws IOException {

        Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the
        Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the

        // Read through the files and compare them record by record.
        // If any of the records do not match, the files are not identical.

        while (pt.hasNextLine() && dc.hasNextLine()) {
            String ptl = pt.nextLine();
            String dcl = dc.nextLine();
            if (!ptl.equals(dcl))
            {
                System.out.println(ptl);
                System.out.println(dcl);
                continue;
//              return false;

        }
            }
        // If we have any records left over, then the files are not identical.

        if (pt.hasNextLine() || dc.hasNextLine())
            return false;

        // The files are identical.

        return true;
    }
}
0 голосов
/ 11 мая 2018

Рабочее решение для вас:

Только что добавили случайное значение IV при инициализации вашего шифра во время шифрования и дешифрования.

c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));

package com.samples;

import java.util.Scanner;
import java.io.File;
import java.io.IOException;

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.PrintWriter;
import java.io.FileWriter;  

// Don't forget to import any supporting classes you plan to use.

public class Crypto
{
    private Scanner fileText; 
    private PrintWriter fileEncrypt;
    private Scanner inputFile;
    private PrintWriter outputFile;

    private static final String ALGO = "AES/CBC/PKCS5Padding";
    private byte[] keyValue;

    public Crypto(String key)
    {
        keyValue = key.getBytes();
    }

    public String encrypt(String Data) throws Exception 
    {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public String decrypt(String encryptedData) throws Exception
    {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[16]));
        byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decodedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    public Key generateKey() throws Exception
    {
        Key key = new SecretKeySpec(keyValue, "AES");
        return key;
    }

    // encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
    // encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")

    public void encrypt_decrypt(String function_type, String source_file, String target_file)
    {
        String lineValue = ""; 
        String convertedValue = "";
        try
        {
            inputFile = new Scanner(new File(source_file));
        } 
        catch(Exception e)
        {
            System.out.println("( " + source_file + ") - File Opening Error");
        }
        try
        {
            outputFile = new PrintWriter(new FileWriter(target_file));
        }
        catch(Exception e)
        {
            System.out.println("( " + target_file + ") - File Opening Error");
        }

        while(inputFile.hasNext())
        { 
            lineValue = inputFile.nextLine();
            System.out.println("Source Line: " + lineValue);

            try
            {
                if (function_type == "ENCRYPT")
                {
                    convertedValue = encrypt(lineValue);
                }
                else if (function_type == "DECRYPT")
                {
                    convertedValue = decrypt(lineValue);
                }
            }
            catch(Exception e)
            {
                System.out.println(e);
            }
            System.out.println("Converted Line : " + convertedValue);

            outputFile.write(convertedValue);
        }

        inputFile.close();
        outputFile.close();
    }  

    public static void main( String args[] ) throws IOException
    {

        // Write your code here...
        // You will read from CryptoPlaintext.txt and write to CryptoCiphertext.txt.
        Crypto c = new Crypto("dk201anckse29sns");
        c.encrypt_decrypt("ENCRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt" 
                );
        c.encrypt_decrypt("DECRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt", 
                "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt");
        //
        // And then read from CryptoCiphertext.txt and write to CryptoDeciphered.txt.
        //
        // DON'T forget your comments!
        // =============================== DO NOT MODIFY ANY CODE BELOW HE     ==============================

        // Compare the files

        System.out.println(compareFiles() ? "The files are identical!" : "The files are NOT identical.");   
    }

    /**  
     *  Compares the Plaintext file with the Deciphered file.
     *
     *    @return  true if files match, false if they do not
     */

    public static boolean compareFiles() throws IOException
    {

        Scanner pt = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt")); // Open the       plaintext file
        Scanner dc = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt"));  // Open the       deciphered file

        // Read through the files and compare them record by record.
        // If any of the records do not match, the files are not identical.

        while(pt.hasNextLine() && dc.hasNextLine())
            if(!pt.nextLine().equals(dc.nextLine())) return false;

        // If we have any records left over, then the files are not identical.

        if(pt.hasNextLine() || dc.hasNextLine()) return false;

        // The files are identical.

        return true;




    }
}
...