//****************************************************************************************************************************
//****************************************************************************************************************************
//**Autor: 					Mike Widmer																						**
//**Fertigstellung:																											**
//**Version:																												**
//**Zweck: 					Kodieren von Wörtern in Zahlen und Dekodieren von Zahlen in Buchstaben nach dem RSA				**
//**Benötigte Dateien: 		InOut.java																						**
//****************************************************************************************************************************
//****************************************************************************************************************************


class RSAEnDecoderV3
{
	public static void main (String[] args)
	{
		int Wahl;
		int p,q,n,e,d, grenze;
		int[] d1;
		char[] a;
		int[] Code;
		int Verschiebung;
		int counter=0;
		char[] Code2;
		boolean test;
		String Text;
		char[] text;
		do
		{
			System.out.println("Bitte waehlen Sie 1 um zu codieren und 2 um zu dekodieren");
			Wahl=InOut.getInt();
			if(Wahl!=1&&Wahl!=2)
			{
				System.out.println("Neee Sie muessen zwischen 1 und 2 waehlen und nix anderes");
			}
		}while(Wahl!=1&&Wahl!=2);
		if(Wahl==1)
		{
			System.out.println("Bitte geben Sie den zu kodierenden Text in KLEINBUCHSTABEN ein");
			Text=InOut.getLine();
			Text=InOut.getLine();
			System.out.println("Waehlen Sie wo der Zahlenbereich fuer die Buchstaben anfaengt.");
			System.out.println("Fuer ASCII Kleinbuchstaben waehle 97 fuer Grossbuchstaben 65.");
			Verschiebung=InOut.getInt();
			Verschiebung=97-Verschiebung;
			a=Text.toCharArray();
			Code=new int[a.length];
			for(int i=0;i<a.length;i++)
			{
				if((int)a[i]==32)
				{
					Code[i]= (int)a[i];
				}
				else
				{
					Code[i]= (int)a[i]-Verschiebung;
				}
			}

			System.out.println();
			System.out.println("Falls Sie einen der folgenden Werte nicht haben geben Sie 0 an");
			System.out.println();

			do
			{
				System.out.println("Bitte geben Sie eine erste Primzahl ein");
				System.out.print("p= ");
				p=InOut.getInt();
				test=Testprim(p);
				if(test==false)
				{
					System.out.println("SIE MUESSEN EINE PRIMZAHL EINGEBEN, DIES WAR KEINE PRIMZAHL");
					System.out.println("Geben Sie diesmal eine Primzahl ein");
				}
			}while(test==false);
			do
			{
				System.out.println("Bitte geben Sie eine zweite Primzahl ein");
				System.out.print("q= ");
				q=InOut.getInt();
				test=Testprim(q);
				if(test==false)
				{
					System.out.println("SIE MUESSEN EINE PRIMZAHL EINGEBEN, DIES WAR KEINE PRIMZAHL");
					System.out.println("Geben Sie diesmal eine Primzahl ein");
				}
			}while(test==false);

			if(p==0||q==0)
			{
				System.out.println();
				System.out.println("Bitte geben Sie den Public Key n an");
				n=InOut.getInt();
				System.out.println();
				p=factor(n);
				q=n/p;
				System.out.println();
				System.out.println("p und q lauten: "+p+" "+q);
				System.out.println();
			}
			else
			{
				n=p*q;
				System.out.println("Der erste Teil des Public Key lautet:");
				System.out.println("n="+n);
				System.out.println();
			}


			grenze=(p-1)*(q-1);
			int z, length=0;
			for(int i=2;i<n;i++)
			{
				z=ggt(i,grenze);
				if(z==1)
				{
					length++;
				}
			}
			d1=new int[length];
			relprim(d1,grenze,n);

			if(d1.length<=20)
			{
				System.out.println("Bitte geben Sie eine der folgenden Zahlen als zweiten Teil des Public Keys ein");

				for(int i=0;i<d1.length;i++)
				{
				System.out.print(d1[i]+"  ");
				}
				System.out.println();
				System.out.println();
				System.out.println("Falls Sie den Privat Key d angeben wollen geben Sie 0 ein");
				System.out.println();
			}
			else
			{
				System.out.println("Bitte geben Sie eine Zahl, die kleiner als n ("+n+") ist und relativ prim zu");
				System.out.println("(p-1)*(q-1) ("+(p-1)*(q-1)+") als zweiten Teil des Public Keys ein");
				System.out.println("Falls Sie den Privat Key d angeben wollen geben Sie 0 ein");
				System.out.println();
			}

			boolean spaeter_d_ausgeben=true;

			do
			{
				test=false;
				System.out.print("e= ");
				e=InOut.getInt();

				if(e==0)
				{
					System.out.println("Na gut dann geben Sie jetzt den Private Key d ein:");
					System.out.print("d= ");
					d=InOut.getInt();
					System.out.println();
					grenze=(p-1)*(q-1);
					e=ModInv(d,grenze);
					System.out.println();
					System.out.println("e lautet: "+e);
					System.out.println();
					spaeter_d_ausgeben=false;
				}


				for(int i=0;i<d1.length;i++)
				{
					if(e==d1[i])
					{
						test=true;
					}
				}

				if(test==false)
				{
					System.out.println();
					System.out.println("Dies ist kein erlaubter Wert. e muss kleiner als n ("+n+") sein und");
					System.out.println("relativ prim zu (p-1)*(q-1) ("+(p-1)*(q-1)+") sein");

					System.out.println();
				}


			}while(test==false);

			if(spaeter_d_ausgeben==true)
			{
				System.out.println();
				System.out.println("Der Privat Key lautet:");
				d=ModInv(e,grenze);
				System.out.println("d= "+d);
				System.out.println();
			}

			Kodierung(Code,e,n);
			System.out.println("Der Text lautet kodiert:");
			System.out.println();
			for(int i=0; i<Code.length;i++)
			{
				System.out.print(Code[i]+"  ");
			}
			System.out.println();
			System.out.println();
		}

		else
		{
			System.out.println("Bitte geben Sie den Code im Zehnersystem");
			System.out.println("mit einem Leerschlag zwischen den Zahlen ein");
			Text=InOut.getLine();
			Text=InOut.getLine();
			Code2=Text.toCharArray();
			for(int i=0;i<Code2.length;i++)
			{
				if((int)Code2[i]==32)
				{
					counter++;
				}
			}
			counter=counter+1;
			Code=new int[counter];
			int j=0;
			for(int i=0;i<Code2.length;i++)
			{
				if((int)Code2[i]!=32)
				{
					Code[j]=Code[j]+((int)Code2[i]-48);
				}
				if(i+1!=Code2.length)
				{
					if((int)Code2[i+1]==32)
					{
						j++;
					}
					else
					{
						Code[j]=Code[j]*10;
					}
				}

			}
			System.out.println("Falls Sie einen der folgenden Werte nicht haben geben Sie 0 an");
			System.out.println("Geben Sie die erste Primzahl p an");
			p=InOut.getInt();
			System.out.println("Geben Sie die zweite Primzahl q an");
			q=InOut.getInt();
			if(p==0||q==0)
			{
				System.out.println("Geben Sie den Public Key n an");
				n=InOut.getInt();
				p=factor(n);
				q=n/p;
				System.out.println();
				System.out.println("p und q lauten: "+p+" "+q);
				System.out.println();
			}
			else
			{
				System.out.println("Der Public Key n lautet:");
				n=p*q;
				grenze=(p-1)*(q-1);
				System.out.println("n= "+n);
			}
			System.out.println("Geben Sie den Public Key e an");
			e=InOut.getInt();
			if(p==0||q==0||e==0)
			{
				System.out.println("Bitte geben Sie den Privat Key d an");
				d=InOut.getInt();
			}
			else
			{

				System.out.println("Der Privat Key d lautet:");
				grenze=(p-1)*(q-1);
				d=ModInv(e,grenze);
				System.out.println("d= "+d);
			}

			if(e==0)
			{
				grenze=(p-1)*(q-1);
				e=ModInv(d,grenze);
				System.out.println();
				System.out.println("e lautet: "+e);
				System.out.println();
			}

			if(d==0)
			{
				grenze=(p-1)*(q-1);
				d=ModInv(e,grenze);
				System.out.println("d lautet: "+d);
				System.out.println();
			}
			System.out.println("Waehlen Sie wo der Zahlenbereich fuer die Buchstaben anfaengt.");
			System.out.println("Fuer ASCII Kleinbuchstaben waehle 97 fuer Grossbuchstaben 65.");
			Verschiebung=InOut.getInt();
			Verschiebung=97-Verschiebung;
			text=new char[Code.length];
			long x=1;
			Verschiebung=64;
			for(int i=0;i<Code.length;i++)											//Dekodierung
			{
				long dec=1;
				for(int g=0;g<d;g++)
				{
					dec=(dec*Code[i])%n;
					x=dec=dec%n;
				}
				text[i]=(char)(dec+Verschiebung);
			}
			System.out.println("Der Text lautet:");
			System.out.println();
			for(int i=0;i<text.length;i++)
			{
				System.out.print(text[i]);
			}
			System.out.println();
			System.out.println();
			System.out.println("Oder als Zahlen:");
			System.out.println();
			for(int i=0;i<text.length;i++)
			{
				System.out.print((int)(text[i]-Verschiebung));
				System.out.print(" ");
			}
			System.out.println();
			System.out.println();
		}


	}

//------------------------------------------------------------

