Java之RSA加解密解析

  說明:在上篇中提到Base64加解密(詳細參見上),但Base64自己並非用來作加解密的。雖然能夠經過變化的序列來達到加解密目的,但Base64有一個問題那就是不具有驗證性,它不驗證目標源是否是通過Base64加密過的,是否能解的開;統統來者不拒,解出來的東西有時候莫名其妙,因此通常仍是建議少用Base64去作加解密。   本文提到RSA是一個標準的非對稱加解密算法,使用場景:根據RSA的特性,它有公鑰和私鑰兩個密匙,一般能夠用在一端加密、另一通須要解密的場景,另一個加密的長度問題在正文中討論;若是僅僅用來作驗籤則沒有必要用。java

1、什麼是非對稱算法


  非對稱密鑰算法是指一個加密算法的加密密鑰和解密密鑰是不同的,或者說不能由其中一個密鑰推導出另外一個密鑰。具體實現算法原理可參見官方說明,這裏主要基於java的應用級別介紹。算法


2、RSA中的長度問題


一、RSA初始化長度   Java中實現的初始化長度默認是512,因此若是小於512會拋異常,這裏的長度是bit數組

在這裏插入圖片描述
二、目標文本長度
在這裏插入圖片描述
在這裏插入圖片描述
  根據上面兩個圖示,一樣的初始化長度,惟一的區別就是第二個圖中的目標文本長度是54,致使加解密失敗。那目標文本長度與初始化長度有什麼關係?在Java對RSA的實現中有一個計算公式,目標文本的長度(字節)<=RSA初化長度-11; 結合公式分析一下上面RSA的字節長度=512/8,即64個字節;64-11=53字節,因此要求目標文本長度必定是小於等於53個字節長度。   這裏也能夠解決在最開始應用場景中的另一個問題,在使用RSA對文本加解密時必定要考慮目標文本的長度,若是文本較長,能夠適當調節初始化長度(建議是8的倍數,緣由不用多說了吧)。   注意: RSA的初始化長度越大,能夠加密的目標文本長度越大,加密後的密文越長,但加密時的性能越差,須要綜合平衡(若目標文本過長,建議分段加密);另外注意上面長度的單位。


3、RSA爲何常和Base64一塊兒使用


一、編碼一致性,Base64設計最初的目的就是解決網絡傳速時,編碼不一致問題,這個很容易理解。 二、二進制的不可見性 bash

在這裏插入圖片描述
  RSA中字符串String用來存放明文,Byte數組用來存放加密後的密文;既然是密文天然不想容易被轉換;經過上面的小demo能夠很清楚的看出,String和Byte數組之間能夠很容易轉換,因此這也是爲何引入Base64的緣由。


4、完整的DEMO


   若是讓Base64具備加解密的功能,至少要一部分是變化的;這裏能夠經過變化標準序列的方式;建議你們用到的時候,能夠先看一下第3部分中標出那個類的源碼(沒幾行代碼);這個變化的序列能夠根據時間、根據UUID、根據一切能夠變換的東西來生成,這裏是根據UUID來隨機生成序列。    一、生成隨機序列網絡

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public final class RSAUtils {
    /**
     * 指定長度來生成RSA公私鑰對。
     */
    public static KeyPair generateRSAKeyPair(int bitLength) throws NoSuchAlgorithmException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        if (bitLength > 0)
            kpg.initialize(bitLength);
        return kpg.generateKeyPair();
    }
    public static String getBase64Key(Key key) {
        byte[] encoded = key.getEncoded();
        return new BASE64Encoder().encode(encoded);
    }
    /**
     * 根據提供的base64編碼生成RSA公鑰。
     */
    public static PublicKey getPubKey(String base64String) throws Exception {
        X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(base64String)); 
        return KeyFactory.getInstance("RSA").generatePublic(pubSpec);
    }
    /**
     * 根據提供的base64編碼生成RSA私鑰。
     */
    public static PrivateKey getPriKey(String base64String) throws Exception {
        PKCS8EncodedKeySpec priSpec = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(base64String));
        return KeyFactory.getInstance("RSA").generatePrivate(priSpec);
    }
}

複製代碼
public static void main(String[] args) throws Exception {
		KeyPair key = RSAUtils.generateRSAKeyPair(960);
		String publicKey = RSAUtils.getBase64Key(key.getPublic());
		String privateKey = RSAUtils.getBase64Key(key.getPrivate());

		System.out.println(publicKey);
		System.out.println(privateKey);

		StringBuilder sb = new StringBuilder();
		sb.append("rank=1&sessionId=")
				.append("0123456789ABCDEF0123456789ABCDEF").append("&ts=")
				.append(System.currentTimeMillis() + 1000000000);

		String en = encode(sb.toString(), key);
		String de = decode(en, key);
		System.out.println("原文:" + sb.toString());
		System.out.println("密文:" + en);
		System.out.println("密文:"+encode(sb.toString(), key));
		System.out.println("解密:" + de);
		
		

	}

	public static String encode(String src, KeyPair key) {
		String hashCode = null;
		try {
			PrivateKey publicKey = (PrivateKey) key.getPrivate();
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(src.getBytes());

			hashCode = new BASE64Encoder().encode(output);
		} catch (Exception e) {

		}
		return hashCode;
	}

	public static String decode(String src, KeyPair key) {
		String returnRes = null;
		try {
			PublicKey publicKey = (PublicKey) key.getPublic();
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(new BASE64Decoder()
					.decodeBuffer(src));
			returnRes = new String(output);
		} catch (Exception e) {

		}
		return returnRes;
	}
複製代碼

持續更新中,能夠關注........ session

javaview.jpg
相關文章
相關標籤/搜索