java-RSA 加解密

網上關於RSA的原理一抓一大把的,這裏只是簡單說說我的理解:

  1. 兩個足夠大的互質數p, q;

  2. 用於模運算的模 n=p*q;

  3. 公鑰KU(e, n)中的e滿足 1<e< (p-1)(q-1),且與(p-1)(q-1)互質;

  4. 密鑰KR(d, n)中的d滿足 d*e % (p-1)(q-1)= 1,%是取餘運算。

因爲公鑰是公開的,所以我知道了e和n,那麼根據2,3,4式子的關係,我們只要從n的值推出p, q的值則可計算出d的值,也就能找到密鑰。

然而,關鍵就在這裏, n=p*q,如果兩個互質數p和q足夠大,那麼根據目前的計算機技術和其他工具,至今也沒能從n分解出p和q,這是數學上的一個難題,也正是這個難題成爲了RSA加密至今被廣泛使用的原因。換句話說,只要密鑰長度n足夠大(一般1024足矣),基本上不可能從公鑰信息推出私鑰信息。

好了,這裏作爲研究的隨筆,記錄一下java如何使用,以下主要有三種方法,基本大同小異,只是獲取公鑰私鑰的途徑不一樣就是了:

方法一:

利用KeyPairGenerator直接生成公鑰和密鑰,一般私鑰保留給服務端,公鑰交給客戶端。

public class RSACryptography {
	
	public static String data="hello world";
 
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		
		KeyPair keyPair=genKeyPair(1024);
		
		//獲取公鑰,並以base64格式打印出來
		PublicKey publicKey=keyPair.getPublic();		
		System.out.println("公鑰:"+new String(Base64.getEncoder().encode(publicKey.getEncoded())));
		
		//獲取私鑰,並以base64格式打印出來
		PrivateKey privateKey=keyPair.getPrivate();		
		System.out.println("私鑰:"+new String(Base64.getEncoder().encode(privateKey.getEncoded())));
		
		//公鑰加密
		byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);	
		System.out.println("加密後:"+new String(encryptedBytes));
		
		//私鑰解密
		byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);		
		System.out.println("解密後:"+new String(decryptedBytes));
	}
	
	//生成密鑰對
	public static KeyPair genKeyPair(int keyLength) throws Exception{
		KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("RSA");
		keyPairGenerator.initialize(1024);		
		return keyPairGenerator.generateKeyPair();
	}
	
	//公鑰加密
	public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");//java默認"RSA"="RSA/ECB/PKCS1Padding"
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(content);
	}
	
	//私鑰解密
	public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(content);
	}
 
}

方法二:

實際上,方法一隻是用來生成密鑰就OK了,生成的密鑰需要保存到本地文件中,所以一般不會在客戶端調用KeyPairGenerator進行密鑰的生成操作。

這裏,我們可以將方法一得到的密鑰保存到文件,下次我們直接讀取就可以了。我假設以String的形式保存在文件內,那麼接下來直接使用讀取到的String生成密鑰即可。

當然,你也可以使用openssl來生成也可以。

public class RSACryptography {
	
	public static String data="hello world";
	public static String publicKeyString="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCISLP98M/56HexX/9FDM8iuIEQozy6kn2JMcbZS5/BhJ+U4PZIChJfggYlWnd8NWn4BYr2kxxyO8Qgvc8rpRZCkN0OSLqLgZGmNvoSlDw80UXq90ZsVHDTOHuSFHw8Bv//B4evUNJBB8g9tpVxr6P5EJ6FMoR/kY2dVFQCQM4+5QIDAQAB";
	public static String privateKeyString="MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIhIs/3wz/nod7Ff/0UMzyK4gRCjPLqSfYkxxtlLn8GEn5Tg9kgKEl+CBiVad3w1afgFivaTHHI7xCC9zyulFkKQ3Q5IuouBkaY2+hKUPDzRRer3RmxUcNM4e5IUfDwG//8Hh69Q0kEHyD22lXGvo/kQnoUyhH+RjZ1UVAJAzj7lAgMBAAECgYAVh26vsggY0Yl/Asw/qztZn837w93HF3cvYiaokxLErl/LVBJz5OtsHQ09f2IaxBFedfmy5CB9R0W/aly851JxrI8WAkx2W2FNllzhha01fmlNlOSumoiRF++JcbsAjDcrcIiR8eSVNuB6ymBCrx/FqhdX3+t/VUbSAFXYT9tsgQJBALsHurnovZS1qjCTl6pkNS0V5qio88SzYP7lzgq0eYGlvfupdlLX8/MrSdi4DherMTcutUcaTzgQU20uAI0EMyECQQC6il1Kdkw8Peeb0JZMHbs+cMCsbGATiAt4pfo1b/i9/BO0QnRgDqYcjt3J9Ux22dPYbDpDtMjMRNrAKFb4BJdFAkBMrdWTZOVc88IL2mcC98SJcII5wdL3YSeyOZto7icmzUH/zLFzM5CTsLq8/HDiqVArNJ4jwZia/q6Fg6e8KO2hAkB0EK1VLF/ox7e5GkK533Hmuu8XGWN6I5bHnbYd06qYQyTbbtHMBrFSaY4UH91Qwd3u9gAWqoCZoGnfT/o03V5lAkBqq8jZd2lHifey+9cf1hsHD5WQbjJKPPIb57CK08hn7vUlX5ePJ02Q8AhdZKETaW+EsqJWpNgsu5wPqsy2UynO";
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		
		
