/*dependencias necessarias (inserir no POM)

    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>
    </dependencies>
 */
import java.nio.charset.Charset;
        import java.security.SecureRandom;

        import javax.crypto.Cipher;
        import javax.crypto.SecretKey;
        import javax.crypto.spec.IvParameterSpec;
        import javax.crypto.spec.SecretKeySpec;

        import org.apache.commons.codec.binary.Base64;

public class Encrypt {
    private static Integer bytesAES = 128;

    public static String encryptAESKey(byte[] key, String publicKey) throws Exception {

        byte[] sigBytes2 = new Base64().decode(publicKey);
        java.security.spec.X509EncodedKeySpec x509KeySpec = new java.security.spec.X509EncodedKeySpec(sigBytes2);
        java.security.KeyFactory keyFact = java.security.KeyFactory.getInstance("RSA");
        java.security.PublicKey pubKey = keyFact.generatePublic(x509KeySpec);
        java.security.Key aesKey = new javax.crypto.spec.SecretKeySpec(key, "AES");
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA");
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, pubKey);
        byte[] encrypted = cipher.doFinal(aesKey.getEncoded());
        return org.apache.commons.codec.binary.Base64.encodeBase64String(encrypted);

    }
    public static byte[] encryptAES(SecretKey key, byte[] plaintext) throws Exception {
        //In practice you should specify your SecureRandom implementation.
        SecureRandom rnd = new SecureRandom();

        //Generate random IV of 128-bit (AES block size)
        byte[] IV = new byte[128 / 8];
        rnd.nextBytes(IV);
        IvParameterSpec IVSpec = new IvParameterSpec(IV);

        //Create the cipher object to perform AES operations.
        //Specify Advanced Encryption Standard - Cipher Feedback Mode - No Padding
        Cipher AESCipher = Cipher.getInstance("AES/CFB/NoPadding");

        //Initialize the Cipher with the key and initialization vector.
        AESCipher.init(Cipher.ENCRYPT_MODE, key, IVSpec);

        //Encrypts the plaintext data
        byte[] ciphertext = AESCipher.doFinal(plaintext);

        /*
         * The IV must now be transferred with the ciphertext somehow. The easiest
         * way to accomplish this would be to prepend the IV to the ciphertext
         * message.
         */

        //Allocate new array to hold ciphertext + IV
        byte[] output = new byte[ciphertext.length + (128 / 8)];

        //Copy the respective parts into the array.
        System.arraycopy(IV, 0, output, 0, IV.length);
        System.arraycopy(ciphertext, 0, output, IV.length, ciphertext.length);

        return output;
    }
    public static String encrypt(String data, String key) throws Exception  {

        SecretKey aesKey = new SecretKeySpec(Base64.decodeBase64(key), "AES");
        byte[] cipherText = encryptAES(aesKey, data.getBytes(Charset.forName("UTF-8")));
        return Base64.encodeBase64String(cipherText);
    }

    public static void main(String[] args) throws Throwable {

        // Trecho de código para gerar a chave AES.
        javax.crypto.KeyGenerator keyGen = javax.crypto.KeyGenerator.getInstance("AES");
        keyGen.init(bytesAES); // for example
        javax.crypto.SecretKey secretKey = keyGen.generateKey();

        // Recuperando a chave publica.

        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRndXd8VPBPzPzluMo4hcotHrA6oK4DeDPLpML2pgE6OEL27aNS8xAY0ihZzS401YbhqR7rHFLB76Za8a5VoYcueg4EfBJzSgsmozIuCS3f/CAPFECSy4XKR0LgFitbLglIwt/V565WtrVzuvIoKQj7UULnjx0zmzb0Yiv24d9NwIDAQAB";
        // Encriptando a sua chave AES
        String cryptedKey = encryptAESKey(secretKey.getEncoded(), publicKey);

        String secretKeyBase64 = org.apache.commons.codec.binary.Base64.encodeBase64String(secretKey.getEncoded());

        String textplain = encrypt("{\"teste\":\"teste\"}", secretKeyBase64);

        System.out.println(cryptedKey);

        System.out.println(secretKeyBase64);

        System.out.println(textplain);
    }
}
