package rsacryptcsvColumn;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author Anass AIT BEN EL ARBI
 * <ul>
 *     <li>AES/CBC/NoPadding (128)</li>
 *     <li>AES/CBC/PKCS5Padding (128)</li>
 *     <li>AES/ECB/NoPadding (128)</li>
 *     <li>AES/ECB/PKCS5Padding (128)</li>
 *     <li>RSA/ECB/PKCS1Padding (1024, 2048)</li>
 *     <li>RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)</li>
 *     <li>RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)</li>
 * </ul>
 * <p>
 * for more details @see <a href="https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html">Java Ciphers</a>
 */

//https://gist.github.com/Anass-ABEA/e2627b5df9abf23e006bcd5d390de205

public class RSA {

    private PrivateKey privateKey;
    private PublicKey publicKey;

    private String PRIVATE_KEY_STRING;
    private String PUBLIC_KEY_STRING;
    
    public void init(){
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
            generator.initialize(1024);
            KeyPair pair = generator.generateKeyPair();
            privateKey = pair.getPrivate();
            publicKey = pair.getPublic();
        } catch (Exception ex) {
        	System.err.println(ex.getMessage());
        }
    }
    
    public void setPrivKey(String privKey) {
    	PRIVATE_KEY_STRING = privKey;
    }
    public void setPubKey(String pubKey) {
    	PUBLIC_KEY_STRING = pubKey;
    }
    
    public String getPrivKey() {
    	return encode(privateKey.getEncoded());
    }
    public String getPubKey() {
    	return encode(publicKey.getEncoded());
    }

    public void initFromStrings(){
        try{
            X509EncodedKeySpec keySpecPublic = new X509EncodedKeySpec(decode(PUBLIC_KEY_STRING));
            PKCS8EncodedKeySpec keySpecPrivate = new PKCS8EncodedKeySpec(decode(PRIVATE_KEY_STRING));

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            publicKey = keyFactory.generatePublic(keySpecPublic);
            privateKey = keyFactory.generatePrivate(keySpecPrivate);
        }catch (Exception ex){
        	//System.err.println(ex.getMessage());
        }
    }


    public void printKeys(){
        System.err.println("Public key\n"+ encode(publicKey.getEncoded()));
        System.err.println("Private key\n"+ encode(privateKey.getEncoded()));
    }

    public String encrypt(String message) throws Exception {
        byte[] messageToBytes = message.getBytes();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(messageToBytes);
        return encode(encryptedBytes);
    }

    private static String encode(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }
    private static byte[] decode(String data) {
        return Base64.getDecoder().decode(data);
    }

    public String decrypt(String encryptedMessage) throws Exception {
        byte[] encryptedBytes = decode(encryptedMessage);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedMessage = cipher.doFinal(encryptedBytes);
        return new String(decryptedMessage, "UTF8");
    }
    /*
    public static void main(String[] args) {
        RSA rsa = new RSA();
        rsa.initFromStrings();
        
        try{
            String encryptedMessage = rsa.encrypt("Dies ist ein extrem langer Kommentar asdfasdf  asdfwelrkja a etdakjer aflkaej tga  alswkjg a-lej avalksdlswiejssfss");
   
            String decryptedMessage = rsa.decrypt(encryptedMessage);

            System.err.println("Encrypted:\n"+encryptedMessage);
            System.err.println("Decrypted:\n"+decryptedMessage);
          
         }catch (Exception ex){
        	 System.err.println(ex.getMessage());
         }

        //rsa.init();
        //rsa.printKeys();         

    }
    */
}
