RSA加密解密與加簽驗籤

  RSA公鑰加密算法是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一塊兒提出的。1987年7月首次在美國公佈,當時他們三人都在麻省理工學院工做實習。RSA就是他們三人姓氏開頭字母拼在一塊兒組成的。java

  RSA是目前最有影響力和最經常使用的公鑰加密算法,它可以抵抗到目前爲止已知的絕大多數密碼攻擊,已被ISO推薦爲公鑰數據加密標準。算法

  RSA公開密鑰密碼體制。所謂的公開密鑰密碼體制就是使用不一樣的加密密鑰與解密密鑰,是一種「由已知加密密鑰推導出解密密鑰在計算上是不可行的」密碼體制。服務器

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

  基於這種理論,1978年出現了著名的RSA算法,它一般是先生成一對RSA 密鑰,其中之一是保密密鑰,由用戶保存;另外一個爲公開密鑰,可對外公開,甚至能夠在網絡服務器中註冊。爲提升保密強度,RSA密鑰至少爲500位長,通常推薦使用1024位。這就使加密的計算量很大。app

  RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操做。RSA是被研究得最普遍的公鑰算法,從提出到現今的三十多年裏,經歷了各類攻擊的考驗,逐漸爲人們接受,截止2017年被廣泛認爲是最優秀的公鑰方案之一。工具

  SET(Secure Electronic Transaction)協議中要求CA採用2048bits長的密鑰,其餘實體使用1024比特的密鑰。RSA密鑰長度隨着保密級別提升,增長很快。ui

  RSA算法是一種非對稱密碼算法,所謂非對稱,就是指該算法須要一對密鑰,使用其中一個加密,則須要用另外一個才能解密。編碼

  咱們接下來看下Java中如何實現RSA加密解密與加簽驗籤。咱們先來看RSA加密解密。  加密

 1 import javax.crypto.BadPaddingException;  2 import javax.crypto.Cipher;  3 import javax.crypto.IllegalBlockSizeException;  4 import javax.crypto.NoSuchPaddingException;  5 import java.security.*;  6 import java.util.Base64;  7 /**  8  * RSA加密解密操做步驟  9  */
10 public class Test1 { 11     public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { 12         //先給出一個待加密的字符串
13         String data="青青子衿,悠悠我心。但爲君故,沉吟至今。"; 14         //1.構建公私鑰匙對
15         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 16         KeyPair keyPair = keyPairGenerator.generateKeyPair(); 17         //2.獲取鑰匙對中的公鑰
18         PublicKey publicKey = keyPair.getPublic(); 19         //3.獲取鑰匙對中的私鑰
20         PrivateKey privateKey = keyPair.getPrivate(); 21         //4.對待加密的數據進行加密
22         Cipher cipher = Cipher.getInstance("RSA"); 23  cipher.init(Cipher.ENCRYPT_MODE,publicKey); 24         byte[] bytesEncrypt = cipher.doFinal(data.getBytes());//產生的是亂碼,須要用Base64進行轉碼 25         //5.Base64編碼
26         byte[] encodeBase64 = Base64.getEncoder().encode(bytesEncrypt); 27         System.out.println("加密後的數據:"+new String(encodeBase64)); 28         //6.在解密時,先對用Base64編碼的信息進行解碼
29         byte[] bytesDecode = Base64.getDecoder().decode(encodeBase64); 30         //7.解密
31         Cipher cipher2=Cipher.getInstance("RSA"); 32  cipher2.init(Cipher.DECRYPT_MODE,privateKey); 33         byte[] bytesDecrypt = cipher2.doFinal(bytesDecode); 34         System.out.println("解密後的數據:"+new String(bytesDecrypt)); 35  } 36 }

  公鑰和私鑰自己存儲的信息是亂碼,在實際使用中,咱們還能夠經過Base64將這些亂碼編碼爲可識別的ASCII碼,而後將公鑰和私鑰信息持久化存儲到文件中,在之後須要使用時,能夠從文件中讀取公鑰和私鑰信息。爲此,咱們能夠寫一個RSA的工具類,從一個儲存公鑰和私鑰信息的文件裏讀取公鑰和私鑰信息,而後定義獲取公鑰和私鑰的方法,以及加密和解密數據的方法。首先,咱們提供一對公私鑰信息,假定公鑰信息儲存在一個名稱爲rsa_public_key.pem的文件裏,信息以下:spa

