Reputation: 13850
I've programmed the following client-server pair to set up a very simplified version of an IPSec-connection (Cryptography-related).
The problem is, that on the second call to readObject(), i.e.:
// Receive finished message from server
finishedMessage = (BigInteger) inputStream.readObject();
I get a java.io.EOFException.
It should be said, that on most runs the EOFException
is thrown, but on some runs it runs flawlessly ?
I've been debugging for hours now, but can't find the error.
If anyone can see the error, please let me know - I will appreciate it !
Error message:
[CLIENT]: Connected...
[CLIENT]: Common key = 33569
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at IPSecClient.SetupSSLConnection(IPSecClient.java:68)
at IPSecClient.main(IPSecClient.java:116)
Client:
import java.math.BigInteger;
import java.net.*;
import java.util.ArrayList;
import java.util.Random;
import java.io.*;
public class IPSecClient {
private Socket socket;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
private IPSec gen;
private ArrayList<BigInteger[]> messages;
private BigInteger[] message;
private final int port, numBits;
private String address;
private Random rand;
private int fixedNumber;
private BigInteger fixedPrime, fixedBase, partialKeyClient,
partialKeyServer, commonKey, publicKeyServer, modulusServer;
public IPSecClient() {
rand = new Random();
numBits = 256;
fixedNumber = rand.nextInt(1000);
fixedPrime = new BigInteger("51803");
fixedBase = new BigInteger("3");
gen = new IPSec();
gen.KeyGen(numBits);
messages = new ArrayList<BigInteger[]>();
port = 5000;
address = "localhost";
}
public void SetupSSLConnection() {
try {
socket = new Socket(address, port);
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
System.out.println("[CLIENT]: Connected...");
// Send partial key and certificate (public key) to server
partialKeyClient = fixedBase.pow(fixedNumber).mod(fixedPrime);
message = new BigInteger[] {partialKeyClient, gen.PublicKey(), gen.Modulus()};
messages.add(message);
outputStream.writeObject(message);
outputStream.flush();
// Receive partial key and certificate from server
message = (BigInteger[]) inputStream.readObject();
messages.add(message);
partialKeyServer = message[0];
publicKeyServer = message[1];
modulusServer = message[2];
// Generate common key
commonKey = partialKeyServer.pow(fixedNumber).mod(fixedPrime);
System.out.println("[CLIENT]: Common key = " + commonKey.intValue());
// Send finished message
BigInteger accumulatedMessages = AccumulateMessages(messages).mod(gen.PublicKey());
BigInteger finishedMessage = gen.GenerateRSASignature(accumulatedMessages);
outputStream.writeObject(finishedMessage);
outputStream.flush();
// Receive finished message from server
finishedMessage = (BigInteger) inputStream.readObject();
// Verify finished message
boolean result = gen.VerifyRSASignature(AccumulateMessages(messages).mod(publicKeyServer), finishedMessage, publicKeyServer, modulusServer);
System.out.println("[CLIENT]: Verification of finished message " + (result ? "succeeded" : "failed"));
if (!result) {
System.out.println("[CLIENT]: SSL-connection could not be estasblished...");
CloseConnection(-1);
}
System.out.println("[CLIENT]: SSL-connection estasblished...");
CloseConnection(0);
} catch (SocketException se) {
se.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void CloseConnection(int exitCode) {
try {
socket.close();
outputStream.close();
inputStream.close();
System.exit(exitCode);
} catch (IOException e) {
e.printStackTrace();
}
}
private BigInteger AccumulateMessages(ArrayList<BigInteger[]> messages) {
BigInteger accumulator = new BigInteger("0");
for (BigInteger[] message : messages)
{
for (BigInteger part : message)
{
accumulator = accumulator.add(part);
}
}
return accumulator;
}
public static void main(String[] args) {
IPSecClient client = new IPSecClient();
client.SetupSSLConnection();
}
}
Server:
import java.io.*;
import java.math.BigInteger;
import java.net.*;
import java.util.ArrayList;
import java.util.Random;
public class IPSecServer {
private ServerSocket serverSocket;
private Socket socket;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
private IPSec gen;
private ArrayList<BigInteger[]> messages;
private BigInteger[] message;
private final int port;
private Random rand;
private int fixedNumber;
private BigInteger fixedPrime, fixedBase, partialKeyClient,
partialKeyServer, commonKey, publicKeyClient, modulusClient;
public IPSecServer() {
rand = new Random();
fixedNumber = rand.nextInt(1000);
fixedPrime = new BigInteger("51803");
fixedBase = new BigInteger("3");
gen = new IPSec();
gen.KeyGen(2048);
messages = new ArrayList<BigInteger[]>();
port = 5000;
}
public void SetupSSLConnection() {
try {
serverSocket = new ServerSocket(port);
System.out.println("[SERVER]: Listening...");
socket = serverSocket.accept();
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream = new ObjectOutputStream(socket.getOutputStream());
System.out.println("[SERVER]: Connected... " + "Port/IP: " + socket.getPort() + socket.getInetAddress());
// Receive partial key and certificate from client
message = (BigInteger[]) inputStream.readObject();
messages.add(message);
partialKeyClient = message[0];
publicKeyClient = message[1];
modulusClient = message[2];
// Send partial key and certificate to client
partialKeyServer = fixedBase.pow(fixedNumber).mod(fixedPrime);
message = new BigInteger[] {partialKeyServer, gen.PublicKey(), gen.Modulus()};
messages.add(message);
outputStream.writeObject(message);
outputStream.flush();
// Generate common key
commonKey = partialKeyClient.pow(fixedNumber).mod(fixedPrime);
System.out.println("[SERVER]: Common key = " + commonKey.intValue());
// Receive finished message from client
BigInteger finishedMessage = (BigInteger) inputStream.readObject();
messages.add(new BigInteger[] {finishedMessage});
// Verify finished message
boolean result = gen.VerifyRSASignature(AccumulateMessages(messages).mod(publicKeyClient), finishedMessage, publicKeyClient, modulusClient);
System.out.println("[SERVER]: Verification of finished message " + (result ? "succeeded" : "failed"));
if (!result) {
System.out.println("[SERVER]: SSL-connection could not be estasblished...");
CloseConnection(-1);
}
// Send finished message to client
BigInteger accumulatedMessages = AccumulateMessages(messages).mod(gen.PublicKey());
finishedMessage = gen.GenerateRSASignature(accumulatedMessages);
outputStream.writeObject(finishedMessage);
outputStream.flush();
System.out.println("[SERVER]: SSL-connection estasblished...");
CloseConnection(0);
} catch (SocketException se) {
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void CloseConnection(int exitCode) {
try {
socket.close();
outputStream.close();
inputStream.close();
serverSocket.close();
System.exit(exitCode);
} catch (IOException e) {
e.printStackTrace();
}
}
private BigInteger AccumulateMessages(ArrayList<BigInteger[]> messages) {
BigInteger accumulator = new BigInteger("0");
for (BigInteger[] message : messages)
{
for (BigInteger part : message)
{
accumulator = accumulator.add(part);
}
}
return accumulator;
}
public static void main(String[] args) {
IPSecServer server = new IPSecServer();
server.SetupSSLConnection();
}
}
IPSec:
import java.math.BigInteger;
import java.util.Random;
import java.security.*;
public class IPSec {
private static final BigInteger one = new BigInteger("1");
// private key (n,d)
private BigInteger privateKey;
// public key (n,e)
private BigInteger publicKey = new BigInteger("3");
// modulus n
private BigInteger modulus;
public IPSec() {
}
// PUBLIC KEY
public BigInteger PublicKey() {
return publicKey;
}
public BigInteger Modulus() {
return modulus;
}
// KEY GENERATION
public void KeyGen(int keyLength) {
BigInteger p = BigInteger.probablePrime((int)Math.ceil(keyLength / 2), new Random());
BigInteger q = BigInteger.probablePrime((int)Math.ceil(keyLength / 2), new Random());
while (!(p.subtract(one)).gcd(publicKey).equals(one))
p = p.nextProbablePrime();
while (!(q.subtract(one)).gcd(publicKey).equals(one))
q = q.nextProbablePrime();
BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));
modulus = p.multiply(q);
privateKey = publicKey.modInverse(phi);
}
// ENCRYPT
public BigInteger Encrypt(BigInteger message) {
return message.modPow(publicKey, modulus);
}
public static BigInteger Encrypt(BigInteger message, BigInteger publicKey, BigInteger modulus) {
return message.modPow(publicKey, modulus);
}
// DECRYPT
public BigInteger Decrypt(BigInteger message) {
return message.modPow(privateKey, modulus);
}
// SIGNATURE GENERATION
// Generate RSA-signatures for a message
public BigInteger GenerateRSASignature(BigInteger message) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
return Decrypt(new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return message;
}
// Verify RSA-signatures for a message
public boolean VerifyRSASignature(BigInteger message, BigInteger signature) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return (new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus())).equals(Encrypt(signature));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return false;
}
public boolean VerifyRSASignature(BigInteger message, BigInteger signature,
BigInteger publicKey, BigInteger modulus) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return (new BigInteger(1, digest.digest(message.toByteArray())).mod(Modulus())).equals(Encrypt(signature, publicKey, modulus));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.exit(-1);
}
return false;
}
public static void main(String[] args) {
Testing();
}
// MISC
public void printKeys() {
String s = "";
s += "public = " + publicKey + "\n";
s += "private = " + privateKey + "\n";
s += "modulus = " + modulus;
System.out.println(s);
}
public static void Testing() {
IPSec gen = new IPSec();
gen.KeyGen(128);
BigInteger message = new BigInteger("329");
System.out.println("Verify: " + gen.VerifyRSASignature(message, gen.GenerateRSASignature(message)));
}
}
Upvotes: 0
Views: 2684
Reputation: 310913
Your server is barfing at the signature-verifying stage here:
if (!result) {
System.out.println("[SERVER]: SSL-connection could not be established...");
CloseConnection(-1);
}
and closing the socket without sending the FINISHED message. Check its output log. In such a case maybe you should send an error object first. Or else treat EOFException
as a handshake failure.
NB:
ObjectOutputStream
before the ObjectInputStream
at both ends.ObjectOutputStream,
not the socket, or the input stream. That way you can be sure it gets flushed. Closing any of the three closes the other two.Upvotes: 1