import java.util.Scanner;
public class RsaUtil {
private long p,q;//輸入的兩個素數p、q
private long n;//兩個素數p、q的乘積之和n
private long phi;//n的歐拉函數值phi=(p-1)*(q-1)
private long e;//公鑰
private long d;//密鑰
final static int MAXLENGTH=500;//定義數組的個數的最大值
private int size=0;//用於表示明文/密文的數組的整數的(實際個數+1)
public long[] clear=new long[MAXLENGTH];//明文
public long[] Ciphertext=new long[MAXLENGTH];//密文
public long[] decryptionText=new long[MAXLENGTH];//解密後的明文
public boolean primenumber(long t){
//判斷是否爲素數
boolean test=true;
long k=0;
k=(long)Math.sqrt((double)t);
outer:
for(int i=2;i<=k;i++){
if((t%i)==0){
test=false;
break outer;
}
}
return test;
}
public void inputPQ() throws Exception{
//輸入兩個素數p、q
Scanner input =new Scanner(System.in);
do{
System.out.println("請輸入素數p:");
p=input.nextLong();
}while(!primenumber(this.p));
do{
System.out.println("請輸入素數q:");
q=input.nextLong();
}while(!primenumber(this.q));
n=p*q; //兩個素數的乘積n
phi=(p-1)*(q-1); //計算歐拉函數值phi
System.out.println("這兩個素數的乘積n="+p+"*"+q+"="+n);
System.out.println("所得的"+n+"的歐拉函數值phi="+(p-1)+"*"+(q-1)+"="+phi);
}
public long gcd(long a,long b){
//求兩個數的最大公約數,採用遞歸算法
long temp;
if(b==0)
temp=a;
else
temp=gcd(b,a%b);
return temp;
}
public void getPublicKey() throws Exception{
//求出公鑰e
for(int i=0;;i++){
e=(long)(Math.random()*(this.phi+1));//由系統隨機產生一個與phi互質且小於phi的正整數e
while((e==0)||(e==1)){
e=(long)(Math.random()*(this.phi+1));//避免系統產生的e爲零或1
}
if((this.gcd(phi, e)==1)&&(e<phi))
break;
}
System.out.println("系統自動產生一個與"+phi+"互素且比"+phi+"小的整數e:"+e);
System.out.println("產生的公鑰{e,n}={"+this.e+","+n+"}");
}
public void getPrivateKey(){
//利用Euclid算法計算獲得私鑰d
long value=1;
outer:
for(long i=1;;i++){
//e*d=1(mod phi)
value=i*this.phi+1;
if((value%this.e==0)&&(value/this.e<this.phi)){
d =value/this.e;
break outer;
}
}
System.out.println("產生的私鑰{d,n}={"+this.d+","+n+"}");
}
public void encryption() throws Exception{
//加密算法
Scanner input =new Scanner(System.in);
System.out.println("請輸入明文,要求輸入的所要加密的是小於"+n+"的正整數(個數不超過MAXLENGTH=500,以輸入-1爲結束標誌):");
//輸入要加密的明文
for(int i=0;i<MAXLENGTH;i++){
clear[i]=input.nextLong();
while(clear[i]>=n){
System.out.println("請輸入比"+n+"小的值");
clear[i]=input.nextLong();
}
size++; //記錄明文的數組的整數的(實際個數+1),包括-1在內
if(clear[i]==-1)//當輸入-1時中止輸入的循環語句
break;
}
System.out.print("輸入的明文爲:"); //輸出鍵盤輸入的明文
for(int i=0;i<size-1;i++)
System.out.print(clear[i]);
System.out.println();
for(int k=0;k<size-1;k++)
Ciphertext[k]=1; //Ciphertext[]初始化爲1
long count;
for(int j=0;j<size-1;j++){
count=this.e;//count表示加密時的次方數
if(clear[j]==-1)
break;
while(count>0){
Ciphertext[j]=(Ciphertext[j]*clear[j])%n;//將加密後密文放入Ciphertext[]中
count--;
}
}
System.out.print("所得的密文爲:");
for(int h=0;h<size;h++)
System.out.print(Ciphertext[h]);
System.out.println();
}
public void decode(){
//解密算法
long count;
for(int i=0;i<size-1;i++) //(size-1)爲密文實際長度
decryptionText[i]=1;
for(int j=0;j<size-1;j++){
count=this.d; //count表示解密時的次方數
while(count>0){
decryptionText[j]=(decryptionText[j]*Ciphertext[j])%n;
count--;
}
}
System.out.print("解密後明文爲:");
for(int k=0;k<size-1;k++)
System.out.print(decryptionText[k]);
System.out.println();
}
public static void main(String[] args)throws Exception{
RsaUtil t=new RsaUtil();
t.inputPQ();//輸入兩個素數p、q,計算出n,phi
t.getPublicKey();//算出公鑰e
t.getPrivateKey();//算出私鑰d
t.encryption();//輸入明文,並對明文進行加密
t.decode();//對密文進行解密
}
}
java