为什么我的 AES 加密会抛出 InvalidKeyException? [英] Why does my AES encryption throws an InvalidKeyException?

查看:18
本文介绍了为什么我的 AES 加密会抛出 InvalidKeyException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在研究使用密钥加密/解密特定文件的函数.我写了三个类,一个生成密钥,一个用密钥加密文件,一个解密.

生成密钥并加密文件工作正常,但是当我尝试解密文件时,在以下行抛出异常:c.init(Cipher.DECRYPT_MODE, keySpec);:<块引用>

java.security.InvalidKeyException:缺少参数

我认为我在将密钥流式传输到我的 byte[] 时做错了什么,或者在解密文件时出现了一些错误.

三个类的快速解释: KeyHandler 创建一个 AES 密钥并将其存储在硬盘上.出于测试目的,密钥/明文/加密/解密文件的名称目前是硬编码的.

EncryptionHandler 将磁盘上的 .txt 文件转换为字节,使用密钥加密文件,然后使用 CipherOutputStream 将加密的字节写入磁盘.

DecryptionHandler 当然与 EncryptionHandler 相反.

代码如下:

 公共类 KeyHandler {Scanner scan = new Scanner(System.in);公共密钥处理程序(){尝试 {开始菜单();} 捕获(异常 e){System.out.println("fel någonstanns :)");}}public void startMenu() 抛出异常{System.out.println("Hej. Med detta program kan du generera en hemlig nyckel"+"
"+"Vill du:"+"
"+ "1. Generera en nyckel"+"
"+"2. Avsluta");int val=Integer.parseInt(scan.nextLine());做{开关(值){情况 1: generateKey();休息;情况2:System.exit(1);默认值:System.out.println("Du måste välja val 1 eller 2");}}而 (val!=3);}public void generateKey() 抛出异常{尝试 {KeyGenerator gen = KeyGenerator.getInstance("AES");gen.init(128);SecretKey 密钥=gen.generateKey();byte[] keyBytes = key.getEncoded();System.out.print("Ge nyckeln ett filnamn:");字符串文件名 = scan.next();System.out.println("通用nyckeln...");FileOutputStream fileOut = new FileOutputStream(filename);fileOut.write(keyBytes);fileOut.close();System.out.println("Nyckeln ärgenererad med filnamnet: "+filename+"...");System.exit(1);} catch (NoSuchAlgorithmException e) {}}公共静态无效主(字符串 [] args){新的 KeyHandler();}}公共类 EncryptHandler {私人字符串加密数据字符串;私人密码;AlgorithmParameterSpec paramSpec;字节[]四;public EncryptHandler(String dataString, String secretKey, String encryptedDataString){this.encryptedDataString=encryptedDataString;尝试 {encryptFile(dataString,secretKey);} 捕获(异常 e){}}public void encryptFile(String dataString, String secretKey) 抛出异常{FileInputStream fis = new FileInputStream(secretKey);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1){baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");尝试{ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");ecipher.init(Cipher.ENCRYPT_MODE, keySpec);}捕获(例外 e){e.printStackTrace();}System.out.println("正在加密文件...");尝试{encryptStream(new FileInputStream(dataString),new FileOutputStream(encryptedDataString));}捕获(异常 e){e.printStackTrace();}}公共无效加密流(输入流输入,输出流输出){ByteArrayOutputStream bOut = new ByteArrayOutputStream();字节[] buf = 新字节[1024];尝试 {out = new CipherOutputStream(out, ecipher);//读取明文并将其写出int numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}bOut.writeTo(out);关闭();bOut.reset();}捕获 (java.io.IOException e){}}公共静态无效主(字符串 [] args){字符串数据 = "test.txt";字符串 keyFileName="a";String encryptedFile="krypterad.txt";//String encryptedFile =args[2];新的 EncryptHandler(data, keyFileName, encryptedFile);}}公共类 DecryptHandler {公共解密处理程序(){尝试 {解密文件();} 捕获(异常 e){System.out.println("något gick fel :)");}}公共无效解密文件()抛出异常{字节[] buf = 新字节[1024];String keyFilename = "hemlig";FileInputStream fis = new FileInputStream(keyFilename);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1){baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");System.out.println("här");c.init(Cipher.DECRYPT_MODE, keySpec);System.out.println("正在解密文件...");尝试{解密流(新文件输入流(krypterad.txt"),新文件输出流(Dekryperad.txt"),c,buf);}抓住(java.io.IOException e){}System.out.println("文件解密!");}公共无效解密流(输入流输入,输出流输出,密码dcipher,字节[] buf){尝试{in = new CipherInputStream(in, dcipher);//读入解密的字节并将明文写入 outint numRead = 0;while ((numRead = in.read(buf)) >= 0){out.write(buf, 0, numRead);}关闭();}抓住(java.io.IOException e){}}public static void main(String[]args){新的解密处理程序();}}

解决方案

如果你使用像 CBC 这样的区块链模式,你还需要为 Cipher 提供一个 IvParameterSpec.

所以你可以像这样初始化一个 IvParameterSpec:

//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);

然后为了加密,将您初始化密码的代码更改为:

ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);

以及你解密的地方:

c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);

