Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
153 views
in Technique[技术] by (71.8m points)

java - Why does my AES encryption throws an InvalidKeyException?

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();
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...