Generate base64 encoded client challenge

This commit is contained in:
Tobias Eidelpes 2020-12-23 22:33:19 +01:00
parent 779fb6dc43
commit 64a12a816f

View File

@ -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