| ||||||||||||||||
Examen ordinàriaJoan Puigcerver Ibáñez Entrega¶Perill Si l'entrega no compleix aquests criteris, no és qualificarà. L'entrega ha de complir els següents requisits:
1a Avaluació¶
|
Camp | Valor |
---|---|
Àlies | handshake-server |
CN | CognomNom-HandshakeServer |
OU | PSP-DAM2S |
O | CIPFP Mislata |
L | Mislata |
ST | València |
C | ES |
El servidor té el mètode getPrivateKey()
, que haurà de retornar la clau privada
del certificat del servidor generat anteriormanet.
El client té el mètode getPublicKey()
, que haurà de retornar la clau pública del
servidor del certificat importat en la TrustStore.
Comunicació encriptada¶
Tant el servidor com el client disposen dels mètodes
sendEncryptedMessage(String message)
i
String readEncryptedMessage()
.
El mètode sendEncryptedMessage()
encripta les dades mitjançant AES
amb la clau simètrica acordada entre el servidor i el client
(guardada com atribut en la classe) i les envia.
El mètode readEncryptedMessage()
reb un missatge i desencripta les
dades mitjançant AES amb la clau simètrica acordada entre el servidor i
el client (guardada com atribut en la classe).
Handshake¶
El handshake es realitzarà de la següent manera:
-
Client:
- Quan es connecta, l'usuari tria una contrasenya que serà utilitzada per generar una clau simètrica.
- Encripta la contrasenya utilitzant RSA amb la clau pública del servidor.
- Envia la contrasenya encriptada al servidor.
- Crea una clau simètrica de 256 bits i la guarda.
- Espera a rebre un missatge de confirmació.
-
Servidor:
- Reb la contrasenya encriptada del client.
- Desencripta la contrasenya utilitzant la clau privada del servidor.
- Crea la clau simètrica de 256 bits i la guarda.
- Envia la resposta "Handshake succesful" encriptat amb la clau simètrica.
Codi font¶
Servidor¶
package ordinaria.exam2.handshake.server;
import ud4.examples.CertificateUtils;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class HandshakeServer extends Thread {
ServerSocket server;
List<HandshakeServerHandler> clients;
boolean running;
private final String keyStorePath;
private final String keyStorePassword;
private final String alias;
public HandshakeServer(int port, String keyStorePath, String keyStorePassword, String alias) throws IOException {
server = new ServerSocket(port);
clients = new ArrayList<>();
running = true;
this.keyStorePath = keyStorePath;
this.keyStorePassword = keyStorePassword;
this.alias = alias;
}
public String getKeyStorePath() {
return keyStorePath;
}
public String getKeyStorePassword() {
return keyStorePassword;
}
public String getAlias() {
return alias;
}
private void showCertificate() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
KeyStore keyStore = CertificateUtils.loadKeyStore(this.keyStorePath, this.keyStorePassword);
// TODO: Obté el certificat de la KeyStore amb el alies especificat
Certificate serverCertificate = null;
String certificateInfo = CertificateUtils.getCertificateInfo(serverCertificate);
System.out.println(certificateInfo);
}
public void close(){
running = false;
this.interrupt();
}
public synchronized void removeClient(HandshakeServerHandler hc){
clients.remove(hc);
}
@Override
public void run() {
while (running){
try {
Socket client = server.accept();
HandshakeServerHandler handshakeServerHandler = new HandshakeServerHandler(client, this);
clients.add(handshakeServerHandler);
handshakeServerHandler.start();
System.out.println("Nova connexió acceptada.");
} catch (IOException e) {
System.err.println("Error while accepting new connection");
System.err.println(e.getMessage());
}
}
}
public static void main(String[] args) {
try {
/*
TODO: llegeix la informació sensible des d'un fitxer de configuració
*/
int port = 0;
String keyStorePath = "";
String keyStorePassword = "";
String alias = "";
Scanner scanner = new Scanner(System.in);
HandshakeServer server = new HandshakeServer(port, keyStorePath, keyStorePassword, alias);
server.showCertificate();
server.start();
// Tanca el servidor amb "ENTER"
scanner.nextLine();
server.close();
} catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
package ordinaria.exam2.handshake.server;
import ordinaria.exam2.handshake.exceptions.CryptographyException;
import ordinaria.exam2.handshake.exceptions.HandshakeException;
import ud4.examples.CertificateUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import java.io.*;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateException;
public class HandshakeServerHandler extends Thread {
private final HandshakeServer server;
private final Socket socket;
private final BufferedReader in;
private final PrintWriter out;
private SecretKey symetricKey;
public HandshakeServerHandler(Socket socket, HandshakeServer server) throws IOException {
this.server = server;
this.socket = socket;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
symetricKey = null;
}
/**
* TODO: Retorna la clau privada del certificat del servidor
* @return Clau publica del servidor
*/
private PrivateKey getPrivateKey() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
String keyStorePath = server.getKeyStorePath();
String keyStorePassword = server.getKeyStorePassword();
String alias = server.getAlias();
KeyStore keyStore = CertificateUtils.loadKeyStore(keyStorePath, keyStorePassword);
// TODO: Obté la clau privada de la KeyStore amb el alies especificat
PrivateKey privateKey = null; //TODO
return privateKey;
}
/**
* TODO: Realitza el handshake.
* - Llegeix la contrasenya encriptada des del client
* - Desencripta la contrasenya amb la clau privada del servidor
* - Genera una clau simètrica utilitzant la contrasenya amb tamany 256 bits
* - Envia la resposta "Handshake successful!"
* @throws IOException
*/
private void handshake() throws HandshakeException {
try {
// Llegeix la contrasenya encriptada
String encryptedKeyPassword = in.readLine();
// TODO: Desencripta la contrasenya amb la clau privada
PrivateKey privateKey = getPrivateKey();
String keyPasswd = "";
// TODO: Genera una clau simètrica utilitzant la contrasenya amb tamany 256 bits
this.symetricKey = null;
// Envia la resposta
sendEncryptedMessage("Handshake successful!");
System.out.println("Handshake successful!");
} catch (UnrecoverableKeyException | NoSuchPaddingException | CertificateException |
IllegalBlockSizeException | IOException | KeyStoreException | NoSuchAlgorithmException |
BadPaddingException | InvalidKeyException e) {
throw new HandshakeException(e.getMessage());
}
}
/**
* TODO: Encripta el missatge utilitzant la clau simètrica i envia'l al servidor
* @param message Missatge a enviar
*/
private void sendEncryptedMessage(String message) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
if (symetricKey == null)
throw new RuntimeException("Symetric key not initialized");
// TODO: Encripta el missatge amb la clau simètrica
String encrypted = ""; // TODO
// Envia el missatge
out.println(encrypted);
}
/**
* TODO: Llig un missatge del servidor encriptat i el desencripta amb la clau simètrica
* @return Missatge rebut
*/
private String readEncryptedMessage() throws IOException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
if (symetricKey == null)
throw new RuntimeException("Symetric key not initialized");
// Llig el missatge
String response = in.readLine();
// Si la resposta és null, retornem null
if(response == null)
return null;
// TODO: Desencripta'l mitjançant la clau simètrica
return "";
}
private void echo() throws CryptographyException, IOException {
try{
String request = null;
while((request = readEncryptedMessage()) != null){
sendEncryptedMessage(request);
}
} catch (NoSuchPaddingException | IllegalBlockSizeException | IOException | NoSuchAlgorithmException |
BadPaddingException | InvalidKeyException e) {
throw new CryptographyException(e.getMessage());
}
this.socket.close();
}
@Override
public void run() {
try {
handshake();
echo();
} catch (HandshakeException e) {
System.err.println("Error en el handshake: " + e.getMessage());
} catch (CryptographyException e) {
System.err.println("Error xifrant o desxifrant les dades: " + e.getMessage());
} catch (IOException e) {
System.err.println(e.getMessage());
}
server.removeClient(this);
}
}
Client¶
package ordinaria.exam2.handshake.client;
import ordinaria.exam2.handshake.exceptions.CryptographyException;
import ordinaria.exam2.handshake.exceptions.HandshakeException;
import ud4.examples.CertificateUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Scanner;
public class HandshakeClient {
private final Socket socket;
private final Scanner scanner;
private final PrintWriter out;
private final BufferedReader in;
private final String trustStorePath;
private final String trustStorePassword;
private final String alias;
private SecretKey symetricKey;
public HandshakeClient(String host, int port, String trustStorePath, String trustStorePassword, String alias) throws IOException {
this.scanner = new Scanner(System.in);
this.socket = new Socket(host, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.trustStorePath = trustStorePath;
this.trustStorePassword = trustStorePassword;
this.alias = alias;
this.symetricKey = null;
}
/**
* TODO: Retorna la clau pública del certificat del servidor
* @return Clau publica del servidor
*/
private PublicKey getPublicKey() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
KeyStore trustStore = CertificateUtils.loadKeyStore(this.trustStorePath, this.trustStorePassword);
// TODO: Obté el certificat de la KeyStore amb el alies especificat
Certificate serverCertificate = null;
String certificateInfo = CertificateUtils.getCertificateInfo(serverCertificate);
System.out.println(certificateInfo);
// TODO: Obté la clau pública del ceritificat
PublicKey serverPublicKey = null;
return serverPublicKey;
}
/**
* TODO: Realitza el handshake.
* - Llegeix la contrasenya a utilitzar
* - Encripta la contrasenya amb la clau pública del servidor
* - Envia la contrsaenya encriptada al servidor
* - Genera una clau simètrica utilitzant la contrasenya amb tamany 256 bits
* - Llegeix i mostra la resposta del servidor
* @throws IOException
*/
private void handshake() throws HandshakeException {
try {
// Llegeix la contrasenya
System.out.print("Introdueix la contrasenya per generar la clau simètrica: ");
String passwd = scanner.nextLine();
// TODO: Encripta la contrasenya amb la clau pública del servidor
PublicKey publicKey = getPublicKey();
String encryptedPasswd = "";
// Envia la contrasenya encriptada
out.println(encryptedPasswd);
// TODO: Genera una clau simètrica utilitzant la contrasenya amb tamany 256 bits
symetricKey = null;
// Llegeix i mostra la resposta del servidor
String response = readEncryptedMessage();
System.out.println(response);
} catch (Exception e){
throw new HandshakeException(e.getMessage());
}
}
/**
* TODO: Encripta el missatge utilitzant la clau simètrica i envia'l al servidor
* @param message Missatge a enviar
*/
private void sendEncryptedMessage(String message) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
if (symetricKey == null)
throw new RuntimeException("No s'ha inicialitzat la clau simètrica");
// TODO: Encripta el missatge amb la clau simètrica
String encrypted = "";
// Envia el missatge al servidor
out.println(encrypted);
}
/**
* TODO: Llig un missatge del servidor encriptat i el desencripta amb la clau simètrica
* @return Missatge rebut
*/
private String readEncryptedMessage() throws IOException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
if (symetricKey == null)
throw new RuntimeException("No s'ha inicialitzat la clau simètrica");
// Llig el missatge
String response = in.readLine();
// Si la resposta és null, retornem null
if(response == null)
return null;
// TODO: Desencripta'l mitjançant la clau simètrica
return "";
}
public void chat() throws CryptographyException {
try {
System.out.println("Acabes d'entrar al chat.");
String line;
while ((line = scanner.nextLine()) != null && this.socket.isConnected()) {
sendEncryptedMessage(line);
String response = readEncryptedMessage();
System.out.println("Response: " + response);
}
} catch (IOException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException |
BadPaddingException | InvalidKeyException e){
throw new CryptographyException(e.getMessage());
}
}
public void close(){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println("Connectant-se amb el servidor...");
try {
/*
TODO: llegeix la informació sensible des d'un fitxer de configuració
*/
String host = "";
int port = 0;
String trustStorePath = "";
String trustStorePassword = "";
String alias = "";
HandshakeClient chat = new HandshakeClient(host, port, trustStorePath, trustStorePassword, alias);
chat.handshake();
chat.chat();
} catch (IOException e){
System.err.println("Error connectant-se amb el servidor.");
} catch (HandshakeException e) {
System.err.println("Error realitzant el handshake: " + e.getMessage());
} catch (CryptographyException e) {
System.err.println("Error al xifrar o desxifrar les dades: " + e.getMessage());
}
}
}
Excepcions¶
Rúbrica¶
- (2 punts) Genera els certificats.
- (1.5 punt) Client:
getPublicKey()
- (1.5 punt) Servidor:
getPrivateKey()
- (1 punt)
sendEncryptedMessage(String message)
- (1 punt)
String readEncryptedMessage()
- Handshake:
- Client:
- (1 punt) Encripta la contrasenya amb la clau pública del servidor.
- (0.5 punt) Genera una clau simètrica amb la contrasenya de 256 bits.
- Servidor:
- (1 punt) Desencripta la contrasenya amb la clau privada del servidor.
- (0.5 punt) Genera una clau simètrica amb la contrasenya de 256 bits.
- Client: