Generate base64 encoded client challenge
This commit is contained in:
parent
779fb6dc43
commit
64a12a816f
@ -9,6 +9,7 @@ import java.security.*;
|
|||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import dslab.ComponentFactory;
|
import dslab.ComponentFactory;
|
||||||
@ -16,6 +17,7 @@ import dslab.util.Config;
|
|||||||
|
|
||||||
import javax.crypto.*;
|
import javax.crypto.*;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
public class MessageClient implements IMessageClient, Runnable {
|
public class MessageClient implements IMessageClient, Runnable {
|
||||||
private static final Logger logger = Logger.getLogger(MessageClient.class.getName());
|
private static final Logger logger = Logger.getLogger(MessageClient.class.getName());
|
||||||
@ -38,6 +40,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
private PrintWriter dmapOut;
|
private PrintWriter dmapOut;
|
||||||
private BufferedReader dmapIn;
|
private BufferedReader dmapIn;
|
||||||
|
|
||||||
|
private Cipher aesCipher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new client instance.
|
* Creates a new client instance.
|
||||||
*
|
*
|
||||||
@ -80,7 +84,6 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startSecure() throws IOException {
|
private void startSecure() throws IOException {
|
||||||
@ -94,8 +97,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
componentId = input.split("\\s+")[1];
|
componentId = input.split("\\s+")[1];
|
||||||
try {
|
try {
|
||||||
// Attempt to read server public key from file called <component-id>_pub.der
|
// Attempt to read server public key from file called <component-id>_pub.der
|
||||||
byte[] keyBytes = Files.readAllBytes(Paths.get(componentId + "_pub.der"));
|
byte[] keyBytes = Files.readAllBytes(Paths.get("keys", "client", componentId + "_pub.der"));
|
||||||
logger.info("Read bytes from path " + Paths.get(componentId + ".der") + ": " + Arrays.toString(keyBytes));
|
logger.info("Read bytes from path " + Paths.get("keys", "client", componentId + "_pub.der") + ": " + Arrays.toString(keyBytes));
|
||||||
// Create X509 spec object from key
|
// Create X509 spec object from key
|
||||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
|
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
|
||||||
// Create generator for RSA scheme
|
// Create generator for RSA scheme
|
||||||
@ -103,7 +106,7 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
// Make generator generate public key from X509 spec
|
// Make generator generate public key from X509 spec
|
||||||
serverPublicKey = kf.generatePublic(spec);
|
serverPublicKey = kf.generatePublic(spec);
|
||||||
logger.info("Server's Public Key: " + serverPublicKey);
|
logger.info("Server's Public Key: " + serverPublicKey);
|
||||||
String clientChallenge = generateChallenge(serverPublicKey);
|
String clientChallenge = generateChallengeMessage(serverPublicKey);
|
||||||
// TODO send clientChallenge to server
|
// TODO send clientChallenge to server
|
||||||
// TODO Receive AES encrypted message saying "ok <client-challenge>"
|
// TODO Receive AES encrypted message saying "ok <client-challenge>"
|
||||||
// TODO Compare received client challenge with generated client challenge
|
// TODO Compare received client challenge with generated client challenge
|
||||||
@ -116,39 +119,80 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey generateSecretKey() throws NoSuchAlgorithmException {
|
private SecretKeySpec generateSecretKey() {
|
||||||
|
try {
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||||
keyGenerator.init(256);
|
keyGenerator.init(256, SecureRandom.getInstanceStrong());
|
||||||
return keyGenerator.generateKey();
|
return new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
logger.severe("This should not be happening!");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] generateIv() {
|
private IvParameterSpec generateIv() {
|
||||||
// Size of IV corresponds to AES block size (=128bits=16bytes)
|
// Size of IV corresponds to AES block size (=128bits=16bytes)
|
||||||
byte[] iv = new byte[16];
|
byte[] iv = new byte[16];
|
||||||
new SecureRandom().nextBytes(iv);
|
new SecureRandom().nextBytes(iv);
|
||||||
return new IvParameterSpec(iv).getIV();
|
return new IvParameterSpec(iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateChallenge(PublicKey serverPublicKey) {
|
private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) {
|
||||||
SecureRandom secureRandom = new SecureRandom();
|
|
||||||
try {
|
try {
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
this.aesCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, serverPublicKey);
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||||
|
logger.severe("This should not be happening!");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
||||||
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||||
|
logger.severe("This should not be happening!");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] generateChallenge(PublicKey serverPublicKey) {
|
||||||
|
SecureRandom secureRandom = new SecureRandom();
|
||||||
// Generate new random 32 byte challenge
|
// Generate new random 32 byte challenge
|
||||||
byte[] clearTextChallenge = new byte[32];
|
byte[] clearTextChallenge = new byte[32];
|
||||||
secureRandom.nextBytes(clearTextChallenge);
|
secureRandom.nextBytes(clearTextChallenge);
|
||||||
// Generate secretKey and initialization vector
|
return clearTextChallenge;
|
||||||
String secretKey = "";
|
}
|
||||||
String IV = "";
|
|
||||||
// Encrypt "ok <clearTextChallenge> <secretKey> <IV>"
|
private String generateChallengeMessage(PublicKey serverPublicKey) {
|
||||||
cipher.update(("ok " + (new String(clearTextChallenge)) + " " + secretKey + " " + IV).getBytes(StandardCharsets.UTF_8));
|
SecureRandom secureRandom = new SecureRandom();
|
||||||
|
byte[] clearTextChallenge = generateChallenge(serverPublicKey);
|
||||||
|
SecretKeySpec secretKeySpec = generateSecretKey();
|
||||||
|
assert secretKeySpec != null;
|
||||||
|
IvParameterSpec iv = generateIv();
|
||||||
|
// Save AES cipher for subsequent communication
|
||||||
|
setAesCipher(secretKeySpec, iv);
|
||||||
|
// Concatenate challenge, secretKey and IV
|
||||||
|
byte[] concatenated = new byte[80];
|
||||||
|
System.arraycopy(clearTextChallenge, 0, concatenated, 0, 32);
|
||||||
|
System.arraycopy(secretKeySpec.getEncoded(), 0, concatenated, 32, 32);
|
||||||
|
System.arraycopy(iv.getIV(), 0, concatenated, 64, 16);
|
||||||
|
String base64Encoded = Base64.getEncoder().encodeToString(concatenated);
|
||||||
|
// Encrypt "ok <base64Encoded>"
|
||||||
|
Cipher cipher = null;
|
||||||
|
try {
|
||||||
|
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, serverPublicKey);
|
||||||
|
cipher.update(("ok " + base64Encoded).getBytes(StandardCharsets.UTF_8));
|
||||||
byte[] cipherTextChallenge = cipher.doFinal();
|
byte[] cipherTextChallenge = cipher.doFinal();
|
||||||
return (new String(cipherTextChallenge, StandardCharsets.UTF_8));
|
return (new String(cipherTextChallenge, StandardCharsets.UTF_8));
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
||||||
logger.severe(e.getMessage());
|
logger.severe("This should not be happening!");
|
||||||
|
e.printStackTrace();
|
||||||
shutdown();
|
shutdown();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user