1. 程式人生 > 實用技巧 >RSA加密與解密

RSA加密與解密

1.實驗目的

(1)掌握金鑰生成、加密、解密的方法

(2)掌握RSA加密與解密原理及流程

2.實驗內容

(1)RSA原理及分析

(2)檢視生成的金鑰與解密後的金鑰是否一致

3.實驗原理

    RSA公開金鑰密碼體制是一種使用不同的加密金鑰與解密金鑰,“由已知加密金鑰推匯出解密金鑰在計算上是不可行的”密碼體制。

    在公開金鑰密碼體制中,加密金鑰(即公開金鑰)PK是公開資訊,而解密金鑰(即祕密金鑰)SK是需要保密的。加密演算法E和解密演算法D也都是公開的。雖然解密金鑰SK是由公開金鑰PK決定的,但卻不能根據PK計算出SK。

    RSA公開金鑰密碼體制的原理是:根據數論,尋求兩個大素數比較簡單,而將它們的乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密金鑰。

    RSA的安全性依賴於大數分解,但是否等同於大數分解一直未能得到理論上的證明,也並沒有從理論上證明破譯。RSA的難度與大數分解難度等價。因為沒有證明破解RSA就一定需要做大數分解。假設存在一種無須分解大數的演算法,那它肯定可以修改成為大數分解演算法,即RSA的重大缺陷是無法從理論上把握它的保密效能如何,而且密碼學界多數人士傾向於因子分解不是NPC問題。

    RSA演算法的保密強度隨其金鑰的長度增加而增強。但是,金鑰越長,其加解密所耗用的時間也越長。因此,要根據所保護資訊的敏感程度與攻擊者破解所要花費的代價值不值得以及系統所要求的反應時間來綜合考慮,尤其對於商業資訊領域更是如此。

4.實驗記錄

BytesHexConverter.java程式碼:

package key;

public class BytesHexConverter {
    public static byte[] hexToBytes(String hex) {
        hex = hex.length() % 2 != 0 ? "0" + hex : hex;

        byte[] b = new byte[hex.length() / 2];
        for (int i = 0; i < b.length; i++) {
            int index = i * 2;
            int v = Integer.parseInt(hex.substring(index, index + 2), 16);
            b[i] = (byte) v;
        }
        return b;
    }

    public static String byteToHex(byte[] bytes){
        String strHex = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < bytes.length; n++) {
            strHex = Integer.toHexString(bytes[n] & 0xFF);
            sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每個位元組由兩個字元表示,位數不夠,高位補0
        }
        return sb.toString().trim();
    }

}

1)生成一個隨機金鑰,作為待加密資料

Skey_DES.java程式碼:

package key;

import java.io.*;
import javax.crypto.*;

public class Skey_DES

{//對稱金鑰的生成,並通過物件序列化方式儲存在檔案中

    public static void main(String args[]) throws Exception

   {

            KeyGenerator kg=KeyGenerator.getInstance("DESede");//建立金鑰生成器

            kg.init(168);//初始化金鑰生成器

            SecretKey k=kg.generateKey( );//生成金鑰

            //通過物件序列化方式將金鑰儲存在檔案中

       String secretKeyContent = BytesHexConverter.byteToHex(k.getEncoded());

       System.out.println(secretKeyContent);

            FileOutputStream  f1=new FileOutputStream("c:/A/Key.dat");
            ObjectOutputStream b1=new  ObjectOutputStream(f1);
             b1.writeObject(k);
      }
}

key:待加密的key


圖1. 生成的待加密的key

2)生成公私鑰對

Skey_RSA.java程式碼:

package key;

import java.io.*;
import java.security.*;

public class Skey_RSA {

