001package org.intellimate.izou.security;
002
003import org.apache.logging.log4j.LogManager;
004import org.apache.logging.log4j.Logger;
005import org.bouncycastle.jcajce.provider.digest.SHA3;
006import org.bouncycastle.util.encoders.Hex;
007
008import javax.crypto.*;
009import java.io.UnsupportedEncodingException;
010import java.security.InvalidKeyException;
011import java.security.NoSuchAlgorithmException;
012import java.security.NoSuchProviderException;
013import java.security.Security;
014
015/**
016 * SecurityFunction implements basic cryptographic functions like hash functions or encryption and decryption
017 * functions.
018 */
019public final class SecurityFunctions {
020    private final Logger logger = LogManager.getLogger(this.getClass());
021
022    /**
023     * Applies SHA-3 hash function on the {@code input} string
024     *
025     * @param input the string to apply to SHA-3 hash on
026     * @return the hashed input string
027     */
028    public String sha3(String input) {
029        String hash = "";
030        try {
031            SHA3.DigestSHA3 md = new SHA3.DigestSHA3(256);
032            md.update(input.getBytes("UTF-8"));
033            hash = Hex.toHexString(md.digest());
034        } catch (UnsupportedEncodingException e) {
035            logger.error("Error while hashing with SHA-3", e);
036        }
037
038        return hash;
039    }
040
041    /**
042     * Applies an AES encryption on the string {@code plainText} with they given key
043     * <p>
044     *     Keys have to be generated using the {@link #generateKey()} function
045     * </p>
046     * @param plainText the string to encrypt
047     * @param key the key to use during the encryption
048     * @return a byte array containing the encrypted data
049     */
050    public byte[] encryptAES(String plainText, SecretKey key) {
051        byte[] byteCipherText = new byte[0];
052
053        try {
054            Cipher cipher = Cipher.getInstance("AES", "BC");
055            cipher.init(Cipher.ENCRYPT_MODE, key);
056            byteCipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
057        } catch (BadPaddingException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException
058                | InvalidKeyException | UnsupportedEncodingException | NoSuchProviderException e) {
059            logger.error("Unable to apply AES encryption", e);
060        }
061
062        return byteCipherText;
063    }
064
065    /**
066     * Applies an AES decryption on the byte array {@code cipherBytes} with they given key. The key has to be the same
067     * key used during encryption, else null is returned
068     *
069     * @param cipherBytes the byte array to decrypt
070     * @param key the key to use during the decryption
071     * @return the decrypted string if everything was successful, else null
072     */
073    public String decryptAES(byte[] cipherBytes, SecretKey key) {
074        String plainText = null;
075        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
076        try {
077            Cipher cipher = Cipher.getInstance("AES", "BC");
078            cipher.init(Cipher.DECRYPT_MODE, key);
079            byte[] bytePlainText = cipher.doFinal(cipherBytes);
080            plainText = new String(bytePlainText, "UTF-8");
081        } catch (IllegalBlockSizeException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException
082                | NoSuchPaddingException | UnsupportedEncodingException | NoSuchProviderException e) {
083            logger.error("Unable to apply AES decryption", e);
084        }
085
086        return plainText;
087    }
088
089    /**
090     * Generates a key for the AES encryption
091     *
092     * @return a new key for the AES encryption
093     */
094    public SecretKey generateKey() {
095        SecretKey key = null;
096        try {
097            KeyGenerator generator = KeyGenerator.getInstance("AES");
098            generator.init(128);
099            key = generator.generateKey();
100        } catch (NoSuchAlgorithmException e) {
101            logger.error("Unable to generate AES key", e);
102        }
103
104        return key;
105    }
106}