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 }