	public static void main(String[] args) throws Exception{
		//???????????KeyPairGenerator?????????????????RSA,DSA
		KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA");

		kpg.initialize(1024);

		KeyPair kp=kpg.genKeyPair();
		PublicKey pbkey=kp.getPublic();
		PrivateKey prkey=kp.getPrivate();
		FileOutputStream  f1=new FileOutputStream("c:/A/Skey_RSA_pub.dat");
		ObjectOutputStream b1=new ObjectOutputStream(f1);
		b1.writeObject(pbkey);
		FileOutputStream  f2=new FileOutputStream("c:/B/Skey_RSA_priv.dat");
		ObjectOutputStream b2=new ObjectOutputStream(f2);
		b2.writeObject(prkey);

	}

}

圖2. Skey_RSA_pub.dat為生成的公鑰

圖3. 為Skey_RSA_priv.dat為生成的私鑰

3)對Key.dat使用公鑰進行加密

Enc_RSA.java程式碼:

package key;

import javax.crypto.SecretKey;
import java.security.interfaces.RSAPublicKey;
import java.math.*;
import java.io.*;
public class Enc_RSA {

	public static void main(String[] args) throws Exception{
//		BufferedReader in=new BufferedReader(new InputStreamReader(new FileInputStream("c:/A/Key.dat")));
//		String s=in.readLine();
		FileInputStream fileInputStream= new FileInputStream("c:/A/Key.dat");
		ObjectInputStream a=new ObjectInputStream(fileInputStream);
		SecretKey key= (SecretKey)a.readObject();
		FileInputStream f=new FileInputStream("c:/A/Skey_RSA_pub.dat");
		ObjectInputStream b=new ObjectInputStream(f);
		//公鑰轉換為RSA公鑰
		RSAPublicKey pbk=(RSAPublicKey)b.readObject();
		//獲取公鑰引數:公鑰對應的整數e,用於取模的整數n
		BigInteger e=pbk.getPublicExponent();
		BigInteger n=pbk.getModulus();
		System.out.println("e="+e);
		System.out.println("n="+n);
		byte ptext[]=key.getEncoded();
		System.out.println(BytesHexConverter.byteToHex(ptext));
		BigInteger m=new BigInteger(ptext);
		BigInteger c=m.modPow(e,n);
		System.out.println("c="+c);
		String cs=c.toString();
		BufferedWriter out=
			new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Enc_RSA.dat")));
		out.write(cs,0,cs.length());
		out.close();

	}

}

圖4. 加密結果,其中e為公鑰引數,n為用於取模的整數,c為加密後的資料

4)對c使用私鑰進行解密

Dec_RSA.java程式碼:

package key;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.interfaces.*;
import java.math.*;
import java.io.*;
public class Dec_RSA {


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

		BufferedReader in=new BufferedReader (
			new InputStreamReader(new FileInputStream("Enc_RSA.dat")));
	String ctext=in.readLine();
	BigInteger c=new BigInteger(ctext);
	FileInputStream f=new FileInputStream("c:/B/Skey_RSA_priv.dat");
	ObjectInputStream b=new ObjectInputStream(f);
	RSAPrivateKey prk=(RSAPrivateKey)b.readObject();
	BigInteger d=prk.getPrivateExponent();
	BigInteger n=prk.getModulus();
	System.out.println("d="+d);
	System.out.println("n="+n);

	BigInteger m=c.modPow(d, n);
	System.out.println("m="+m);
	byte[]mt=m.toByteArray();
		SecretKey key=new SecretKeySpec(mt,"DESede");
		System.out.println("new key="+BytesHexConverter.byteToHex(key.getEncoded()));
	System.out.println("Plain Text is");
		FileOutputStream f1=new FileOutputStream("c:/B/Key.dat");
		ObjectOutputStream b1=new ObjectOutputStream(f1);
		b1.writeObject(key);
		b1.close();
		f1.close();
//	for(int i=0;i<mt.length;i++){
//		System.out.print((char)mt[i]);
//		FileOutputStream f1=new FileOutputStream("c:/B/Key.dat");
//		ObjectOutputStream b1=new ObjectOutputStream(f1);
//		b1.writeObject(m);
//	}
	}

}

圖5. 解密結果,其中d為私鑰引數,n為取模的整數,m為n的尤拉函式,new key為解密後的key