使用 Java 进行 AES 加密和解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20796042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:23:25  来源:igfitidea点击:

AES Encryption and Decryption with Java

javaencryptioncryptographyaes

提问by Yogesh D

Here is what I am doing which can look a bit clumsy but any help is appreciated regarding the problem. I'm getting a BadPaddingException. Read almost all related topics but didn't find the appropriate solution. I am new to encryption decryption programming and need to implement it in one of my Java application.

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

Thank You.. this is how the code looks....

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

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();
            }






}

采纳答案by bgamlath

Here, what you have to understand is that cipher text may contain non-printable characters. So, when you use readLine(), it will likely not give you all of the bytes in the file.

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

Also, byteCipherText.toString()does not give you what you thought you would get. In java, the toString()method does not give the string representation of the contents of the array.

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

There is no need to add padding to encrypted text. It is already padded.

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

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);
    }
}

回答by Leri

You need to define what padding algorithm you use when you create instance of Cipher. Personally I use PKCS5.

您需要定义在创建Cipher. 我个人使用PKCS5.

So you should change:

所以你应该改变:

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

to:

到:

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

CBC stands for Cipher-block chaining.

CBC 代表密码块链接

CBCrequires IVto be passed. So you want to generate random IVand pass it in initmethod:

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);

Note:it's a good practice to avoid magical numbers/stringsin your code. I'd suggest to extract argument passes in Cipher#getInstanceto a constant.

注意:在代码中避免使用魔法数字/字符串是一个很好的做法。我建议提取参数传递Cipher#getInstance到一个常量。