2016-11-06 87 views
0

这个问题可能已经被问到了,但由于我很难理解密码学,特别是密钥处理,所以我不知道如何处理这个问题例外,也不在何处/如何找到解决方案。javax.crypto.BadPaddingException:给定的最终块在CipherInputStream中没有正确填充

我正在尝试写入和读取加密文件中的对象。 为此,我在DataInputStream下封装了一个CipherInputStream。

我得到了BadPadding异常,这可能意味着我在做关键的问题。

请帮帮我。

Main.java:

package main; 

import java.util.Arrays; 

import io.Io; 

public class Main { 
    static final String FIRST_TEXT_TO_CRYPTO = "First text"; 
    static final boolean BOOLEAN_CRYPTO = true; 
    static final String SECOND_TEXT_TO_CRYPTO = "First text"; 
    static final String KEY = "key123"; 

    public static void main(String[] args) { 
     Io.encryptAndWriteAll(Arrays.asList(new Stuff(FIRST_TEXT_TO_CRYPTO, BOOLEAN_CRYPTO, SECOND_TEXT_TO_CRYPTO)), 
       KEY); 

     for (Stuff stuff : Io.readAndDecryptAllFromLocation(KEY)) { 
      System.out.println(stuff); 
     } 
    } 
} 

Stuff.java

package main; 

import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.property.SimpleStringProperty; 

public class Stuff { 
    SimpleStringProperty firstString = new SimpleStringProperty(), secondString = new SimpleStringProperty(); 
    SimpleBooleanProperty bool = new SimpleBooleanProperty(); 

    public Stuff(String firstString, boolean bool, String secondString) { 
     this.firstString.set(firstString); 
     this.secondString.set(secondString); 
     this.bool.set(bool); 
    } 

    @Override 
    public String toString() { 
     return String.format("FirstString: %s; Boolean: %B; SecondString: %s", getFirstString(), isBool(), 
       getSecondString()); 
    } 

    public final SimpleStringProperty firstStringProperty() { 
     return this.firstString; 
    } 

    public final String getFirstString() { 
     return this.firstStringProperty().get(); 
    } 

    public final void setFirstString(final String firstString) { 
     this.firstStringProperty().set(firstString); 
    } 

    public final SimpleStringProperty secondStringProperty() { 
     return this.secondString; 
    } 

    public final String getSecondString() { 
     return this.secondStringProperty().get(); 
    } 

    public final void setSecondString(final String secondString) { 
     this.secondStringProperty().set(secondString); 
    } 

    public final SimpleBooleanProperty boolProperty() { 
     return this.bool; 
    } 

    public final boolean isBool() { 
     return this.boolProperty().get(); 
    } 

    public final void setBool(final boolean bool) { 
     this.boolProperty().set(bool); 
    } 

} 

Io.java:

package io; 

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.EOFException; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.UTFDataFormatException; 
import java.util.ArrayList; 
import java.util.List; 

import javax.crypto.CipherInputStream; 
import javax.crypto.CipherOutputStream; 

import main.Stuff; 

public class Io { 
    private static final File FILE = new File("file.file"); 

    public static void encryptAndWriteAll(List<Stuff> stuffs, String key) { 
     try (FileOutputStream fos = new FileOutputStream(FILE); 
       BufferedOutputStream bos = new BufferedOutputStream(fos); 
       CipherOutputStream cos = new CipherOutputStream(bos, new Crypto(key).getEncryptionCipher()); 
       DataOutputStream dos = new DataOutputStream(cos)) { 
      for (Stuff stuff : stuffs) { 
       dos.writeUTF(stuff.getFirstString()); 
       dos.writeBoolean(stuff.isBool()); 
       dos.writeUTF(stuff.getSecondString()); 
      } 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static List<Stuff> readAndDecryptAllFromLocation(String key) { 
     try (FileInputStream fis = new FileInputStream(FILE); 
       BufferedInputStream bis = new BufferedInputStream(fis); 
       CipherInputStream cis = new CipherInputStream(bis, new Crypto(key).getDecryptionCipher()); 
       DataInputStream dis = new DataInputStream(cis)) { 
      ArrayList<Stuff> stuffs = new ArrayList<>(); 
      try { 
       for (;;) 
        // The next line throws 
        // ("at io.Io.readAndDecryptAllFromLocation(Io.java:52)") 
        stuffs.add(new Stuff(dis.readUTF(), dis.readBoolean(), dis.readUTF())); 
      } catch (EOFException e) { 
       System.out.println("EOF"); 
       e.printStackTrace(); 
      } catch (UTFDataFormatException e) { 
       e.printStackTrace(); 
      } 
      return stuffs; 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 

Crypto.java:

package io; 

import java.security.InvalidKeyException; 
import java.security.Key; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import java.util.Arrays; 

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

public class Crypto { 

    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; 
    private static final String ALGORITHM = "AES"; 
    private byte[] paddedKey; 

    public Crypto(String key) { 
     paddedKey = addPaddingToKey(key); 
    } 

    private byte[] addPaddingToKey(String key) { 
     try { 
      MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
      return Arrays.copyOf(digest.digest(key.getBytes()), 16); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private Key getKey() { 
     return new SecretKeySpec(paddedKey, ALGORITHM); 
    } 

    public Cipher getEncryptionCipher() { 
     try { 
      Cipher cipher = Cipher.getInstance(TRANSFORMATION); 
      cipher.init(Cipher.ENCRYPT_MODE, getKey()); 
      return cipher; 
     } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public Cipher getDecryptionCipher() { 
     try { 
      Cipher cipher = Cipher.getInstance(ALGORITHM); 
      cipher.init(Cipher.DECRYPT_MODE, getKey()); 
      return cipher; 
     } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

} 

例外:

java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded 
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:121) 
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:239) 
    at java.io.DataInputStream.readFully(DataInputStream.java:195) 
    at java.io.DataInputStream.readUTF(DataInputStream.java:609) 
    at java.io.DataInputStream.readUTF(DataInputStream.java:564) 
    at io.Io.readAndDecryptAllFromLocation(Io.java:52) 
    at main.Main.main(Main.java:17) 
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:975) 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833) 
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) 
    at javax.crypto.Cipher.doFinal(Cipher.java:2048) 
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:118) 
    ... 6 more 
Exception in thread "main" java.lang.NullPointerException 
    at main.Main.main(Main.java:17) 
+0

提供[mcve],IOW只是所需的代码。 – zaph

回答

2

您正在使用AES/CBC,这将需要IV参数。如果您没有指定IV参数,则会生成并使用加密随机IV。

您可以随机生成IV并将其预先加到加密数据中,因为IV不需要保密。

+2

更好的是,加密在加密数据前面加上IV,它不需要保密。这样它可用于解密。 – zaph

+1

不使用随机IV是不安全的,存储IV并重用它只在加密/解密在相同位置执行时才起作用。因此,尽管您可能已经发现了这个问题,但所提供的解决方案无法解决(安全地)。 –

+0

那么,如果我在每次将数据加密到文件时预先安排随机生成的IV,那么可以吗?或者,我应该如何存储随机产生的IV? – SlumpA

相关问题