CryptoFactory.java

package sk.iway.iwcm;

import sk.iway.iwcm.common.DocTools;
import sk.iway.iwcm.components.crypto.CryptoRsa2048;
import sk.iway.iwcm.components.crypto.CryptoTink;

import javax.servlet.http.HttpSession;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;

/**
 * CryptoFactory.java
 * <p>
 * Class CryptoFactory is used for
 * <p>
 * <p>
 * Title        webjet8
 * Company      Interway a.s. (www.interway.sk)
 * Copyright    Interway a.s. (c) 2001-2020
 *
 * @author $Author: mhruby $
 * @version $Revision: 1.0 $
 * created      29. 4. 2020 13:19
 * modified     29. 4. 2020 13:19
 */

public class CryptoFactory {

    // handluje I/O plaintext a encryptovanych dat
    // tu handlujem vsetko na vyse (vsetky hovadiny ktore musim pridat k zasifrovanym dat)

    /**
     * Staticka metoda na jednoduche desifrovanie dat, sama si zisti, ci su sifrovane, ziska kluc zo session a skusi desifrovat
     * @param maybeEncryptedText
     * @return
     */
    public static String decrypt(String maybeEncryptedText) {
        if (Tools.isEmpty(maybeEncryptedText) || maybeEncryptedText.startsWith("encrypted-")==false) return maybeEncryptedText;

        String privateKey = CryptoFactory.getCurrentPrivateKey();
        if (Tools.isEmpty(privateKey)) return maybeEncryptedText;

        return CryptoFactory.decrypt(maybeEncryptedText, privateKey); //NOSONAR
    }

    public CryptoKeys generateKeys(String login) {
        Crypto crypto;
        int id = PkeyGenerator.getNextValue("crypto_key");
        String loginIdprefix = DocTools.removeChars(login, true)+"_"+id;
        if ("CryptoTink".equalsIgnoreCase(Constants.getString("cryptoAlg"))) {
            Logger.debug(getClass(), "Using CryptoTink");
            crypto = CryptoTink.getInstance();
        } else {
            Logger.debug(getClass(), "Using CryptoRsa2048");
            crypto = CryptoRsa2048.INSTANCE;
        }
        CryptoKeys cryptoKeys = null;
        try {
            cryptoKeys = crypto.generateNewPrivateAndPublicKey(login);
            cryptoKeys.setPrivateKeyEncoded("decrypt_key" + crypto.getAlgKey() + loginIdprefix + ":" + cryptoKeys.getPrivateKeyEncoded());
            cryptoKeys.setPublicKeyEncoded("encrypt_key" + crypto.getAlgKey() + loginIdprefix + ":" + cryptoKeys.getPublicKeyEncoded());
        } catch (NoSuchAlgorithmException e) {
            sk.iway.iwcm.Logger.error(e);
        }
        return cryptoKeys;
    }

    public String encrypt(String plainText, String publicKeyBASE64) {

        if (Tools.isEmpty(publicKeyBASE64)) return plainText;

        // podla kluca rozhodnem ktory sifrovaciu implementaciu pouzijem nezaujima ma ako sifrovanie funguje
        Crypto crypto;
        if (publicKeyBASE64.contains(CryptoTink.ALG_KEY))
            crypto = CryptoTink.getInstance();
        else
            crypto = CryptoRsa2048.INSTANCE;
        // pridam prefix z kluca k datam aby pouzivatel vedel kto a ktorym klucom zasifroval dane data
        try {
            RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
            if (rb != null) {
                //ak mame zapnute sifrovanie musime vypnut auditovanie request parametrov
                LinkedHashMap<String, String[]> map = new LinkedHashMap<>();
                rb.setParameters(map);
            }

            return Tools.replace(CryptoFactory.getPrefix(publicKeyBASE64), "encrypt_key", "encrypted") + ":" + crypto.encrypt(plainText, removeRedundantPrefix(publicKeyBASE64));
        } catch (Exception ex) {
            sk.iway.iwcm.Logger.error(ex);
        }
        //ked padne sifrovanie radsej vratim povodne data, aby sme o ne neprisli
        return plainText;
    }

    public static String decrypt(String encryptedText, String privateKey) {
        if (Tools.isEmpty(privateKey) || encryptedText==null || encryptedText.startsWith("encrypted")==false)
            return encryptedText;

        Crypto crypto;
        if (privateKey.contains(CryptoTink.ALG_KEY))
            crypto = CryptoTink.getInstance();
        else
            crypto = CryptoRsa2048.INSTANCE;

        // odstranujem nepotrebne data z encryptovanych dat a kluca
        try {
            String decrypted = crypto.decrypt(removeRedundantPrefix(encryptedText), removeRedundantPrefix(privateKey));
            return decrypted;
        } catch (Exception ex) {
            sk.iway.iwcm.Logger.error(ex);
        }
        //desifrovanie sa nepodarilo, vratim povodny zasifrovany text
        return encryptedText;
    }

    /**
     * Metoda odstrani redundantne (nepotrebne) znaky z kluca
     *
     * @param text
     * @return
     */
    public static String removeRedundantPrefix(String text) {
        String cleanKey = text;
        int i = cleanKey.indexOf(":");
        if (i > 0) {
            cleanKey = cleanKey.substring(i + 1);
        }

        cleanKey = cleanKey.replace("\n", "").replace("\r", "");

        return cleanKey;
    }

    /**
     * Ziska prefix kluca alebo zasifrovanych dat.
     * Priklad: key = encrypted-v2-admin_32:ewogICAgI => encrypted-v2-admin_32
     *
     * @param string
     * @return
     */
    public static String getPrefix(String string) {
        int i = string.indexOf(":");
        if (i > 0) {
            return string.substring(0, i);
        }
        return "";
    }

    public static String getCurrentPrivateKey() {
        RequestBean requestBean = SetCharacterEncodingFilter.getCurrentRequestBean();
        if (requestBean != null) {
            return requestBean.getCryptoPrivateKey();
        }
        return null;
    }

    /**
     * Ulozi privatny kluc do session. Tento kluc sa potom pouzije v JPACryptoConverteri na desifrovanie dat.
     * Vrati true/false podla toho ci sa kluc podarilo vlozit do session a requestBeanu
     * @param session
     * @param privateKey privatny kluc ktory sa pouzije na desifrovanie dat
     * @return podarilo sa ulozit kluc
     */
    public boolean setPrivateKeyToSession(String privateKey, HttpSession session) {
        session.setAttribute("JPACryptoConverter.privateKey", privateKey);
        RequestBean requestBean = SetCharacterEncodingFilter.getCurrentRequestBean();
        if (requestBean != null) {
            requestBean.setCryptoPrivateKey(privateKey);
            return true;
        }
        return false;
    }
}