import java.util.Random;
import java.math.BigInteger;

public class RSA {
    private BigInteger n, e, d;

    public RSA(String p, String q) {
        BigInteger pBig = new BigInteger("p");
        BigInteger qBig = new BigInteger("q");
        this.n = pBig.multiply(qBig);
        this.e = generateE(pBig, qBig);
        this.d = generateD(pBig, qBig);
    }

    public RSA(String p, String q, String e) {
        BigInteger pBig = new BigInteger(p);
        BigInteger qBig = new BigInteger(q);
        BigInteger eBig = new BigInteger(e);
        this.n = pBig.multiply(qBig);
        this.e = generateE(pBig, qBig);
        this.d = generateD(eBig, totient(pBig, qBig));
    }

    private BigInteger totient(BigInteger p, BigInteger q) {
        return (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
    }

    private BigInteger generateE(BigInteger p, BigInteger q) {
        Random random = new Random();
        BigInteger calculate = totient(p, q);
        BigInteger prime = BigInteger.probablePrime(calculate.bitLength(), random);
        return prime;
    }

    private BigInteger generateD(BigInteger e, BigInteger totient) {
        BigInteger value;
        BigInteger calculate = totient(e, totient);
        int i = 1;
        while(true) {
            this.d = new BigInteger("" + i);
            value = e.multiply(d).divide(calculate);
            if (value.equals(BigInteger.ONE)) {
                break;
            }
            i++;
        }
        return totient;
    }

    public String encrypt(String message) {
        String string = "";
        for (int i = 0; i < message.length(); i++) {
            string += (int) message.charAt(i);
        }
        BigInteger msg = new BigInteger(string);
        return msg.modPow(e, n).toString(); // msg^e % n == result
    }

    public String decrypt(String message) {
        String string = "";
        for (int i = 0; i < message.length(); i++) {
            string += (int)message.charAt(i);
        }
        BigInteger msg = new BigInteger(string);
        return msg.modPow(d, n).toString(); // msg^d % n == result
    }
}
public static void main(String[] args) {
        RSA rsa = new RSA("19","79", "17");
        String message = "Hello World";
        message = rsa.encrypt(message);
        System.out.println(message);
        message = rsa.decrypt(message);
        System.out.println(message);
    }