所以你的完整代码应该是这样的(它对我有用):

 公共类 KeyHandler {Scanner scan = new Scanner(System.in);公共 KeyHandler() {尝试 {开始菜单();} 捕获(异常 e){System.out.println("fel någonstanns :)");}}public void startMenu() 抛出异常 {System.out.println("Hej. Med detta program kan du generera en hemlig nyckel" + "
" + "Vill du:" + "
" + "1. Generera en nyckel" + "
" + "2. Avsluta");int val = Integer.parseInt(scan.nextLine());做 {开关(值){情况1:生成密钥();休息;案例2:System.exit(1);默认:System.out.println("Du måste välja val 1 eller 2");}} while (val != 3);}public void generateKey() 抛出异常 {尝试 {KeyGenerator gen = KeyGenerator.getInstance("AES");gen.init(128);SecretKey 密钥 = gen.generateKey();byte[] keyBytes = key.getEncoded();System.out.print("Ge nyckeln ett filnamn:");字符串文件名 = scan.next();System.out.println("通用nyckeln...");FileOutputStream fileOut = new FileOutputStream(filename);fileOut.write(keyBytes);fileOut.close();System.out.println("Nyckeln ärgenererad med filnamnet: " + 文件名 + "...");System.exit(1);} catch (NoSuchAlgorithmException e) {}}公共静态无效主(字符串 [] args){新的 KeyHandler();}}公共类 EncryptHandler {私人字符串加密数据字符串;私人密码;AlgorithmParameterSpec paramSpec;字节[]四;public EncryptHandler(String dataString, String secretKey, String encryptedDataString) {this.encryptedDataString = encryptedDataString;尝试 {encryptFile(dataString,secretKey);} 捕获(异常 e){}}public void encryptFile(String dataString, String secretKey) 抛出异常 {FileInputStream fis = new FileInputStream(secretKey);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1) {baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);尝试 {ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);} 捕获(异常 e){e.printStackTrace();}System.out.println("正在加密文件...");尝试 {encryptStream(new FileInputStream(dataString), new FileOutputStream(encryptedDataString));} 捕获(异常 e){e.printStackTrace();}}公共无效加密流(输入流输入,输出流输出){ByteArrayOutputStream bOut = new ByteArrayOutputStream();字节[] buf = 新字节[1024];尝试 {out = new CipherOutputStream(out, ecipher);//读取明文并将其写出int numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}bOut.writeTo(out);关闭();bOut.reset();} catch (java.io.IOException e) {}}公共静态无效主(字符串 [] args){字符串数据 = "test.txt";String keyFileName = "a";String encryptedFile = "krypterad.txt";//String encryptedFile =args[2];新的 EncryptHandler(data, keyFileName, encryptedFile);}}公共类 DecryptHandler {公共解密处理程序(){尝试 {解密文件();} 捕获(异常 e){e.printStackTrace();System.out.println("något gick fel :)");}}公共无效解密文件()抛出异常{字节[] buf = 新字节[1024];String keyFilename = "hemlig";FileInputStream fis = new FileInputStream(keyFilename);ByteArrayOutputStream baos = new ByteArrayOutputStream();int theByte = 0;while ((theByte = fis.read()) != -1) {baos.write(theByte);}fis.close();byte[] keyBytes = baos.toByteArray();baos.close();SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");//构建初始化向量.这个例子全为零,但它//可以是任何值或使用随机数生成器生成.byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };IvParameterSpec ivspec = 新的 IvParameterSpec(iv);Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");System.out.println("här");c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);System.out.println("正在解密文件...");尝试 {解密流(新文件输入流(krypterad.txt"),新文件输出流(Dekryperad.txt"),c,buf);} catch (java.io.IOException e) {}System.out.println("文件解密!");}公共无效解密流(输入流输入,输出流输出,密码密码,字节[] buf){尝试 {in = new CipherInputStream(in, dcipher);//读入解密的字节并将明文写入 outint numRead = 0;while ((numRead = in.read(buf)) >= 0) {out.write(buf, 0, numRead);}关闭();} catch (java.io.IOException e) {}}公共静态无效主(字符串 [] args){新的解密处理程序();}}

I'm currently working on a function that encrypt/decrypts a specific file with a secret key. I have written three classes, one which generates a key, one which encrypts a file with the key and one that decrypts.

Generating the key and encrypting the file works fine, but when I try to decrypt the file, an exception is thrown at line: c.init(Cipher.DECRYPT_MODE, keySpec);:

java.security.InvalidKeyException: Parameters missing

I take it I've done something wrong when streaming the secret key to my byte[] or something is wrong when decrypting the file.

Quick explanation of the three classes: KeyHandler creates a AES key and stores it on the harddrive. The name of the key/plaintext/encrypted/decrypted files is currently hardcoded for testing purposes.

EncryptionHandler transfers a .txt file on the disk into bytes, encrypts the file with the secret key and then writes the encrypted bytes to the disk using CipherOutputStream.

DecryptionHandler of course does the opposite of EncryptionHandler.

Here's the code:

    public class KeyHandler {
        Scanner scan = new Scanner(System.in);

        public KeyHandler(){
            try {
                startMenu();
            } catch (Exception e) {
                System.out.println("fel någonstanns :)");
            }
        }

        public void startMenu() throws Exception{

            System.out.println("Hej. Med detta program kan du generera en hemlig nyckel"+"
"+"Vill du:"+"
"+ "1. Generera en nyckel"+"
"+"2. Avsluta");
            int val=Integer.parseInt(scan.nextLine());
        do{ 
            switch (val){
            case 1: generateKey(); break;
            case 2: System.exit(1);

            default: System.out.println("Du måste välja val 1 eller 2");
            }
        }
            while (val!=3);
        }

        public void generateKey() throws Exception{
            try {
                KeyGenerator gen = KeyGenerator.getInstance("AES");
                gen.init(128);

                SecretKey key=gen.generateKey();
                byte[] keyBytes = key.getEncoded();
                System.out.print("Ge nyckeln ett filnamn: ");
                String filename = scan.next();
                System.out.println("Genererar nyckeln...");
                FileOutputStream fileOut = new FileOutputStream(filename);
                fileOut.write(keyBytes);
                fileOut.close();
                System.out.println("Nyckeln är genererad med filnamnet: "+filename+"...");
                System.exit(1);
                 } catch (NoSuchAlgorithmException e) {
                    }

        }

        public static void main(String[] args){
            new KeyHandler();
        }

    }


    public class EncryptHandler {
        private String encryptedDataString;
        private Cipher ecipher; 

        AlgorithmParameterSpec paramSpec;
        byte[] iv;

        public EncryptHandler(String dataString, String secretKey, String encryptedDataString){
            this.encryptedDataString=encryptedDataString;
            try {
                encryptFile(dataString, secretKey);
            } catch (Exception e) {

            }
        }

            public void encryptFile(String dataString, String secretKey) throws Exception{

                    FileInputStream fis = new FileInputStream(secretKey);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();

                    int theByte = 0;
                    while ((theByte = fis.read()) != -1)
                    {
                      baos.write(theByte);
                    }
                    fis.close();

                    byte[] keyBytes = baos.toByteArray();
                    baos.close();
                    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

                try 
                { 
                ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
                ecipher.init(Cipher.ENCRYPT_MODE, keySpec);     

                } 
                catch (Exception e) 
                    { 
                e.printStackTrace(); 
            } 

                System.out.println("Encrypting file...");
                try 
                { 

                    encryptStream(new FileInputStream(dataString),new FileOutputStream(encryptedDataString)); 
                }
                catch(Exception e){
                e.printStackTrace();
                }

                }
    public void encryptStream(InputStream in, OutputStream out){
                ByteArrayOutputStream bOut = new ByteArrayOutputStream();
                byte[] buf = new byte[1024]; 
                try { 
                out = new CipherOutputStream(out, ecipher); 

             // read the cleartext and write it to out
                int numRead = 0; 
                while ((numRead = in.read(buf)) >= 0) {
                out.write(buf, 0, numRead); 

                }
                bOut.writeTo(out);
                out.close();
                bOut.reset();

                } 
                catch (java.io.IOException e) 
                { 
                } 

                }


        public static void main(String[] args){
            String data = "test.txt";
            String keyFileName="a";
            String encryptedFile="krypterad.txt";
            //String encryptedFile =args[2];
            new EncryptHandler(data, keyFileName, encryptedFile);
        }

    }


public class DecryptHandler {
    public DecryptHandler(){

    try {
        decryptFile();
    } catch (Exception e) {
        System.out.println("något gick fel :) ");
        }
    }


    public void decryptFile()throws Exception{
        byte[] buf = new byte[1024]; 
        String keyFilename = "hemlig";
        FileInputStream fis = new FileInputStream(keyFilename);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int theByte = 0;
        while ((theByte = fis.read()) != -1)
        {
          baos.write(theByte);
        }
        fis.close();

        byte[] keyBytes = baos.toByteArray();
        baos.close();
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");


        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
                System.out.println("här");
        c.init(Cipher.DECRYPT_MODE, keySpec); 

        System.out.println("Decrypting file...");
        try{
        decryptStream(new FileInputStream("krypterad.txt"),new FileOutputStream("Dekryperad.txt"), c, buf);
        }
            catch (java.io.IOException e){

            }
            System.out.println("File decrypted!");
        }
    public void decryptStream(InputStream in, OutputStream out, Cipher dcipher, byte[] buf){
        try 
        { 

        in = new CipherInputStream(in, dcipher); 

        // Read in the decrypted bytes and write the cleartext to out 
        int numRead = 0; 


        while ((numRead = in.read(buf)) >= 0) 
        { 
        out.write(buf, 0, numRead);

        } 
        out.close();


        } 
        catch (java.io.IOException e){ 

        } 
    } 
    public static void main(String[]args){
        new DecryptHandler();
    }
}

解决方案

If you use a block-chaining mode like CBC, you need to provide an IvParameterSpec to the Cipher as well.

So you can initialize an IvParameterSpec like this:

    // build the initialization vector.  This example is all zeros, but it 
    // could be any value or generated using a random number generator.
    byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);

Then for encryption, change your code where you init the cipher to this:

ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);

