【问题标题】:AES Encryption and Decryption with Java使用 Java 进行 AES 加密和解密
【发布时间】:2014-01-14 18:30:22
【问题描述】:

这是我正在做的事情,看起来有点笨拙,但对于这个问题的任何帮助表示赞赏。我收到了BadPaddingException。阅读几乎所有相关主题,但没有找到合适的解决方案。我是加密解密编程的新手,需要在我的一个 Java 应用程序中实现它。

谢谢你.. 这就是代码的样子......

public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    // TODO Auto-generated method stub
            String FileName="encryptedtext.txt";
            String FileName2="decryptedtext.txt";
            String pad="0"; 

            KeyGenerator KeyGen=KeyGenerator.getInstance("AES");
            KeyGen.init(128);

            SecretKey SecKey=KeyGen.generateKey();

            Cipher AesCipher=Cipher.getInstance("AES");
            AesCipher.init(Cipher.ENCRYPT_MODE,SecKey);

            byte[] byteText="My name is yogesh".getBytes();
            byte[] byteCipherText=AesCipher.doFinal(byteText);
            String cipherText = null;

            try {
                FileWriter fw=new FileWriter(FileName);
                BufferedWriter bw=new BufferedWriter(fw);
                bw.write(byteCipherText.toString());
                bw.close();
            }catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            try {
                FileReader fr=new FileReader(FileName);
                BufferedReader br=new BufferedReader(fr);
                cipherText=br.readLine();
                br.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            AesCipher.init(Cipher.DECRYPT_MODE,SecKey);
            while(((cipherText.getBytes().length)%16)!=0)
            {
                cipherText=cipherText+pad;


            }

            byte[] bytePlainText=AesCipher.doFinal(cipherText.getBytes());
            FileWriter fw1;
            try {
                fw1 = new FileWriter(FileName2);
                BufferedWriter bw1=new BufferedWriter(fw1);
                bw1.write(bytePlainText.toString());
                bw1.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }






}

【问题讨论】:

    标签: java encryption cryptography aes


    【解决方案1】:

    这里,你要明白的是,密文可能包含不可打印的字符。因此,当您使用 readLine() 时,它可能不会为您提供文件中的所有字节。

    另外,byteCipherText.toString() 并没有给你你认为你会得到的东西。在java中,toString()方法没有给出数组内容的字符串表示。

    无需为加密文本添加填充。它已经被填充了。

    import java.nio.file.Files;
    import java.nio.file.Paths;
    import javax.crypto.*;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
            String fileName = "encryptedtext.txt";
            String fileName2 = "decryptedtext.txt";
    
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(128);
    
            SecretKey secKey = keyGen.generateKey();
    
            Cipher aesCipher = Cipher.getInstance("AES");
    
    
            byte[] byteText = "Your Plain Text Here".getBytes();
    
            aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
            byte[] byteCipherText = aesCipher.doFinal(byteText);
            Files.write(Paths.get(fileName), byteCipherText);
    
    
            byte[] cipherText = Files.readAllBytes(Paths.get(fileName));
    
            aesCipher.init(Cipher.DECRYPT_MODE, secKey);
            byte[] bytePlainText = aesCipher.doFinal(cipherText);
            Files.write(Paths.get(fileName2), bytePlainText);
        }
    }
    

    【讨论】:

    • 请注意,这样的加密并不安全,因为它不使用 IV。在生产环境中使用此代码会非常愚蠢
    • @LukePark 如果为每个要加密的输入更改密钥文件,这会是一个坏主意吗?如果密钥只能使用一次,是否需要 IV?
    • @Allan5 有非常特殊的情况不需要静脉注射。例如,如果密钥不断变化并且您加密的块大小小于块大小(AES 为 128 位)。否则使用 IV。或者只使用一个。
    【解决方案2】:

    您需要定义创建Cipher 实例时使用的填充算法。我个人使用PKCS5

    所以你应该改变:

    Cipher AesCipher=Cipher.getInstance("AES");
    

    到:

    Cipher AesCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
    

    CBC 代表Cipher-block chaining

    CBC 要求 IV 被传递。所以你要生成随机的IV 并传入init 方法:

    byte[] iv = new byte[16];
    SecureRandom random = new SecureRandom();
    random.nextBytes(iv);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
    AesCipher.init(Cipher.ENCRYPT_MODE, SecKey, ivParameterSpec);
    

    注意:最好避免在代码中使用神奇的数字/字符串。我建议将Cipher#getInstance 中的参数传递提取到一个常量。

    【讨论】:

    • 是否进行了上述更改,但现在我在线程“main”java.security.InvalidKeyException 中遇到异常:缺少参数......异常
    • 我认为问题不在于填充方案。这是由于对文本文件与二进制文件和 java 数组的 toString() 方法的一些小误解。
    • @user3117915 更有可能IV 丢失了。
    • @bgamlath 更有可能,你是对的。但是,我总是喜欢在加密/解密之前进行填充,所以在大多数情况下我可以避免错误的填充。
    • @user3117915 更新了答案。
    猜你喜欢
    • 2021-04-27
    • 1970-01-01
    • 2014-11-17
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2016-03-15
    • 1970-01-01
    相关资源
    最近更新 更多