运行代码时出现编译错误。
Error: javax.crypto.BadPaddingException: Data must start with zero
此行testClient.java
byte[] newPlainText = cipher.doFinal(cipherTextFromServer);
客户端无法解密从服务器加密的消息。 我的代码有什么问题吗?
// TestServer.java
public class TestServer {
public static void main(String[] args) throws Exception{
//set variables for port number, RSA key size
final int port = 3344;
final int RSAKeySize = 1024;
final String newline = "\n";
//set public key, sockets, server text, plain text
PublicKey pubKey = null;
PrivateKey priKey = null;
ServerSocket server = null;
Socket client = null;
String serverText = "Hello Client! This is an authentication message from server";
byte[] plainText = serverText.getBytes("UTF8");
//initialize RSA
try {
System.out.println("Start generating RSA key");
KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
RSAKeyGen.initialize(RSAKeySize,random);
KeyPair pair = RSAKeyGen.generateKeyPair();
System.out.println("Finish generating RSA key");
pubKey = pair.getPublic();
priKey = pair.getPrivate();
}catch (GeneralSecurityException e){
System.out.println(e.getLocalizedMessage() + newline);
System.out.println("Error initialising encryption. Exiting.\n");
System.exit(0);
}
//initialize cryptography, set cipherText
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
System.out.println("RSA cipher object and provider"+cipher.getProvider().getInfo());
System.out.println("Start Encryption for plainText");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(plainText);
System.out.println("Finish Encryption to cipherText: ");
BASE64Encoder base64 = new BASE64Encoder();
String encryptedValue = base64.encode(cipherText);
//String encryptedValue = new sun.misc.BASE64Encoder().encode(cipherText);
System.out.println(new String(cipherText,"UTF8"));
System.out.println("Base64");
System.out.println(encryptedValue);
//initialize socket connection
try{
server = new ServerSocket(port);
client = server.accept();
}catch(IOException e){
System.out.println("Error initialising I/O.\n");
System.exit(0);
}
//send server private key
try{
System.out.println("Send private key out");
System.out.println(DatatypeConverter.printHexBinary(priKey.getEncoded()));
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(priKey.getEncoded().length);
client.getOutputStream().write(bb.array());
client.getOutputStream().write(pubKey.getEncoded());
client.getOutputStream().flush();
}catch (IOException e){
System.out.println("I/O Error");
System.exit(0);
}
//send cipherText
ObjectOutputStream obOut = new ObjectOutputStream(client.getOutputStream());
obOut.writeObject(encryptedValue);
obOut.flush();
client.close();
}
}
// TestClient.java
public class TestClient {
public static void main(String[] args){
//throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, ClassNotFoundException,
//InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//set variable for port, socket, server public key
final int port = 3344;
Socket sock = null;
Key serverPubKey = null;
final int RSAKeySize = 1024;
final String newline = "\n";
Key priKey = null;
//setup connection by creating socket
try{
sock = new Socket(InetAddress.getLocalHost(),port);
}catch(UnknownHostException e){
System.out.println("Unknown host.");
System.exit(1);
}catch(IOException e){
System.out.println("No I/O");
System.exit(1);
}
//get public key from server
try{
byte[] lenb = new byte[4];
sock.getInputStream().read(lenb,0,4);
ByteBuffer bb = ByteBuffer.wrap(lenb);
int len = bb.getInt();
System.out.println(len);
byte[] servPubKeyBytes = new byte[len];
sock.getInputStream().read(servPubKeyBytes);
System.out.println(DatatypeConverter.printHexBinary(servPubKeyBytes));
X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
serverPubKey = kf.generatePublic(ks);
System.out.println(DatatypeConverter.printHexBinary(serverPubKey.getEncoded()));
//PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
}catch (IOException e) {
System.out.println("Error obtaining server public key 1.");
System.exit(0);
} catch (NoSuchAlgorithmException e) {
System.out.println("Error obtaining server public key 2.");
System.exit(0);
} catch (InvalidKeySpecException e) {
System.out.println("Error obtaining server public key 3.");
System.exit(0);
}
try {
System.out.println("Start generating RSA key");
KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
RSAKeyGen.initialize(RSAKeySize, random);
KeyPair pair = RSAKeyGen.generateKeyPair();
System.out.println("Finish generating RSA key");
priKey = pair.getPrivate();
}catch (GeneralSecurityException e){
System.out.println(e.getLocalizedMessage() + newline);
System.out.println("Error initialising encryption. Exiting.\n");
System.exit(0);
}
try{
//Decrypt message from server
BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String message = in.readLine();
//ObjectInputStream obIn = new ObjectInputStream(sock.getInputStream());
//Object obj = obIn.readObject();
System.out.println(message);
byte[] cipherTextFromServer = new BASE64Decoder().decodeBuffer(message);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
System.out.println("Start decryption");
cipher.init(Cipher.DECRYPT_MODE, priKey);
byte[] newPlainText = cipher.doFinal(cipherTextFromServer);
System.out.println("Finish decryption: ");
System.out.println(new String(newPlainText,"UTF8"));
sock.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
答案 0 :(得分:3)
您的代码看起来完全坏了。您使用服务器上生成的公钥加密数据,然后使用客户端上生成的私钥对其进行解密。这将永远不会奏效,因为密钥对不会匹配。
为了进一步混淆问题,似乎你试图在服务器和客户端之间发送密钥,但这看起来也很糟糕,例如。
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(priKey.getEncoded().length);
client.getOutputStream().write(bb.array());
client.getOutputStream().write(pubKey.getEncoded()); // pubKey?!!
你应该完全重新考虑你的设计。私钥通常不是集中生成的,而是向外分发的。相反,请考虑让您的客户端生成密钥对并将其公钥发送到服务器,服务器可以使用它来加密数据。
答案 1 :(得分:3)
您忽略了InputStream.read()
方法的返回值。
您正在使用ObjectOutputStream
在服务器端编写编码值,并使用InputStreamReader
在客户端读取它。
最终结果是servPubKeyBytes
和cipherTextFromServer
包含一些垃圾,当你将它们传递给密码时,它可以预测会中断。
首先,通过测试客户端是否正确读取所有数据来修复您的I / O代码。
其次,检查加密和解密代码是否可以在同一个应用程序中使用它,而不需要任何I / O.
第三,将工作I / O与工作的enc / dec代码结合起来。