-----BEGIN RSA PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDY90KtriCa4KjNe3mgrGGbDB95 8A2byBKf+wOmPmOopP3gGeg7+DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1J Z7JjopYVZW6JKqA2ImyneeUEK748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UF lT0EhL6JA8ULKFoiHwIDAQAB -----BEGIN RSA PUBLIC KEY-----

  假定私鑰信息儲存在一個名稱爲rsa_private_key.pem的文件裏,信息以下::

-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDY90KtriCa4KjNe3mgrGGbDB958A2byBKf+wOmPmOopP3gGeg7 +DFAPNYCC+tL8h2bpUI3IPKOm2Hon8kM/p628i1JZ7JjopYVZW6JKqA2ImyneeUE K748FXwXTRAAMCTqQG/7a178BGawTdHi6hk+M6UFlT0EhL6JA8ULKFoiHwIDAQAB AoGBAIJFhF2wLZeQyQoH13Gnzzs/Pi8C+cjNipFQMFLDJyd9WYoTRCOt1DST0pOM AI2rJCfuRCHBwKHrnhAE0LzirPxkmvyHTIBXIoz3fHiSkIKkUVG04BcgTYpNKWPB ISlzdhSaw7CnmJjTthTrD5LLPtpqUl350lUYFEHVNR6Ys9JRAkEA9JUEVxzSvQkV V6hxhbvlxl0mATbPfiNKDBTPdr48dyYdgluAoGfAPf9rmgoCpdEd2hZBIfdy7xdL LvP7ztb/rQJBAOMYNC/lZLz9A9cDJ5bibrJnmyRG0SAGAzu4ffYdBoGb0kRRKzTe 5jxfRnbiUPQU4GQXhADfikGn2ogRqbtDsnsCQQCJdp+D3n1LJanLJK75PQv9myjb EdU4zdi2RZP85xrQ1KlNNORsQyO3NLFjWDD4xTmD83IUByGf43WsJBDoxcnZAkA3 i84IARX42/I6fz0JvOzSmmDqKKAyMwZLbz7wGf1jalet+iSVVAgAsFUt8wFWEl0o XlAdXpAUqxfavGdFtLNNAkABS576xgLcLmyw51f9hoM9RiamLn+WNzoA5TLOZjGI dZZnX/A8SoFYGoJoN1O0hp5DxDdl+gjW/mH51+gliEIB -----END RSA PRIVATE KEY-----

  接下來,咱們寫一個RSAUtil工具類,代碼以下:  

 1 import javax.crypto.BadPaddingException;  2 import javax.crypto.Cipher;  3 import javax.crypto.IllegalBlockSizeException;  4 import javax.crypto.NoSuchPaddingException;  5 import java.io.BufferedReader;  6 import java.io.FileReader;  7 import java.io.IOException;  8 import java.security.*;  9 import java.security.spec.InvalidKeySpecException;  10 import java.security.spec.PKCS8EncodedKeySpec;  11 import java.security.spec.X509EncodedKeySpec;  12 import java.util.Base64;  13 /**  14  * 工具類  15  */
 16 public class RSAUtil {  17     /*
 18  讀取祕鑰數據  19      */
 20     public static byte[] readKeyDatas(String keyFilePath){  21         BufferedReader bufferedReader=null;  22         try{  23             bufferedReader = new BufferedReader(new FileReader(keyFilePath));  24             String str=null;  25             StringBuilder stringBuilder=new StringBuilder();  26             while ((str=bufferedReader.readLine())!=null){  27                 if(str.contains("---")){  28                     continue;  29  }  30  stringBuilder.append(str);  31  }  32             return stringBuilder.toString().getBytes();  33         }catch (IOException e) {  34  e.printStackTrace();  35         }finally {  36             try {  37  bufferedReader.close();  38             } catch (IOException e) {  39  e.printStackTrace();  40  }  41  }  42         return null;  43  }  44     /*
 45  生成公鑰  46      */
 47     public static PublicKey getPublicKey(String publicKeyPath){  48         //1.讀取公鑰文件,獲取公鑰數據
 49         byte[] bytesPublicBase64 = readKeyDatas(publicKeyPath);  50         //2.對讀取回來的數據進行Base64解碼
 51         byte[] bytesPublic = Base64.getDecoder().decode(bytesPublicBase64);  52         //3.把解碼後的數據,從新封裝成一個PublicKey對象
 53         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytesPublic);  54         KeyFactory keyFactory=null;  55         try {  56             keyFactory = KeyFactory.getInstance("RSA");  57             PublicKey publicKey = keyFactory.generatePublic(keySpec);  58             return publicKey;  59         } catch (NoSuchAlgorithmException e) {  60  e.printStackTrace();  61         } catch (InvalidKeySpecException e) {  62  e.printStackTrace();  63  }  64         return null;  65  }  66     /*
 67  生成私鑰  68      */
 69     public static PrivateKey getPrivateKey(String privateKeyPath){  70         //1.讀取私鑰文件,獲取私鑰數據
 71         byte[] bytesPrivateBase64 = readKeyDatas(privateKeyPath);  72         //2.對讀取回來的數據進行Base64解碼
 73         byte[] bytesPrivate = Base64.getDecoder().decode(bytesPrivateBase64);  74         //3.把解碼後的數據,從新封裝成一個PrivateKey對象
 75         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytesPrivate);  76         KeyFactory keyFactory=null;  77         try {  78             keyFactory = KeyFactory.getInstance("RSA");  79             PrivateKey privateKey = keyFactory.generatePrivate(keySpec);  80             return privateKey;  81         } catch (NoSuchAlgorithmException e) {  82  e.printStackTrace();  83         } catch (InvalidKeySpecException e) {  84  e.printStackTrace();  85  }  86         return null;  87  }  88     /*
 89  加密數據  90      */
 91     public static String encodeData(PublicKey publicKey,String originData){  92         try {  93             Cipher cipher = Cipher.getInstance("RSA");  94  cipher.init(Cipher.ENCRYPT_MODE,publicKey);  95             byte[] bytesEncrypt = cipher.doFinal(originData.getBytes());  96             //Base64編碼
 97             byte[] bytesEncryptBase64 = Base64.getEncoder().encode(bytesEncrypt);  98             return new String(bytesEncryptBase64);  99         } catch (NoSuchAlgorithmException e) { 100  e.printStackTrace(); 101         } catch (NoSuchPaddingException e) { 102  e.printStackTrace(); 103         } catch (InvalidKeyException e) { 104  e.printStackTrace(); 105         } catch (BadPaddingException e) { 106  e.printStackTrace(); 107         } catch (IllegalBlockSizeException e) { 108  e.printStackTrace(); 109  } 110         return null; 111  } 112     /*
113  解密數據 114      */
115     public static String decodeData(PrivateKey privateKey,String encodeData){ 116         try { 117             //Base64解碼
118             byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData); 119             //加密
120             Cipher cipher = Cipher.getInstance("RSA"); 121  cipher.init(Cipher.DECRYPT_MODE,privateKey); 122             byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt); 123             return new String(bytesDecrypt); 124         } catch (NoSuchAlgorithmException e) { 125  e.printStackTrace(); 126         } catch (NoSuchPaddingException e) { 127  e.printStackTrace(); 128         } catch (InvalidKeyException e) { 129  e.printStackTrace(); 130         } catch (BadPaddingException e) { 131  e.printStackTrace(); 132         } catch (IllegalBlockSizeException e) { 133  e.printStackTrace(); 134  } 135         return null; 136  } 137 }

  這樣的話,之後須要使用公鑰和私鑰,以及加密解密時,調用上述工具類中的相應方法便可。

  最後,咱們再來看用RSA如何對數據進行加簽驗籤,具體代碼以下:

 1 import java.io.UnsupportedEncodingException;  2 import java.security.*;  3 /**  4  * 加簽 驗籤 簽名驗證:驗證數據的合法來源 即驗證數據來源的合法性  5  * 加簽:私鑰  6  * 驗籤:公鑰  7  */
 8 public class Test2 {  9     private static String privateKeyPath="儲存私鑰信息的文件路徑"; 10     private static String publicKeyPath="儲存公鑰信息的文件路徑"; 11     public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException { 12         String data="驗證該數據是否爲合法的服務器發送"; 13         /** 14  * 加簽過程 15          */
16         PrivateKey privateKey = RSAUtil.getPrivateKey(privateKeyPath); 17         Signature signature = Signature.getInstance("Sha1WithRSA"); 18  signature.initSign(privateKey); 19         signature.update(data.getBytes("UTF-8")); 20         byte[] signed = signature.sign(); 21         /** 22  * 驗簽過程 23          */
24         PublicKey publicKey = RSAUtil.getPublicKey(publicKeyPath); 25         Signature signature2 = Signature.getInstance("Sha1WithRSA"); 26  signature2.initVerify(publicKey); 27         signature2.update(data.getBytes("UTF-8")); 28         boolean verify = signature2.verify(signed); 29         System.out.println("驗簽結果:"+verify); 30  } 31 }
相關文章
相關標籤/搜索