java.security.spec.InvalidKeySpecException and Inappropriate key specification error in java program

15,972

Ciphertext and keys should both consist of random bytes. Neither one of them can be represented 1:1 with a string. Not all bytes may represent valid encodings for a specific .

Instead you should use byte arrays directly. If you require actual text, use either hexadecimals or base 64 .

Your code using ciphertext as bytes and a key specified in hexadecimals:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;

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

import codec.Hex;

public class Pgm {
    public static void main(String[] args) {
        try {
            KeyPairGenerator dsa = KeyPairGenerator.getInstance("DSA");
            SecureRandom random = new SecureRandom();
            dsa.initialize(1024, random);
            KeyPair keypair = dsa.generateKeyPair();
            PrivateKey privateKey = (PrivateKey) keypair.getPrivate();
            byte[] key = Hex.decode("000102030405060708090A0B0C0D0E0F");
            Key aesKey = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            String currentDir = System.getProperty("user.dir");
            // encrypt the text
            cipher.init(Cipher.ENCRYPT_MODE, aesKey);
            byte[] abc = privateKey.getEncoded();

            byte[] encrypted = cipher.doFinal(abc);
            // System.out.println("len="+encrypted.length());
            File dir = new File(currentDir);
            File private_file = new File(dir, "privatekey.txt");
            if (!private_file.exists()) {
                private_file.createNewFile();
            }
            FileOutputStream fileos = new FileOutputStream(private_file);
            ObjectOutputStream objectos = new ObjectOutputStream(fileos);
            objectos.writeObject(encrypted);
            objectos.close();
            fileos.close();

            File file_private = new File(dir, "privatekey.txt");
            FileInputStream fileo = new FileInputStream(file_private);
            ObjectInputStream objos = new ObjectInputStream(fileo);
            Object obj = objos.readObject();
            byte[] encrypted1 = (byte[]) obj;
            cipher.init(Cipher.DECRYPT_MODE, aesKey);
            byte[] decrypted = cipher.doFinal(encrypted1);
            if (Arrays.equals(decrypted, abc))
                System.out.println("true");
            else
                System.out.println("false");
            Signature tosign = Signature.getInstance("DSA");

            KeyFactory generator = KeyFactory.getInstance("DSA");
            EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decrypted);
            PrivateKey privatekey1 = generator.generatePrivate(privateKeySpec);
            tosign.initSign(privatekey1);

        } catch (Exception e) {
            System.out.println("failed");
            e.printStackTrace();
        }
    }
}
Share:
15,972
user123
Author by

user123

Updated on June 04, 2022

Comments

  • user123
    user123 almost 2 years

    As a part of project implementation,I have done: 1. Generete DSA keys 2. Encrypt the private key using AES 3. Save into the file 4. Open the file and read the encrypted private key 5. I tried to convert the read value into primary key format

    import java.security.spec.EncodedKeySpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.Security;
    import java.io.File;
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.Signature;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.io.*;
    import java.security.*;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.SecretKeySpec;
    
    public class Pgm {
        public static void main(String[] args) {
            try {
                KeyPairGenerator dsa = KeyPairGenerator.getInstance("DSA");
                SecureRandom random = new SecureRandom();
                dsa.initialize(1024, random);
                KeyPair keypair = dsa.generateKeyPair();
                PrivateKey privateKey = (PrivateKey) keypair.getPrivate();
                byte[] key = "�u���1�iw&a".getBytes();
                Key aesKey = new SecretKeySpec(key, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                String currentDir = System.getProperty("user.dir");
                // encrypt the text
                cipher.init(Cipher.ENCRYPT_MODE, aesKey);
                byte[] abc = privateKey.getEncoded();
    
                byte[] encrypted = cipher.doFinal(abc);
                // System.out.println("len="+encrypted.length());
                File dir = new File(currentDir);
                File private_file = new File(dir, "privatekey.txt");
                if (!private_file.exists()) {
                    private_file.createNewFile();
                }
                FileOutputStream fileos = new FileOutputStream(private_file);
                ObjectOutputStream objectos = new ObjectOutputStream(fileos);
                objectos.writeObject(encrypted);
                objectos.close();
                fileos.close();
    
                File file_private = new File(dir, "privatekey.txt");
                FileInputStream fileo = new FileInputStream(file_private);
                ObjectInputStream objos = new ObjectInputStream(fileo);
                Object obj = objos.readObject();
                byte[] encrypted1 = (byte[]) obj;
                cipher.init(Cipher.DECRYPT_MODE, aesKey);
                String decrypted = new String(cipher.doFinal(encrypted1));
                if (decrypted.equals(new String(abc)))
                    System.out.println("true");
                else
                    System.out.println("false");
                Signature tosign = Signature.getInstance("DSA");
                byte[] val = decrypted.getBytes();
    
                KeyFactory generator = KeyFactory.getInstance("DSA");
                EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(val);
                PrivateKey privatekey1 = generator.generatePrivate(privateKeySpec);
                tosign.initSign(privatekey1);
    
            } catch (Exception e) {
                System.out.println("failed");
                e.printStackTrace();
    
            }
    
        }
    }
    

    While I am trying to execute the above code, it shows the following error!

    screen shot of output screen

  • Maarten Bodewes
    Maarten Bodewes over 9 years
    I've now used the Hex codec from Apache Codec, but you can of course use any encoding. Base 64 encoding is now supported by default in Java 8, but hex isn't yet (at least not in one of the util packages).
  • user123
    user123 over 9 years
    Thank you for your reply. Now the code is working. The problem in my code is an unwanted conversion from byte[] to string and back from string to byte[]. 'String decrypted = new String(cipher.doFinal(encrypted1));'