CryptoRsa2048.java

package sk.iway.iwcm.components.crypto;

import javax.crypto.Cipher;

import sk.iway.iwcm.Constants;
import sk.iway.iwcm.Crypto;
import sk.iway.iwcm.CryptoKeys;
import sk.iway.iwcm.Logger;
import sk.iway.iwcm.Tools;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * CryptoTools - trieda sluzi na sifrovanie a desifrovanie textovych retazcov algoritmom RSA
 * s dlzkou kluca 2048
 */
public class CryptoRsa2048 implements Crypto {
    public static CryptoRsa2048 INSTANCE = new CryptoRsa2048();
    private String ALGORITHM = "RSA";
    private int KEY_SIZE = 2048;

    public CryptoRsa2048() {
    }

    /**
     * Metoda zasifruje data, vrati vo formate base64-enkodovane
     * @param plainData data ktore maju byt zasifrovane
     * @param publicKey verejny kluc ktorym budu data zasifrovane
     * @return zasifrovane data
     */
    public String encrypt(String plainData, String publicKey) throws Exception {
        //ak nemame publicKey tak nic nesifrujeme, vratime ako je
        if (Tools.isEmpty(publicKey))
            return plainData;

        String cleanPublicKey = publicKey;
        Key key = loadPublicKey(cleanPublicKey);
        byte[] encryptedData = encrypt(key, plainData);
        String encrypted = new String(Base64.getEncoder().encode(encryptedData));
        return encrypted;
    }

    /**
     * Metoda desifruje zasifrovane data algoritmom RSA
     * @param encryptedData zasifrovane data
     * @param privateKey sukromny kluc
     * @return desifrovane data
     */
    public String decrypt(String encryptedData, String privateKey) throws Exception {

        // hodnota zacina na encrypted-rsa2048-admin_2 pouzije sa CryptoTools,
        // hodnota zacina na encrypted-v1- pouzije sa CryptoToolsV2
        
        String cleanPrivateKey = privateKey;
        Key key = loadPrivateKey(cleanPrivateKey);
        byte[] data = Base64.getDecoder().decode(((encryptedData).getBytes()));
        final String decrypted = new String(decrypt(key, data));
        return decrypted;
    }

    @Override
    public String getAlgKey() {
        return "-"+ALGORITHM.toLowerCase()+KEY_SIZE+"-";
    }

    /**
     * Vygeneruje privatny a verejny kluc a vrati ho v objekte aj enkodovane
     * @return CrypTokeys objekt obsahuje oba kluce aj enkodovane
     * @throws NoSuchAlgorithmException
     */
    @Override
    public CryptoKeys generateNewPrivateAndPublicKey(String loginName) throws NoSuchAlgorithmException {
        KeyPair keyPair = this.buildKeyPair();

        //int id = PkeyGenerator.getNextValue("crypto_key");

        String privateKeyEncoded = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
        String publicKeyEncoded = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        boolean showLog = Constants.getBoolean("cryptoToolsShowGeneratedKeysLog");
        if (showLog) {
            Logger.println(CryptoRsa2048.class, "=== Generating RSA keys ===");
            Logger.println(CryptoRsa2048.class, "Generated Private key => " + privateKeyEncoded);
            Logger.println(CryptoRsa2048.class, "Generated Public key => " + publicKeyEncoded);
            Logger.println(CryptoRsa2048.class, "===========================");
        }
        return new CryptoKeys(keyPair, publicKeyEncoded, privateKeyEncoded);
    }

    /**
     * Metoda vygeneruje sukromny a verejny kluc na sifrovanie a desifrovanie dat.
     * @return KeyPair objekt s klucami
     * @throws NoSuchAlgorithmException
     */
    private KeyPair buildKeyPair() throws NoSuchAlgorithmException {
        final int keySize = KEY_SIZE;
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(keySize);
        return keyPairGenerator.genKeyPair();
    }

    private byte[] encrypt(Key publicKey, String sensitiveData) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(sensitiveData.getBytes());
    }

    private byte[] decrypt(Key privateKey, byte [] encrypted) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(encrypted);
    }

    private Key loadPublicKey(String publicKey) throws GeneralSecurityException {
        byte[] data = Base64.getDecoder().decode((publicKey.getBytes()));
        X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
        KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
        return fact.generatePublic(spec);
    }

    private Key loadPrivateKey(String key64) throws GeneralSecurityException {
        byte[] clear = Base64.getDecoder().decode(key64.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
        KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
        PrivateKey priv = fact.generatePrivate(keySpec);
        return priv;
    }

}