	public static boolean Testprim(int x)
	{
		boolean test=true;
		for(int i=2;i<x;i++)
		{
			if(x%i==0)
			{
				test=false;
			}
		}
		return test;
	}

//---------------------------------------------------------------

	public static void relprim (int []d1,int grenze,int n)
	{
		int z;
		int j=0;
		for(int i=2;i<n;i++)
		{
			z=ggt(i,grenze);
			if(z==1)
			{
				d1[j]=i;
				j++;
			}
		}
	}

//--------------------------------------------------------------

	public static int ggt(int i, int y)
	{
		while(i>0&&y>0)
		{
			if(y>i)
			{
				i=y+i;
				y=i-y;
				i=i-y;
			}
			i=i-y;
		}
		return i+y;
	}

//-------------------------------------------------------------------

	public static int ModInv(int e, int grenze)
	{
		int d=0;
		for(int i=1; d==0;i++)
		{
			if((grenze*i+1)%e==0)
			{
				d=(grenze*i+1)/e;
			}
		}
		return d;
	}

//---------------------------------------------------------------------

	public static int factor(double n)
	{
		for(int i=3;i<n;i++)
		{
			if(n%i==0)
			{
				return i;
			}
		}
		return 0;
	}

//---------------------------------------------------------------------
	public static void Kodierung(int[] Code, int e, int n)
	{
		long x;
		for(int i=0;i<Code.length;i++)
		{
			x=1;
			for(int j=0;j<e;j++)
			{
				x=(x*Code[i])%n;
			}
			Code[i]=(int)x;
		}
	}

//--------------------------------------------------------------------




}
