- Ajout système de Context dans les ProtocolWriter.java

- Ajout récupération Clé AES via Context.java
- Ajout cryptage lors de l'envoie du fichier
This commit is contained in:
Benjamin 2022-03-12 12:34:04 +01:00
parent 02d9d30985
commit 5fe63fa3ea
21 changed files with 162 additions and 59 deletions

View File

@ -45,7 +45,7 @@ public class App {
protocolRep.addWriter(new FilesRule());
protocolRep.addWriter(new SaveFileOkRule());
protocolRep.addWriter(new SaveFileErrorRule());
protocolRep.addWriter(new SendfileRule());
protocolRep.addWriter(new SendfileRule(repositoryStorage.getStoragePath()));
FileFrontEnd ffe = new FileFrontEnd(clientRep, storeRep, protocolRep);
new UnicastServerListener(ffe, clientRep, protocolRep, repositoryStorage, repositoryStorage.getUnicastPort());

View File

@ -174,7 +174,7 @@ public class ClientHandler implements Runnable, AutoCloseable {
* Lorsque l'accès à été refusé.
*/
private void accessDenied() {
ProtocolWriter.ProtocolResult signErrorResult = protocolRep.executeWriter(SignErrorRule.NAME);
ProtocolWriter.ProtocolResult signErrorResult = protocolRep.executeWriter(context, SignErrorRule.NAME);
writer.write(signErrorResult.getCommand()); // Envoie SignError car echec de la connection
writer.flush();
}

View File

@ -31,7 +31,8 @@ public class Context {
/**
* Permet de créer un utilisateur.
* @param login Login de l'utilisateur
*
* @param login Login de l'utilisateur
* @param password Mot de passe de l'utilisateur
* @return TRUE si l'utilisateur a pu être créé
*/
@ -47,12 +48,14 @@ public class Context {
this.login = login;
return true;
}
} catch (AES_GCM.AesGcmException e) {}
} catch (AES_GCM.AesGcmException e) {
}
return false;
}
/**
* Login de l'utilisateur
*
* @return Login de l'utilisateur
*/
public String getLogin() {
@ -62,7 +65,8 @@ public class Context {
/**
* Permet de demander la connection de l'utilisateur
* @param login Login
*
* @param login Login
* @param password Mot de passe
* @return TRUE si l'utilisateur a été authentifié
*/
@ -70,8 +74,8 @@ public class Context {
String passwordSalt = this.repository.getUserPasswordSalt(login);
if (passwordSalt != null) {
ShaHasher hasher = new ShaHasher(password);
System.out.println(hasher.fromSalt(passwordSalt));
if (this.repository.verifyUser(login, hasher.fromSalt(passwordSalt))) {
if (this.repository.verifyUser(login, hasher.fromSalt(hasher.saltToByte(passwordSalt)))) {
this.login = login;
return true;
}
@ -81,9 +85,19 @@ public class Context {
/**
* Permet de savoir si l'utilisateur s'est connecté (Avec login et mdp)
*
* @return TRUE si l'utilisateur est connecté
*/
public boolean isConnected() {
return this.getLogin() != null;
}
/**
* Clé AES de l'utilisateur
* @return Clé AES de l'utilisateur
*/
public String getAesKey() {
return this.repository.getUserAesKey(getLogin());
}
}

View File

@ -8,7 +8,7 @@ public interface ProtocolRepository {
<T extends ProtocolReader.ProtocolResult> T executeReader(Context context, String data);
<T extends ProtocolWriter.ProtocolResult> T executeWriter(String cmdName, String... data);
<T extends ProtocolWriter.ProtocolResult> T executeWriter(Context context, String cmdName, String... data);
void addReader(ProtocolReader reader);

View File

@ -1,8 +1,8 @@
package lightcontainer.protocol;
import java.io.InputStream;
import lightcontainer.domains.client.Context;
import java.io.OutputStream;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -30,8 +30,14 @@ public abstract class ProtocolWriter {
public static class ProtocolResult {
private final Context context;
private String command;
public ProtocolResult(Context context) {
this.context = context;
}
public String getCommand() {
return command;
}
@ -46,14 +52,22 @@ public abstract class ProtocolWriter {
* @param writer Buffer à remplir qui sera envoyer via le réseau
*/
public void write(OutputStream writer) {}
/**
* Accesseur au contexte courant sur lequel opère la commande
* @return Context
*/
public Context getContext() {
return context;
}
}
/**
* Permet de contruire une commande selon une règle établie.
* @param data Les données à ajouter dans la commande; L'ordre défini leur position dans la commande
* @return La commande construite
* @return La commande construites
*/
public final <T extends ProtocolResult> T execute(String... data) {
public final <T extends ProtocolResult> T execute(Context context, String... data) {
// Concatatène le nom de la commande avec les données (trim), avec un espace entre chaque
StringBuilder builder = new StringBuilder(this.cmdName);
@ -64,7 +78,7 @@ public abstract class ProtocolWriter {
Matcher ruleMatcher = this.rulePattern.matcher(command); // Vérifie que tout match (cf. Matcher). Si match alors on retourne la commande build, sinon on retourne NULL
if (ruleMatcher.matches()) {
ProtocolResult result = onExecuted(data);
ProtocolResult result = onExecuted(context, data);
result.setCommand(command);
return (T) result;
}
@ -75,8 +89,8 @@ public abstract class ProtocolWriter {
/**
* Cette méthode est appelée lors de l'exécution de la règle
*/
protected <T extends ProtocolResult> T onExecuted(String... data) {
return (T) new ProtocolResult();
protected <T extends ProtocolResult> T onExecuted(Context context, String... data) {
return (T) new ProtocolResult(context);
}
}

View File

@ -37,7 +37,7 @@ public class FilelistRule extends ProtocolReader {
@Override
protected FilelistRule.Result onExecuted(Context context, String... data) {
FilelistRule.Result result = new Result(context);
result.setResultCommand(this.protocolRep.executeWriter(FilesRule.NAME, "endbenja.txt!500"), ResultCmdReceiver.CLIENT);
result.setResultCommand(this.protocolRep.executeWriter(context, FilesRule.NAME, "endbenja.txt!500"), ResultCmdReceiver.CLIENT);
return result;
}
}

View File

@ -54,19 +54,18 @@ public class SavefileRule extends ProtocolReader {
System.out.printf("Sauvegarde du fichier : %s %d\n", filename, size);
try {
FileReceiver fileReceiver = new FileReceiver(storagePath); // "D:\\"); //"/home/benjamin/ffe");
FileReceiver fileReceiver = new FileReceiver(storagePath);
String key = AES_GCM.generateSecretKey();
String iv = AES_GCM.generateIV();
System.out.println("Clé " + key);
System.out.println("IV " + iv);
if (!fileReceiver.receiveFile(reader, this.filename, this.size, key, iv))
throw new IOException();
this.setResultCommand(protocolRep.executeWriter(SendfileRule.NAME, this.filename, String.valueOf(this.size), "EMPREINTEBLBLBLBLBLABLABLBALBALBALBALBALBALBALBALBALABLBALBALBALABLABLABLABLABLABLABALBLABALABLABLABLABKJABKAHBHKBHJbhjvgkh"), ResultCmdReceiver.STOREBACKEND);
System.out.println("AHAHAHAH");
this.setResultCommand(protocolRep.executeWriter(getContext(), SendfileRule.NAME, this.filename, String.valueOf(this.size), "EMPREINTEBLBLBLBLBLABLABLBALBALBALBALBALBALBALBALBALABLBALBALBALABLABLABLABLABLABLABALBLABALABLABLABLABKJABKAHBHKBHJbhjvgkh"), ResultCmdReceiver.STOREBACKEND);
} catch (IOException | AES_GCM.AesGcmException e) {
this.setResultCommand(protocolRep.executeWriter(SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
this.setResultCommand(protocolRep.executeWriter(getContext(), SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
e.printStackTrace();
}
}
@ -87,7 +86,7 @@ public class SavefileRule extends ProtocolReader {
protected ProtocolReader.ProtocolResult onError(Context context) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
// Commande renvoyée en cas d'erreur
result.setResultCommand(protocolRep.executeWriter(SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(protocolRep.executeWriter(context, SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
return result;
}

View File

@ -29,7 +29,7 @@ public class SendOkRule extends ProtocolReader {
@Override
protected ProtocolReader.ProtocolResult onExecuted(Context context, String... data) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
result.setResultCommand(protocolRep.executeWriter(SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(protocolRep.executeWriter(context, SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
return result;
}
}

View File

@ -57,9 +57,9 @@ public class SigninRule extends ProtocolReader {
SigninRule.Result result = new SigninRule.Result(context, data[LOGIN], data[PASSWORD]);
if (context.signIn(result.getLogin(), result.getPassword())) {
result.setResultCommand(this.protocolRep.executeWriter(SignOkRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(this.protocolRep.executeWriter(context, SignOkRule.NAME), ResultCmdReceiver.CLIENT);
} else {
result.setResultCommand(this.protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(this.protocolRep.executeWriter(context, SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
}
return result;
@ -69,7 +69,7 @@ public class SigninRule extends ProtocolReader {
protected ProtocolReader.ProtocolResult onError(Context context) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
result.setResultCommand(protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(protocolRep.executeWriter(context, SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
return result;
}
}

View File

@ -50,9 +50,9 @@ public class SignupRule extends ProtocolReader {
SignupRule.Result result = new SignupRule.Result(context, data[LOGIN], data[PASSWORD]);
if (context.createUser(result.getLogin(), result.getPassword())) {
result.setResultCommand(this.protocolRep.executeWriter(SignOkRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(this.protocolRep.executeWriter(context, SignOkRule.NAME), ResultCmdReceiver.CLIENT);
} else {
result.setResultCommand(this.protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(this.protocolRep.executeWriter(context, SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
}
return result;
@ -62,7 +62,7 @@ public class SignupRule extends ProtocolReader {
protected ProtocolReader.ProtocolResult onError(Context context) {
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult(context);
result.setResultCommand(protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
result.setResultCommand(protocolRep.executeWriter(context, SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
return result;
}
}

View File

@ -1,7 +1,8 @@
package lightcontainer.protocol.rules.writer;
import lightcontainer.domains.client.Context;
import lightcontainer.protocol.ProtocolWriter;
import lightcontainer.utils.FileReceiver;
import lightcontainer.utils.AES_GCM;
import lightcontainer.utils.FileSender;
import java.io.OutputStream;
@ -19,8 +20,11 @@ public class SendfileRule extends ProtocolWriter {
private static final int FILE_SIZE = 1; // Index file size.
private static final int HASHED_FILE_CONTENT = 2; // Index file content hashed.
public SendfileRule() {
private String storagePath;
public SendfileRule(String storagePath) {
super(NAME, PATTERN);
this.storagePath = storagePath;
}
public class Result extends ProtocolWriter.ProtocolResult {
@ -29,7 +33,8 @@ public class SendfileRule extends ProtocolWriter {
private final int fileSize;
private final String hashedFileContent;
public Result(String hashedFileName, int fileSize, String hashedFileContent) {
public Result(Context context, String hashedFileName, int fileSize, String hashedFileContent) {
super(context);
this.hashedFileName = hashedFileName;
this.fileSize = fileSize;
this.hashedFileContent = hashedFileContent;
@ -39,14 +44,18 @@ public class SendfileRule extends ProtocolWriter {
public void write(OutputStream writer) {
super.write(writer);
System.out.println("Envoie du fichier au SBE");
FileSender fileSender = new FileSender("D:\\"); //"/home/benjamin/ffe");
FileSender fileSender = new FileSender(storagePath);
fileSender.sendFile(hashedFileName, writer);
// TODO : Supprimer le fichier du FFE
}
}
@Override
protected SendfileRule.Result onExecuted(String... data) {
return new SendfileRule.Result(data[HASHED_FILE_NAME], Integer.parseInt(data[FILE_SIZE]), data[HASHED_FILE_CONTENT]);
protected SendfileRule.Result onExecuted(Context context, String... data) {
return new SendfileRule.Result(context, data[HASHED_FILE_NAME], Integer.parseInt(data[FILE_SIZE]), data[HASHED_FILE_CONTENT]);
}
}

View File

@ -24,10 +24,10 @@ public class ProtocolRepositoryImpl implements ProtocolRepository {
}
@Override
public <T extends ProtocolWriter.ProtocolResult> T executeWriter(String cmdName, String... data) {
public <T extends ProtocolWriter.ProtocolResult> T executeWriter(Context context, String cmdName, String... data) {
for (ProtocolWriter writer : writers) {
T command;
if (cmdName.equals(writer.getCmdName()) && (command = writer.execute(data)) != null) {
if (cmdName.equals(writer.getCmdName()) && (command = writer.execute(context, data)) != null) {
return command;
}
}

View File

@ -15,6 +15,7 @@ public class AppConfig {
private int multicastPort;
private String networkInterface;
private boolean isTls;
private String storagePath;
/**
* Constructs a new instance of AppConfig.
@ -26,6 +27,7 @@ public class AppConfig {
this.multicastPort = -1;
this.networkInterface = "NONE";
this.isTls = false;
storagePath = "";
}
/**
@ -85,4 +87,20 @@ public class AppConfig {
public void setTls(boolean tls) {
this.isTls = tls;
}
/**
* Méthode permettant de récupérer le chemin de sauvegarde des fichiers
* @return Chemin de sauvegarde
*/
public String getStoragePath() {
return this.storagePath;
}
/**
* Méthode permettant d'assigner le chemin de sauvegarde des fichiers
* @return Chemin de sauvegarde
*/
public void setStoragePath(String storagePath) {
this.storagePath = storagePath;
}
}

View File

@ -151,4 +151,15 @@ public class AppData {
User user = getUser(login);
return user == null ? null : user.getPasswordSalt();
}
/**
* Méthode permettant de récupérer la clé AES d'un utilisateur
* @param login Login de l'utilisateur
* @return Clé AES
*/
public String getUserAesKey(String login) {
User user = getUser(login);
return user == null ? null : user.getAesKey();
}
}

View File

@ -25,6 +25,7 @@ public class JsonAdapter implements Adapter {
config.addProperty("multicast_port", appConfig.getMulticastPort());
config.addProperty("network_interface", appConfig.getNetworkInterface());
config.addProperty("tls", appConfig.isTls());
config.addProperty("storagePath", appConfig.getStoragePath());
JsonArray users = new JsonArray();
Iterator<User> userIterator = appData.usersIterator();
addUsers(users, userIterator);
@ -85,13 +86,14 @@ public class JsonAdapter implements Adapter {
appConfig.setMulticastPort(jsonAppData.get("multicast_port").getAsInt());
appConfig.setNetworkInterface(jsonAppData.get("network_interface").getAsString());
appConfig.setTls(jsonAppData.get("tls").getAsBoolean());
appConfig.setStoragePath(jsonAppData.get("storagePath").getAsString());
JsonArray jsonUsers = jsonAppData.getAsJsonArray("users");
List<User> users = new ArrayList<>();
getUsers(jsonUsers, users);
AppData appData = AppData.getInstance();
appData.setAppConfig(appConfig);
for (User user : users) {
appData.addUser(user.getName(), user.getPassword(), user.getAesKey(), "");
appData.addUser(user.getName(), user.getPassword(), user.getAesKey(), user.getPasswordSalt());
}
return appData;
} catch (JsonParseException parseException) {

View File

@ -117,9 +117,18 @@ public class Repository {
/**
* Méthode permettant de récupérer le chemin de sauvegarde des fichiers
* @return
* @return Chemin de sauvegarde
*/
public String getStoragePath() {
return null;
return appData.getAppConfig().getStoragePath();
}
/**
* Méthode permettant de récupérer la clé AES d'un utilisateur
* @param login Login de l'utilisateur
* @return Clé AES
*/
public String getUserAesKey(String login) {
return appData.getUserAesKey(login);
}
}

View File

@ -12,14 +12,14 @@ import java.util.Map;
*/
public class User {
private final String Name;
private final String name;
private final String password;
private final String aesKey;
private final String passwordSalt;
private final Map<String, File> files;
public User(String Name, String password, String aesKey, String passwordSalt, Map<String, File> files) {
this.Name = Name;
public User(String name, String password, String aesKey, String passwordSalt, Map<String, File> files) {
this.name = name;
this.password = password;
this.aesKey = aesKey;
this.passwordSalt = passwordSalt;
@ -27,7 +27,7 @@ public class User {
}
public String getName() {
return Name;
return name;
}
public String getPassword() {

View File

@ -26,7 +26,6 @@ public class AES_GCM {
{
/*
* FILE ENCRYPTION DEMO
*/
// Init files
File inFile = new File("D:\\HELMo.png");
File outFile = new File("D:\\HELMoCrypted.png");
@ -53,6 +52,7 @@ public class AES_GCM {
IVFile,
keyFile
);
*/
/*
* TEXT ENCRYPTION DEMO
@ -207,16 +207,18 @@ public class AES_GCM {
*
* @throws AesGcmException Exception if an error occur.
*/
private static void encryptStream(InputStream in, OutputStream out, String key, String IV) throws AesGcmException {
public static void encryptStream(InputStream in, OutputStream out, int fileSize, String key, String IV) throws AesGcmException {
byte[] buffer = new byte[1024];
int bytes;
int currSize = 0;
try {
// Make the cipher for encryption
Cipher cipher = createCipher(Cipher.ENCRYPT_MODE, key, IV);
// Initialize a CipherOutputStream
CipherOutputStream cipherOut = new CipherOutputStream(out, cipher);
// Encryption Process
while((bytes = in.read(buffer)) > 0) {
while(currSize < fileSize && (bytes = in.read(buffer)) > 0) {
currSize += bytes;
cipherOut.write(buffer, 0, bytes);
cipherOut.flush();
}
@ -259,7 +261,7 @@ public class AES_GCM {
*
* @throws AesGcmException Exception if an error occur.
*/
private static void decryptStream(InputStream in, OutputStream out, String key, String IV) throws AesGcmException {
public static void decryptStream(InputStream in, OutputStream out, String key, String IV) throws AesGcmException {
byte[] buffer = new byte[1024];
int bytes;
try {

View File

@ -8,17 +8,41 @@ public class FileSender {
public FileSender(String path) { this.path = path; }
public boolean sendFile(String filename, OutputStream out, int fileSize, String aesKey, String iv) {
BufferedInputStream bisFile = null;
System.out.printf("Envoie fichier : %s - %s - %s \n", filename, aesKey, iv);
try {
File f = new File(String.format("%s/%s", path, filename));
if(f.exists()) {
bisFile = new BufferedInputStream(new FileInputStream(f));
AES_GCM.decryptStream(bisFile, out, aesKey, iv);
bisFile.close();
return true;
} else
return false;
} catch(IOException | AES_GCM.AesGcmException ex) {
ex.printStackTrace();
return false;
}
}
public boolean sendFile(String filename, OutputStream out) {
BufferedInputStream bisFile = null;
int bytesReaded = 0;
try {
File f = new File(String.format("%s/%s", path, filename));
long fileSize = f.length();
if(f.exists()) {
byte[] buffer = new byte[DEFAULT_BUFFER];
bisFile = new BufferedInputStream(new FileInputStream(f));
//AES_GCM.encryptStream(bisFile, out, fileSize, "hyjFrdMJW6Pur8fiFueVrWKqwtnqAZmXEZPBAyBXp+o=", "e6H7xuw+PNrDppJCPLTKhg==");
long currentOffset = 0;
while((currentOffset < fileSize) && (bytesReaded = bisFile.read(buffer)) > 0) {
out.write(buffer, 0, bytesReaded); out.flush();
currentOffset+= bytesReaded;
}
bisFile.close();
return true;
} else
@ -28,4 +52,5 @@ public class FileSender {
return false;
}
}
}

View File

@ -35,14 +35,14 @@ public class ShaHasher {
public String nextHashing() {
this.salt = generateSalt();
return fromSalt(getSalt());
return fromSalt(this.salt);
}
public String fromSalt(String passwordSalt) {
public String fromSalt(byte[] passwordSalt) {
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-384");
md.update(saltToByte(passwordSalt));
md.update(passwordSalt);
byte[] bytes = md.digest(password.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
@ -70,7 +70,7 @@ public class ShaHasher {
return b64Encoder.encodeToString(this.salt);
}
private byte[] saltToByte(String salt) {
public byte[] saltToByte(String salt) {
Base64.Decoder b64Decoder = Base64.getDecoder();
return b64Decoder.decode(salt);
}

View File

@ -7,10 +7,10 @@
"storagePath": "/home/benjamin/ffe",
"users": [
{
"name": "benjamin",
"password": "08ffabe5c9577b4c809aa4eeee61c1859d4b5c44b0acfe9534a81ae48c3ba1a1d372f4a6bdaad2bb46483e0899cd765b",
"aes_key": "FaiZVQaeJF1qrbcOsM0yaUdzcmeIZ3p9R3NZwA5zPcs=",
"passwordSalt": "azA4e8Dtw+svxQWWnJ+rlA==",
"name": "aaaaa",
"password": "5d628c274ebb008324f1e199d3bfff0a3fe839730a7f2355e82850d7acca5e5ca64db9071abf3d91034295695f84a617",
"aes_key": "qlTH6TijnfMRnrS0Qf+k6IPKGp5LoRMXGxCq16e+mF4=",
"passwordSalt": "Ns8Al6DpqPsIDlCSRBVTEg==",
"files": []
}
]