And where you decrypt:

c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);

So your complete code should look like this (It works for me):

    public class KeyHandler {

    Scanner scan = new Scanner(System.in);

    public KeyHandler() {
        try {
            startMenu();
        } catch (Exception e) {
            System.out.println("fel någonstanns :)");
        }
    }

    public void startMenu() throws Exception {

        System.out.println("Hej. Med detta program kan du generera en hemlig nyckel" + "
" + "Vill du:" + "
" + "1. Generera en nyckel" + "
" + "2. Avsluta");
        int val = Integer.parseInt(scan.nextLine());
        do {
            switch (val) {
                case 1:
                    generateKey();
                    break;
                case 2:
                    System.exit(1);

                default:
                    System.out.println("Du måste välja val 1 eller 2");
            }
        } while (val != 3);
    }

    public void generateKey() throws Exception {
        try {
            KeyGenerator gen = KeyGenerator.getInstance("AES");
            gen.init(128);

            SecretKey key = gen.generateKey();
            byte[] keyBytes = key.getEncoded();
            System.out.print("Ge nyckeln ett filnamn: ");
            String filename = scan.next();
            System.out.println("Genererar nyckeln...");
            FileOutputStream fileOut = new FileOutputStream(filename);
            fileOut.write(keyBytes);
            fileOut.close();
            System.out.println("Nyckeln är genererad med filnamnet: " + filename + "...");
            System.exit(1);
        } catch (NoSuchAlgorithmException e) {
        }

    }

    public static void main(String[] args) {
        new KeyHandler();
    }
}

public class EncryptHandler {

    private String encryptedDataString;
    private Cipher ecipher;
    AlgorithmParameterSpec paramSpec;
    byte[] iv;

    public EncryptHandler(String dataString, String secretKey, String encryptedDataString) {
        this.encryptedDataString = encryptedDataString;
        try {
            encryptFile(dataString, secretKey);
        } catch (Exception e) {
        }
    }

    public void encryptFile(String dataString, String secretKey) throws Exception {

        FileInputStream fis = new FileInputStream(secretKey);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int theByte = 0;
        while ((theByte = fis.read()) != -1) {
            baos.write(theByte);
        }
        fis.close();

        byte[] keyBytes = baos.toByteArray();
        baos.close();
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        // build the initialization vector.  This example is all zeros, but it 
        // could be any value or generated using a random number generator.
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        try {
            ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            ecipher.init(Cipher.ENCRYPT_MODE, keySpec, ivspec);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("Encrypting file...");
        try {

            encryptStream(new FileInputStream(dataString), new FileOutputStream(encryptedDataString));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void encryptStream(InputStream in, OutputStream out) {
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        try {
            out = new CipherOutputStream(out, ecipher);

            // read the cleartext and write it to out
            int numRead = 0;
            while ((numRead = in.read(buf)) >= 0) {
                out.write(buf, 0, numRead);

            }
            bOut.writeTo(out);
            out.close();
            bOut.reset();

        } catch (java.io.IOException e) {
        }

    }

    public static void main(String[] args) {
        String data = "test.txt";
        String keyFileName = "a";
        String encryptedFile = "krypterad.txt";
        //String encryptedFile =args[2];
        new EncryptHandler(data, keyFileName, encryptedFile);
    }
}

public class DecryptHandler {

    public DecryptHandler() {

        try {
            decryptFile();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("något gick fel :) ");
        }
    }

    public void decryptFile() throws Exception {
        byte[] buf = new byte[1024];
        String keyFilename = "hemlig";
        FileInputStream fis = new FileInputStream(keyFilename);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int theByte = 0;
        while ((theByte = fis.read()) != -1) {
            baos.write(theByte);
        }
        fis.close();

        byte[] keyBytes = baos.toByteArray();
        baos.close();
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        // build the initialization vector.  This example is all zeros, but it 
        // could be any value or generated using a random number generator.
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        System.out.println("här");
        c.init(Cipher.DECRYPT_MODE, keySpec, ivspec);

        System.out.println("Decrypting file...");
        try {
            decryptStream(new FileInputStream("krypterad.txt"), new FileOutputStream("Dekryperad.txt"), c, buf);
        } catch (java.io.IOException e) {
        }
        System.out.println("File decrypted!");
    }

    public void decryptStream(InputStream in, OutputStream out, Cipher dcipher, byte[] buf) {
        try {

            in = new CipherInputStream(in, dcipher);

            // Read in the decrypted bytes and write the cleartext to out 
            int numRead = 0;


            while ((numRead = in.read(buf)) >= 0) {
                out.write(buf, 0, numRead);

            }
            out.close();


        } catch (java.io.IOException e) {
        }
    }

    public static void main(String[] args) {
        new DecryptHandler();
    }
}

这篇关于为什么我的 AES 加密会抛出 InvalidKeyException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