		//獲取公鑰 
		PublicKey publicKey=getPublicKey(publicKeyString);
		
		//獲取私鑰 
		PrivateKey privateKey=getPrivateKey(privateKeyString);		
		
		//公鑰加密
		byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);	
		System.out.println("加密後:"+new String(encryptedBytes));
		
		//私鑰解密
		byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);		
		System.out.println("解密後:"+new String(decryptedBytes));
	}
	
	//將base64編碼後的公鑰字符串轉成PublicKey實例
	public static PublicKey getPublicKey(String publicKey) throws Exception{
		byte[ ] keyBytes=Base64.getDecoder().decode(publicKey.getBytes());
		X509EncodedKeySpec keySpec=new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory=KeyFactory.getInstance("RSA");
		return keyFactory.generatePublic(keySpec);	
	}
	
	//將base64編碼後的私鑰字符串轉成PrivateKey實例
	public static PrivateKey getPrivateKey(String privateKey) throws Exception{
		byte[ ] keyBytes=Base64.getDecoder().decode(privateKey.getBytes());
		PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory=KeyFactory.getInstance("RSA");
		return keyFactory.generatePrivate(keySpec);
	}
	
	//公鑰加密
	public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");//java默認"RSA"="RSA/ECB/PKCS1Padding"
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(content);
	}
	
	//私鑰解密
	public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(content);
	}
 
}

方法三:

除了保存密鑰字符串之外,其他的做法一般是隻保存 模n(modulus),公鑰和私鑰的e和d(exponent)。

其中,n, e, d可以這樣獲取到,獲取到後可以保存到本地文件中。

//獲取公鑰
		RSAPublicKey publicKey=(RSAPublicKey) getPublicKey(publicKeyString);
		BigInteger modulus1=publicKey.getModulus();
		BigInteger exponent1=publicKey.getPublicExponent();
			
		//獲取私鑰
		RSAPrivateKey privateKey=(RSAPrivateKey) getPrivateKey(privateKeyString);		
		BigInteger modulus2=privateKey.getModulus();
		BigInteger exponent2=privateKey..getPrivateExponent();

這裏,假設我已經從文件中讀取到了modulus和exponent:

public class RSACryptography {
	
	public static String data="hello world";
	public static String modulusString="95701876885335270857822974167577168764621211406341574477817778908798408856077334510496515211568839843884498881589280440763139683446418982307428928523091367233376499779842840789220784202847513854967218444344438545354682865713417516385450114501727182277555013890267914809715178404671863643421619292274848317157";
	public static String publicExponentString="65537";
	public static String privateExponentString="15118200884902819158506511612629910252530988627643229329521452996670429328272100404155979400725883072214721713247384231857130859555987849975263007110480563992945828011871526769689381461965107692102011772019212674436519765580328720044447875477151172925640047963361834004267745612848169871802590337012858580097";
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub		
		
		//由n和e獲取公鑰
		PublicKey publicKey=getPublicKey(modulusString, publicExponentString);
		
		//由n和d獲取私鑰
		PrivateKey privateKey=getPrivateKey(modulusString, privateExponentString);
		
		//公鑰加密
		byte[] encryptedBytes=encrypt(data.getBytes(), publicKey);	
		System.out.println("加密後:"+new String(encryptedBytes));
		
		//私鑰解密
		byte[] decryptedBytes=decrypt(encryptedBytes, privateKey);		
		System.out.println("解密後:"+new String(decryptedBytes));
	}
	
	//將base64編碼後的公鑰字符串轉成PublicKey實例
	public static PublicKey getPublicKey(String modulusStr, String exponentStr) throws Exception{
		BigInteger modulus=new BigInteger(modulusStr);
		BigInteger exponent=new BigInteger(exponentStr);
		RSAPublicKeySpec publicKeySpec=new RSAPublicKeySpec(modulus, exponent);
		KeyFactory keyFactory=KeyFactory.getInstance("RSA");
		return keyFactory.generatePublic(publicKeySpec);
	}
	
	//將base64編碼後的私鑰字符串轉成PrivateKey實例
	public static PrivateKey getPrivateKey(String modulusStr, String exponentStr) throws Exception{
		BigInteger modulus=new BigInteger(modulusStr);
		BigInteger exponent=new BigInteger(exponentStr);
		RSAPrivateKeySpec privateKeySpec=new RSAPrivateKeySpec(modulus, exponent);
		KeyFactory keyFactory=KeyFactory.getInstance("RSA");
		return keyFactory.generatePrivate(privateKeySpec);
	}
	
	//公鑰加密
	public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");//java默認"RSA"="RSA/ECB/PKCS1Padding"
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(content);
	}
	
	//私鑰解密
	public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
		Cipher cipher=Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(content);
	}
 
}

這裏三種方式總結起來也就是

1.KeyPairGenerator獲取key;

  1. String獲取key;

  2. modulus和exponent獲取key。

加密後的密文可以使用Base64加密下,保存在任意位置。

轉載至:https://blog.csdn.net/qq_18870023/article/details/52596808

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章