【问题标题】:Converting string to SecretKey [duplicate]将字符串转换为 SecretKey [重复]
【发布时间】:2018-01-17 16:09:34
【问题描述】:

我正在 java 中实现 AES 算法。我正在将 SecretKey 转换为 String 并通过套接字传递给 server.java。在 server.java 中,我将此字符串转换回 SecretKey。但是,我收到了错误 如下所述。

我已经尝试了所有可能的解决方案,但没有一个对我有用。 在 client.java 中,我将 secKey 转换为 String

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

输出:

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

我已将此字符串转换回 SecretKey

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

输出 - de.flexiprovider.api.keys.SecretKeySpec@fffe87c2

在这里,两个输出不一样,我收到以下错误

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)

我该如何纠正这个错误?

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

客户端输出

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

【问题讨论】:

  • 我不知道你是怎么得到你的输出的,显示的代码 sn-ps 都没有写任何东西,它绝对不是字符串 encodedKey 的值(不是 base64 编码)。输出看起来像在 SecretKey 对象上调用 toString 的结果。要获得有意义的帮助,请确切地显示您在做什么。
  • 您提供的第一个代码永远不会给您输出de.flexiprovider.core.rijndael.RijndaelKey@714b1429。无论如何,您为什么要使用 Flexiprovidder? AES 集成在 Java 中。
  • 如果您在发送之前和接收之后打印密钥的编码形式(encodedKey,而不是 secKey),您会更好地了解您的问题secKey)。
  • 我试过这个stackoverflow.com/a/12039611/7403803。但它对我不起作用

标签: java aes secret-key


【解决方案1】:

我建议阅读Java 256-bit AES Password-Based Encryption。但这里有一个快速概述。您必须创建一个SecretKeyFactory、一个KeySpec,然后您可以根据KeySpec 生成您的SecretKey。从那里,您可以通过 SecretKeySpec 指定您的密钥是 AES。这里有一些你必须考虑的神奇数字。一个是密码迭代,另一个是密钥大小。对于我在下面创建的示例,我使用的是 128 密钥而不是 256。抱歉,我不是安全主题方面的专家,所以我使用了一些我拥有的示例。

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

希望这会对您有所帮助。

【讨论】:

    【解决方案2】:

    对于 Java 7 或更低版本:

    字符串的密钥:

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

    字符串到密钥:

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

    对于 Java 8:

    字符串的密钥:

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

    字符串到密钥:

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

    取自参考:https://stackoverflow.com/a/12039611/7403803

    【讨论】:

    • 我试过了,但它对我不起作用。我不明白我哪里出错了
    猜你喜欢
    • 2011-07-18
    • 1970-01-01
    • 2019-10-27
    • 2016-09-06
    • 1970-01-01
    • 2014-07-31
    相关资源
    最近更新 更多