Converting string to SecretKey [duplicate]

☆樱花仙子☆ 提交于 2021-02-07 04:37:36

问题


I am implementing AES algorithm in java.I am converting SecretKey to String and passing to server.java through sockets. In server.java, I am converting this string back to SecretKey.However, I am getting the error mentioned below.

I have tried all possible solutions but nothing worked for me. In client.java, I am converting secKey to String

 String encodedKey = 
 Base64.getEncoder().encodeToString(secKey.getEncoded());
 System.out.println(secKey);

Output:

de.flexiprovider.core.rijndael.RijndaelKey@714b1429

I have converted this string back to SecretKey

 byte[] decodedKey = Base64.getDecoder().decode(line);
 SecretKey secKey = new SecretKeySpec(decodedKey, "AES");
 System.out.println(secKey);`

Output - de.flexiprovider.api.keys.SecretKeySpec@fffe87c2

Here, both outputs are not same and I am getting the following error

Exception in thread "main" java.security.InvalidKeyException: 
unsupported type
   at 
de.flexiprovider.api.BlockCipher.engineInit(BlockCipher.java:165)
   at de.flexiprovider.api.Cipher.engineInit(Cipher.java:68)
   at javax.crypto.Cipher.init(Cipher.java:1246)
   at javax.crypto.Cipher.init(Cipher.java:1186)
   at server.main(server.java:93)

How can I correct this error?

server.java

 import java.net.*;
   import java.io.*;
   import java.security.Security;
   import javax.crypto.*;
   import de.flexiprovider.api.keys.SecretKeySpec;
   import de.flexiprovider.core.FlexiCoreProvider;
   import de.flexiprovider.core.rijndael.RijndaelKeyFactory;
   import java.util.Base64;
   public class server {
    public final static int FILE_SIZE = 6022386; 
    private Socket          socket   = null;
    private ServerSocket    server   = null;
    private DataInputStream in       =  null;
    int bytesRead;
    int current = 0;
    FileOutputStream fos = null;
    BufferedOutputStream bos = null;
    static SecretKey secKey = null;


    public server(int port)
    {
        // starts server and waits for a connection
        try
        {
               server = new ServerSocket(port);
            System.out.println("Server started");
            System.out.println("Waiting for a client ...");
            socket = server.accept();
            System.out.println("Client accepted");



            // takes input from the client socket
            in = new DataInputStream(new 
      BufferedInputStream(socket.getInputStream()));
            String line = in.readUTF();

          byte[] decodedKey = Base64.getDecoder().decode(line);
            secKey = new SecretKeySpec(decodedKey, "AES"); 





            byte [] mybytearray  = new byte [FILE_SIZE];
            InputStream is = socket.getInputStream();
            fos = new FileOutputStream("cipher.txt");
            bos = new BufferedOutputStream(fos);
            bytesRead = is.read(mybytearray,0,mybytearray.length);
            current = bytesRead;
            do {
                bytesRead =
                   is.read(mybytearray, current, (mybytearray.length-
         current));
                if(bytesRead >= 0) current += bytesRead;
             } while(bytesRead > -1);
            bos.write(mybytearray, 0 , current);
            bos.flush();
            System.out.println("File Received" );

            // close connection
            socket.close();
            in.close();fos.close();bos.close();
        }
        catch(IOException i)
        {
            System.out.println(i);
        }
        }
       public static void main(String args[]) throws Exception
       {
        Security.addProvider(new FlexiCoreProvider());
        Cipher cipher = Cipher.getInstance("AES128_CBC", "FlexiCore");
        server ser = new server(5003);

        byte[] block = new byte[8];
        int i;

        String ciphertextFile = "cipher.txt";
        String cleartextAgainFile = "cleartextAgainSymm.txt";

        System.out.println(secKey);
        cipher.init(Cipher.DECRYPT_MODE, secKey);
        FileInputStream fis  = new FileInputStream(ciphertextFile);
        CipherInputStream cis = new CipherInputStream(fis, cipher);


    FileOutputStream  fos = new FileOutputStream(cleartextAgainFile);

            while ((i = cis.read(block)) != -1) {
                fos.write(block, 0, i);
            }
            fos.close();
           }
         }

server output

   Server started
Waiting for a client ...
Client accepted
File Received
de.flexiprovider.api.keys.SecretKeySpec@fffe8f6c
Exception in thread "main" java.security.InvalidKeyException: unsupported type
    at de.flexiprovider.api.BlockCipher.engineInit(BlockCipher.java:165)
    at de.flexiprovider.api.Cipher.engineInit(Cipher.java:68)
    at javax.crypto.Cipher.init(Cipher.java:1246)
    at javax.crypto.Cipher.init(Cipher.java:1186)

client.java

   import java.net.*;
import java.io.*;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import de.flexiprovider.api.keys.SecretKeySpec;
import de.flexiprovider.core.FlexiCoreProvider;

import java.util.Arrays;
import java.util.Base64;

public class Client {

    static SecretKey secKey;
    // initialize socket and input output streams
    private Socket socket            = null;
    private DataInputStream  input   = null;
    private DataOutputStream out     = null;
    FileInputStream fis;
    File myFile;
    BufferedInputStream bis = null;
    OutputStream os = null;

    public Client(String address, int port)
    {

        // establish a connection
        try
        {
            socket = new Socket(address, port);
            System.out.println("Connected");

            // takes input from terminal
            input  = new DataInputStream(System.in);

            // sends output to the socket
            out    = new DataOutputStream(socket.getOutputStream());


            String encodedKey = Base64.getEncoder().encodeToString(secKey.getEncoded());
            out.writeUTF(encodedKey);

             myFile = new File ("ciphertextSymm.txt");
             byte [] mybytearray  = new byte [(int)myFile.length()];
             fis=new FileInputStream(myFile);
             bis = new BufferedInputStream(fis);
             bis.read(mybytearray,0,mybytearray.length);
             os = socket.getOutputStream();
             System.out.println("Sending ");
             os.write(mybytearray,0,mybytearray.length);
             os.flush();
             System.out.println("Done.");

        }
        catch(UnknownHostException u)
        {
            System.out.println(u);
        }
        catch(IOException i)
        {
            System.out.println(i);
        }

        // close the connection
        try
        {
            input.close();
            out.close();
            socket.close();
            bis.close();
            os.close();
        }
        catch(IOException x)
        {
            System.out.println(x);
        }
    }
    public static void main(String args[]) throws Exception
    {
        Security.addProvider(new FlexiCoreProvider());
        Cipher cipher = Cipher.getInstance("AES128_CBC", "FlexiCore");
        KeyGenerator keyGen = KeyGenerator.getInstance("AES", "FlexiCore");
        secKey = keyGen.generateKey();


        System.out.println(secKey);
        cipher.init(Cipher.ENCRYPT_MODE, secKey);
        String cleartextFile = "cleartext.txt";
        String ciphertextFile = "ciphertextSymm.txt";

        FileInputStream fis = new FileInputStream(cleartextFile);
        FileOutputStream fos = new FileOutputStream(ciphertextFile);
        CipherOutputStream cos = new CipherOutputStream(fos, cipher);

        byte[] block = new byte[8];
        int i;
        while ((i = fis.read(block)) != -1) {
            cos.write(block, 0, i);
        }
        cos.close();

        Client client = new Client("127.0.0.1", 5003);
    }
}

client output

    de.flexiprovider.core.rijndael.RijndaelKey@7c226727
Connected
Sending 
Done.

回答1:


I would recommend to read Java 256-bit AES Password-Based Encryption. But here a quick overview. You will have to create a SecretKeyFactory, a KeySpec and then you can generate your SecretKey based on the KeySpec. From there, you can specify that your key is an AES through SecretKeySpec. There are some magic numbers here that you will have to consider. One is the password iterations, and the other the key sizes. For the example that I created below, I am using a 128 key instead of a 256. Sorry, I am not an expert in security topics so I used some examples that I have.

public static void main(String[] args) {
    try {
        //message to be encrypted
        final String message = "This is a test message";  
        final String password = "password";

        // Here the magic numbers
        final int pswdIterations = 65536;
        final int keySize = 128;

        final byte[] saltBytes = {0, 1, 2, 3, 4, 5, 6};

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Instantiate the cipher
        Cipher cipher = Cipher.getInstance("AES");

        // Encrypt
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] encrypted = cipher.doFinal(message.getBytes());
        System.out.println("Original string: " + message);
        System.out.println("Encrypted string: " + Arrays.toString(encrypted));

        // Decrypt
        cipher.init(Cipher.DECRYPT_MODE, secret);
        byte[] decrypt_original = cipher.doFinal(encrypted);
        String decrypt_originalString = new String(decrypt_original);
        System.out.println("Decrypt string: " + decrypt_originalString);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
        Logger.getLogger(Sandbox.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Hopefully, this will help you.




回答2:


For Java 7 or below:

Secret Key to String:

stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT);

String to Secret Key:

byte[] encodedKey     = Base64.decode(stringKey, Base64.DEFAULT);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

For Java 8:

Secret Key to String:

String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());

String to Secret Key:

byte[] decodedKey = Base64.getDecoder().decode(encodedKey);

SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); 

Taken from reference: https://stackoverflow.com/a/12039611/7403803



来源:https://stackoverflow.com/questions/48305410/converting-string-to-secretkey

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!