问题
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