【发布时间】:2017-09-02 09:01:32
【问题描述】:
我正在尝试实现一个基本的 Diffie-Hellman 协议,并且代码在需要使用 DES 解密发送的值时成功。我看过很多例子,其中键不匹配的问题,但我在连接的两端打印它们的值,它们都是完全相同的。我还尝试了多种填充方案以及更改密钥的生成方式。
我最后一次尝试是将参数 IvParameterSpec 添加到密码初始化中,但这仅解决了一个错误。
我在套接字通过本地主机连接的单台机器上运行此程序,并且我一直在检查任何一方的任何问题,发送的数据与接收的数据不完全匹配,但发送中没有任何改变。但是,我确实注意到,当在套接字的任一侧打印每个字节数组时,客户端比服务器长得多,看起来像是填充(?)
我得到的错误是最后一个块被错误地填充,所以解密失败
我的服务器代码(未按预期工作的一侧):
public static void main(String[] args) {
ServerSocket welcomeSocket = null;
// Creates a connectable socket on port 6789
try {
welcomeSocket = new ServerSocket(6789);
} catch (IOException e) {
e.printStackTrace();
}
while(true){
try{
double k2, B, A;
double n = 13;
double g = 61;
long y = 7;
B = (Math.pow(g, y))%n;
System.out.println("Accepting connections");
// Accept an incoming connection on the socket server
Socket connectionSocket = welcomeSocket.accept();
// Creates a read and write stream for that client
DataInputStream inFromClient = new DataInputStream(connectionSocket.getInputStream());
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
// Sends the double to the client
outToClient.writeDouble(B);
System.out.println("Sent " + B);
// Reads the number sent by the Client
A = inFromClient.readDouble();
System.out.println("Received " + A);
// Modifies the number
k2 = (Math.pow(A, y))%n;
System.out.println("DES key seed = " + k2);
byte[] deskeydata = toByteArray(k2);
// Turns the bytes of the modified number into a DES key spec
DESKeySpec deskeyspec = new DESKeySpec(deskeydata);
// Makes a secret key (DES)
SecretKeyFactory keyF = SecretKeyFactory.getInstance("DES");
SecretKey keystuff = keyF.generateSecret(deskeyspec);
System.out.println(keystuff.toString());
// Gets an incoming string from the client and turns it into binary
byte[] incomingBytes = new byte[128];
try{
inFromClient.readFully(incomingBytes);
} catch(EOFException eof){
System.out.println("Finished reading");
}
System.out.println(new String(incomingBytes));
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
// Decrypts the string using the shared secret key
c.init(Cipher.DECRYPT_MODE, keystuff, new IvParameterSpec(new byte[8]));
byte[] ct2 = c.doFinal(incomingBytes);
// Decode it from base 64
//byte[] decodedBytes = Base64.getDecoder().decode(ct2);
// Prints the received string
System.out.println("Received: " + new String(ct2));
inFromClient.close();
outToClient.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
我的客户代码:
public static void main(String[] args) {
// Creates a socket to the local host on port 6789
Socket clientSocket = null;
try {
clientSocket = new Socket("localhost", 6789);
} catch (IOException e1) {
e1.printStackTrace();
}
try{
double k1, B, A;
double n = 13;
double g = 61;
long x = 3;
// Sends an unencrypted number to the server
A = (Math.pow(g, x))%n;
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream inFromServer = new DataInputStream(clientSocket.getInputStream());
// Transforms A into a byte array and sends it over
outToServer.writeDouble(A);
outToServer.flush();
System.out.println("Sending " + A);
// Reads the incoming data from the server
B = inFromServer.readDouble();
System.out.println("Recieved " + B);
// Modifies the data to create the number for des key
k1 = (Math.pow(B, x))%n;
System.out.println("DES key seed = " + k1);
byte[] deskeydata = toByteArray(k1);
// Turns the bytes of the modified number into a DES key spec
DESKeySpec deskeyspec = new DESKeySpec(deskeydata);
// Makes a secret key (DES)
SecretKeyFactory keyF = SecretKeyFactory.getInstance("DES");
SecretKey keystuff = keyF.generateSecret(deskeyspec);
System.out.println(keystuff.toString());
// Takes in input from the user and turns it into binary
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter a message:");
String sentence = inFromUser.readLine();
byte[] str2 = sentence.getBytes();
byte[] encodedMessage = Base64.getEncoder().encode(str2);
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
// Encrypts the user's input with the secret key
c.init(Cipher.ENCRYPT_MODE, keystuff, new IvParameterSpec(new byte[8]));
byte[] ct2 = c.doFinal(encodedMessage);
System.out.println("Initted the cipher and moving forward with " + new String(ct2));
// Writes the encrypted message to the user
outToServer.write(ct2);
outToServer.flush();
inFromServer.close();
outToServer.close();
} catch(Exception e){
e.printStackTrace();
}
}
任何可以帮助我解决这个问题的东西都会非常受欢迎,因为我已经独自解决这个错误很长一段时间了。
【问题讨论】:
-
你能比“没有按预期工作”更具体吗?实际错误/意外结果是什么?
-
调整了描述。这是一个 badpaddingexception 说最后一个块被错误地填充了
-
您正在客户端写入一个未知且长度可变的字节数组。在服务器端,您总是读取 128 个字节。这种不匹配可能是错误的来源。很明显还有其他的bug,比如client端base64编码,server端没有解码。
-
我认为这可能是问题所在,但我之前已经使用 rsa 加密字符串完成了这件事,并且假设字符串小于密钥,则根本没有遇到任何问题。至于base64,我在加密之前就这样编码了,问题是加密失败了,所以base64不应该影响我目前遇到的错误。我的想法是 readFully 函数正在从传输中剥离填充。那可能吗?否则,readfully 只会获取流中存在的字节数。
-
现在不要使用 DES。 它只提供 56 位的安全性。 AES 会更好,因为它使用 128 位的最低密钥大小更安全。 DES 的最大密文大小也有实际限制。见Security comparison of 3DES and AES。
标签: java sockets encryption des