All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.clarussecure.dataoperations.encryption.KeyStore Maven / Gradle / Ivy

The newest version!
package eu.clarussecure.dataoperations.encryption;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import static com.mongodb.client.model.Filters.eq;
import com.mongodb.client.model.UpdateOptions;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bson.Document;

public class KeyStore {
    private static KeyStore instance = null;
    private final MongoDatabase db;
    private final MongoClient mongoClient;
    private final MongoCollection keystoreCollection;
    private int instancesNumber;

    private String confFile = "/etc/clarus/clarus-keystore.conf";
    private String mongoDBHostname = "localhost"; // Default server
    private int mongoDBPort = 27017; // Default port
    private String clarusDBName = "CLARUS"; // Default DB name

    private KeyStore() {
        // Initiate the basic connections to the database
        // Correctly configure the log level
        Logger mongoLogger = Logger.getLogger("org.mongodb.driver");
        mongoLogger.setLevel(Level.SEVERE);
        // Open the configuraiton file to extract the information from it.
        this.processConfigurationFile();
        // Create a new client connecting to "localhost" on port 
        this.mongoClient = new MongoClient(this.mongoDBHostname, this.mongoDBPort);

        // Get the database (will be created if not present)
        this.db = mongoClient.getDatabase(this.clarusDBName);
        this.keystoreCollection = this.db.getCollection("keystore");

        this.instancesNumber++;
    }

    public static KeyStore getInstance() {
        if (KeyStore.instance == null) {
            KeyStore.instance = new KeyStore();
        }
        return KeyStore.instance;
    }

    public void deleteInstance() {
        this.instancesNumber--;

        if (this.instancesNumber <= 0) {
            this.mongoClient.close();
            KeyStore.instance = null;
        }
    }

    public SecretKey retrieveKey(String dataID) {
        SecretKey key = null;
        String stringKey;
        // Check if there is an entry for this data ID
        if (this.keystoreCollection.count(eq("dataID", dataID)) <= 0) {
            // There is not a Key-IV pair, generate one
            this.generateSecurityParameters(dataID);
        }

        // At this point, a Key-IV pair EXISTS in the DB for this dataID
        // Retrieve the key
        MongoCursor keys = this.keystoreCollection.find(eq("dataID", dataID)).iterator();
        if (keys.hasNext()) {
            // A key was found, retrieve it
            Document doc = keys.next();
            stringKey = doc.getString("enckey");
            // Create the Key Object
            byte[] bytesKey = Base64.getDecoder().decode(stringKey);
            key = new SecretKeySpec(bytesKey, 0, bytesKey.length, "AES");
        }
        return key;
    }

    public byte[] retrieveInitVector(String dataID) {
        byte[] bytesIV = new byte[16];
        // Check if there is an entry for this data ID
        if (this.keystoreCollection.count(eq("dataID", dataID)) <= 0) {
            // There is not a Key-IV pair, generate one
            this.generateSecurityParameters(dataID);
        }

        // At this point, a Key-IV pair EXISTS in the DB for this dataID
        // Retrieve the IV
        MongoCursor ivs = this.keystoreCollection.find(eq("dataID", dataID)).iterator();
        if (ivs.hasNext()) {
            // An IV was found, retrieve it
            Document doc = ivs.next();
            String stringIV = doc.getString("initvector");
            // Decode the IV from the string
            bytesIV = Base64.getDecoder().decode(stringIV);
        }

        return bytesIV;
    }

    protected boolean generateSecurityParameters(String dataID) {
        SecretKey key = null;
        String stringKey;
        byte[] bytesIV = new byte[16];
        String stringIV;
        try {
            // Generate new Key for AES algorithm
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(this.getKeyLength());
            key = keygen.generateKey();

            // Encode it into a String
            stringKey = Base64.getEncoder().encodeToString(key.getEncoded());

            // Generate a Random Init Vector
            SecureRandom randomGen = new SecureRandom();
            randomGen.nextBytes(bytesIV);

            // Encode it into a String
            stringIV = Base64.getEncoder().encodeToString(bytesIV);

            // Prepare the document into the dabase
            Document doc = new Document("dataID", dataID);
            doc.append("enckey", stringKey);
            doc.append("initvector", stringIV);

            // Store the encoded key into the database
            boolean ack = this.keystoreCollection
                    .replaceOne(eq("dataID", dataID), doc, new UpdateOptions().upsert(true)).wasAcknowledged();
            return ack;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.exit(1);
        }
        return false;
    }

    private int getKeyLength() {
        // This method should retrieve the key length (in bits) from the DB
        MongoCursor cursor = this.keystoreCollection.find(eq("conf", "simple-keylength")).iterator();

        int keyLength = 128; // Default value is 128 bits
        while (cursor.hasNext()) {
            keyLength = cursor.next().getDouble("keylength").intValue();
        }
        return keyLength;
    }

    private void processConfigurationFile() throws RuntimeException {
        // Open the file in read-only mode. This will avoid any permission problem
        try {
            // Read all the lines and join them in a single string
            List lines = Files.readAllLines(Paths.get(this.confFile));
            String content = lines.stream().reduce("", (a, b) -> a + b);

            // Use the bson document parser to extract the info
            Document doc = Document.parse(content);
            this.mongoDBHostname = doc.getString("CLARUS_keystore_db_hostname");
            this.mongoDBPort = doc.getInteger("CLARUS_keystore_db_port");
            this.clarusDBName = doc.getString("CLARUS_keystore_db_name");
        } catch (IOException e) {
            throw new RuntimeException("CLARUS configuration file could not be processed", e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy