RSA加解密VS加签与验签

63 阅读8分钟

RSA加解密VS加签与验签

原则:

1) 公钥加密数据

2)私钥进行签名

3)公私钥互加解密密钥。

其实也可以互换,私钥加密,公解解密 。 需要注意的是,我们只是将公钥公开, ps:私钥是可以推出公钥的。如果将私钥公开,那么全套就是明文 。

参考:co63oc.blog.51cto.com/904636/6254…

公钥加密,私钥解密时,因为加入随机数,每次得到的加密信息不固定。

私钥加密,公钥解密时,得到的加密信息固定。

下面引入几个常见的工具类

RSAUtils

 ​
 /**
  * <p>
  * RSA公钥/私钥/签名工具包
  * </p>
  * <p>
  * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
  * </p>
  * <p>
  * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
  * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
  * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
  * </p>
  * 
  * @author IceWee
  * @date 2012-4-26
  * @version 1.0
  */
 public class RSAUtils {
 ​
   /**
    * 加密算法RSA
    */
   public static final String KEY_ALGORITHM = "RSA";
 ​
   /**
    * 签名算法
    */
   // public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
   public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
 ​
   /**
    * 获取公钥的key
    */
   private static final String PUBLIC_KEY = "RSAPublicKey";
 ​
   /**
    * 获取私钥的key
    */
   private static final String PRIVATE_KEY = "RSAPrivateKey";
 ​
   /**
    * RSA最大加密明文大小
    */
   private static final int MAX_ENCRYPT_BLOCK = 117;
 ​
   /**
    * RSA最大解密密文大小
    */
   private static final int MAX_DECRYPT_BLOCK = 128;
 ​
   /**
    * <p>
    * 生成密钥对(公钥和私钥)
    * </p>
    * 
    * @return
    * @throws Exception
    */
   public static Map<String, Object> genKeyPair() throws Exception {
     KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
     keyPairGen.initialize(1024);
     KeyPair keyPair = keyPairGen.generateKeyPair();
     RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
     RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
     Map<String, Object> keyMap = new HashMap<String, Object>(2);
     keyMap.put(PUBLIC_KEY, publicKey);
     keyMap.put(PRIVATE_KEY, privateKey);
     return keyMap;
   }
 ​
   /**
    * 从文件中输入流中加载公钥
    * 
    * @param in
    *            公钥输入流
    * @throws Exception
    *             加载公钥时产生的异常
    */
   public static  RSAPublicKey loadPublicKey(InputStream in) throws Exception {
     try {
       BufferedReader br = new BufferedReader(new InputStreamReader(in));
       String readLine = null;
       StringBuilder sb = new StringBuilder();
       while ((readLine = br.readLine()) != null) {
         if (readLine.charAt(0) == '-') {
           continue;
         } else {
           sb.append(readLine);
           sb.append('\r');
         }
       }
       return loadPublicKey(sb.toString());
     } catch (IOException e) {
       throw new Exception("公钥数据流读取错误");
     } catch (NullPointerException e) {
       throw new Exception("公钥输入流为空");
     }
   }
 ​
   /**
    * 从字符串中加载公钥
    * 
    * @param publicKeyStr
    *            公钥数据字符串
    * @throws Exception
    *             加载公钥时产生的异常
    */
   public  static  RSAPublicKey  loadPublicKey(String publicKeyStr) throws Exception {
     try {
 ​
       byte[] buffer = Base64Utils.decode(publicKeyStr);
       KeyFactory keyFactory = KeyFactory.getInstance("RSA");
       X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
 ​
       return (RSAPublicKey) keyFactory.generatePublic(keySpec);
 ​
     } catch (NoSuchAlgorithmException e) {
       throw new Exception("无此算法");
     } catch (InvalidKeySpecException e) {
       throw new Exception("公钥非法");
     } catch (IOException e) {
       throw new Exception("公钥数据内容读取错误");
     } catch (NullPointerException e) {
       throw new Exception("公钥数据为空");
     }
   }
 ​
   /**
    * 从文件中加载私钥
    * 
    * @param keyFileName
    *            私钥文件名
    * @return 是否成功
    * @throws Exception
    */
   public static RSAPrivateKey  loadPrivateKey(InputStream in) throws Exception {
     try {
       BufferedReader br = new BufferedReader(new InputStreamReader(in));
       String readLine = null;
       StringBuilder sb = new StringBuilder();
       while ((readLine = br.readLine()) != null) {
         if (readLine.charAt(0) == '-') {
           continue;
         } else {
           sb.append(readLine);
           sb.append('\r');
         }
       }
       return loadPrivateKey(sb.toString());
     } catch (IOException e) {
       throw new Exception("私钥数据读取错误");
     } catch (NullPointerException e) {
       throw new Exception("私钥输入流为空");
     }
   }
 ​
   public static  RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
     try {
 ​
       byte[] buffer = Base64Utils.decode(privateKeyStr);
       PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
       KeyFactory keyFactory = KeyFactory.getInstance("RSA");
       return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
     } catch (NoSuchAlgorithmException e) {
       throw new Exception("无此算法");
     } catch (InvalidKeySpecException e) {
       throw new Exception("私钥非法");
     } catch (IOException e) {
       throw new Exception("私钥数据内容读取错误");
     } catch (NullPointerException e) {
       throw new Exception("私钥数据为空");
     }
   }
 ​
   /**
    * <p>
    * 用私钥对信息生成数字签名
    * </p>
    * 
    * @param data
    *            已加密数据
    * @param privateKey
    *            私钥(BASE64编码)
    * 
    * @return
    * @throws Exception
    */
   public static String sign(byte[] data, String privateKey) throws Exception {
     byte[] keyBytes = Base64Utils.decode(privateKey);
     PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
     Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
     signature.initSign(privateK);
     signature.update(data);
     return Base64Utils.encode(signature.sign());
   }
 ​
   /**
    * <p>
    * 校验数字签名
    * </p>
    * 
    * @param data
    *            已加密数据
    * @param publicKey
    *            公钥(BASE64编码)
    * @param sign
    *            数字签名
    * 
    * @return
    * @throws Exception
    * 
    */
   public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
     byte[] keyBytes = Base64Utils.decode(publicKey);
     X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     PublicKey publicK = keyFactory.generatePublic(keySpec);
     Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
     signature.initVerify(publicK);
     signature.update(data);
     return signature.verify(Base64Utils.decode(sign));
   }
 ​
   /**
    * <P>
    * 私钥解密
    * </p>
    * 
    * @param encryptedData
    *            已加密数据
    * @param privateKey
    *            私钥(BASE64编码)
    * @return
    * @throws Exception
    */
   public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
     byte[] keyBytes = Base64Utils.decode(privateKey);
     PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
     Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
     cipher.init(Cipher.DECRYPT_MODE, privateK);
     int inputLen = encryptedData.length;
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     int offSet = 0;
     byte[] cache;
     int i = 0;
     // 对数据分段解密
     while (inputLen - offSet > 0) {
       if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
         cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
       } else {
         cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
       }
       out.write(cache, 0, cache.length);
       i++;
       offSet = i * MAX_DECRYPT_BLOCK;
     }
     byte[] decryptedData = out.toByteArray();
     out.close();
     return decryptedData;
   }
 ​
   /**
    * <p>
    * 公钥解密
    * </p>
    * 
    * @param encryptedData
    *            已加密数据
    * @param publicKey
    *            公钥(BASE64编码)
    * @return
    * @throws Exception
    */
   public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
     byte[] keyBytes = Base64Utils.decode(publicKey);
     X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     Key publicK = keyFactory.generatePublic(x509KeySpec);
     Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
     cipher.init(Cipher.DECRYPT_MODE, publicK);
     int inputLen = encryptedData.length;
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     int offSet = 0;
     byte[] cache;
     int i = 0;
     // 对数据分段解密
     while (inputLen - offSet > 0) {
       if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
         cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
       } else {
         cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
       }
       out.write(cache, 0, cache.length);
       i++;
       offSet = i * MAX_DECRYPT_BLOCK;
     }
     byte[] decryptedData = out.toByteArray();
     out.close();
     return decryptedData;
   }
 ​
   /**
    * <p>
    * 公钥加密
    * </p>
    * 
    * @param data
    *            源数据
    * @param publicKey
    *            公钥(BASE64编码)
    * @return
    * @throws Exception
    */
   public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
     byte[] keyBytes = Base64Utils.decode(publicKey);
     X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     Key publicK = keyFactory.generatePublic(x509KeySpec);
     // 对数据加密
     Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
     cipher.init(Cipher.ENCRYPT_MODE, publicK);
     int inputLen = data.length;
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     int offSet = 0;
     byte[] cache;
     int i = 0;
     // 对数据分段加密
     while (inputLen - offSet > 0) {
       if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
         cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
       } else {
         cache = cipher.doFinal(data, offSet, inputLen - offSet);
       }
       out.write(cache, 0, cache.length);
       i++;
       offSet = i * MAX_ENCRYPT_BLOCK;
     }
     byte[] encryptedData = out.toByteArray();
     out.close();
     return encryptedData;
   }
 ​
   /**
    * <p>
    * 私钥加密
    * </p>
    * 
    * @param data
    *            源数据
    * @param privateKey
    *            私钥(BASE64编码)
    * @return
    * @throws Exception
    */
   public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
     byte[] keyBytes = Base64Utils.decode(privateKey);
     PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
     KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
     Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
     Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
     cipher.init(Cipher.ENCRYPT_MODE, privateK);
     int inputLen = data.length;
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     int offSet = 0;
     byte[] cache;
     int i = 0;
     // 对数据分段加密
     while (inputLen - offSet > 0) {
       if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
         cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
       } else {
         cache = cipher.doFinal(data, offSet, inputLen - offSet);
       }
       out.write(cache, 0, cache.length);
       i++;
       offSet = i * MAX_ENCRYPT_BLOCK;
     }
     byte[] encryptedData = out.toByteArray();
     out.close();
     return encryptedData;
   }
 ​
   /**
    * <p>
    * 获取私钥
    * </p>
    * 
    * @param keyMap
    *            密钥对
    * @return
    * @throws Exception
    */
   public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
     Key key = (Key) keyMap.get(PRIVATE_KEY);
     return Base64Utils.encode(key.getEncoded());
   }
 ​
   /**
    * <p>
    * 获取公钥
    * </p>
    * 
    * @param keyMap
    *            密钥对
    * @return
    * @throws Exception
    */
   public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
     Key key = (Key) keyMap.get(PUBLIC_KEY);
     return Base64Utils.encode(key.getEncoded());
   }
 ​
 }
 ​
 public class Base64Utils {
  
     /**
      * 文件读取缓冲区大小
      */
     private static final int CACHE_SIZE = 1024;
      
     /**
      * <p>
      * BASE64字符串解码为二进制数据
      * </p>
      * 
      * @param base64
      * @return
      * @throws Exception
      */
     public static byte[] decode(String base64) throws Exception {
         return Base64.decode(base64.getBytes());
     }
      
     /**
      * <p>
      * 二进制数据编码为BASE64字符串
      * </p>
      * 
      * @param bytes
      * @return
      * @throws Exception
      */
     public static String encode(byte[] bytes) throws Exception {
         return new String(Base64.encode(bytes));
     }
      
     /**
      * <p>
      * 将文件编码为BASE64字符串
      * </p>
      * <p>
      * 大文件慎用,可能会导致内存溢出
      * </p>
      * 
      * @param filePath 文件绝对路径
      * @return
      * @throws Exception
      */
     public static String encodeFile(String filePath) throws Exception {
         byte[] bytes = fileToByte(filePath);
         return encode(bytes);
     }
      
     /**
      * <p>
      * BASE64字符串转回文件
      * </p>
      * 
      * @param filePath 文件绝对路径
      * @param base64 编码字符串
      * @throws Exception
      */
     public static void decodeToFile(String filePath, String base64) throws Exception {
         byte[] bytes = decode(base64);
         byteArrayToFile(bytes, filePath);
     }
      
     /**
      * <p>
      * 文件转换为二进制数组
      * </p>
      * 
      * @param filePath 文件路径
      * @return
      * @throws Exception
      */
     public static byte[] fileToByte(String filePath) throws Exception {
         byte[] data = new byte[0];
         File file = new File(filePath);
         if (file.exists()) {
             FileInputStream in = new FileInputStream(file);
             ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
             byte[] cache = new byte[CACHE_SIZE];
             int nRead = 0;
             while ((nRead = in.read(cache)) != -1) {
                 out.write(cache, 0, nRead);
                 out.flush();
             }
             out.close();
             in.close();
             data = out.toByteArray();
          }
         return data;
     }
      
     /**
      * <p>
      * 二进制数据写文件
      * </p>
      * 
      * @param bytes 二进制数据
      * @param filePath 文件生成目录
      */
     public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
         InputStream in = new ByteArrayInputStream(bytes);   
         File destFile = new File(filePath);
         if (!destFile.getParentFile().exists()) {
             destFile.getParentFile().mkdirs();
         }
         destFile.createNewFile();
         OutputStream out = new FileOutputStream(destFile);
         byte[] cache = new byte[CACHE_SIZE];
         int nRead = 0;
         while ((nRead = in.read(cache)) != -1) {   
             out.write(cache, 0, nRead);
             out.flush();
         }
         out.close();
         in.close();
     }
      
      
 }

测试demo

 ​
 public class RSATester {
 ​
   static String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5wonDXZhItfDmRUlWQCFwjYL/SSb5PYU7x4mtKPzopnUamlDXTVcSbUdFGRr4K6ANNPs3UsviraN/QWmI3vguzd/xWlpIbGnkyAOzS4hErf+cQDHSW2/TAf1MqI0I6p6tjfLpp4jXJj0OcEeeVR1oVXkY3I8vuOW1v0wwByAkpwIDAQAB";
   static String privateKey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALnCicNdmEi18OZFSVZAIXCNgv9JJvk9hTvHia0o/OimdRqaUNdNVxJtR0UZGvgroA00+zdSy+Kto39BaYje+C7N3/FaWkhsaeTIA7NLiESt/5xAMdJbb9MB/UyojQjqnq2N8umniNcmPQ5wR55VHWhVeRjcjy+45bW/TDAHICSnAgMBAAECgYBkO9+gRomcemhBqJNY8gPZOtK7s5pPFO4mgpX8lMhbNS6tKyWB956LN+IkG9bcoJWdasA/avLPHsjBKueqTj32AAu0lNCXnJBtFHXY2IAIpSNjOYP2HEsq6FWO9V4eznOcg588Hb4udi5F+Sq8E5werTx0q7PZKou8X31apXgiWQJBAN2y1FGjeGeskwPYpfqIv4xF+u4EPTkGWMNOD3uUqJNzPqg5ETYYXKlfQu5LnNMV0LHUbGl0f0hD70Hv+Xbz8RUCQQDWgDq7lEG7FmwPVVdbQceJJOfCWSLl3liFYRUXvLAVXL1aq3314OMp/m93HtbUj/oVJVJ8pEsAWkKEcS8jFFXLAkAEfS19ZbD3cHAdoNJji0dNoNEe5qkSsYU0ly0LFIyBR9EZ+OXXUZD2wP4K8y7+uy9ZmnKDhB9bqDx8+k3z0aatAkEAmIEUwPbYgO6hJ4mykTREbJJroHcFY89gunvapkTGIHoOOp/A74bTm7DFiTjI3tn6oPwnGG0q0fZaYpWiQNudXwJAfWhC3gaFpFYXZdg9+ysB3i7gIlpWd6CELkUV6YIEmW9V8B9URmDPBMLbjRYpt8Q4vGaPPunteeLfIl3Ld0rXUA==";
 ​
   static {
     try {
 //      Map<String, Object> keyMap = RSAUtils.genKeyPair();
 //      publicKey = RSAUtils.getPublicKey(keyMap);
 //      privateKey = RSAUtils.getPrivateKey(keyMap);
 //      System.out.println("公钥: \n\r" + publicKey);
 //      System.out.println("私钥: \n\r" + privateKey);
 //      
 //      publicKey= RSAUtils.loadPublicKey("");
 //      privateKey=RSAUtils.loadPrivateKey("");
 //      
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 ​
   public static void main(String[] args) throws Exception {
     //test();
     
     testSign();
   }
 ​
   static void test() throws Exception {
     System.out.println("公钥加密——私钥解密");
     String source = "123456";
     System.out.println("\r加密前文字:" + source);
     
     byte[] data = source.getBytes();
     byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey);
     System.out.println("加密后文字:" + Base64Utils.encode(encodedData));
     
     
     byte[] decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey);
     String target = new String(decodedData);
     System.out.println("解密后文字: " + target);
 ​
   }
 ​
   static void testSign() throws Exception {
     System.out.println("私钥加密——公钥解密");
     String source = "9876543";
     System.out.println("原文字:" + source);
     
     byte[] data = source.getBytes();
     byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);
     System.out.println("加密后:" + Base64Utils.encode(encodedData));
     
     byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);
     String target = new String(decodedData);
     System.out.println("解密后: " + target);
 ​
     System.out.println("私钥签名——公钥验证签名");
     String sign = RSAUtils.sign(data, privateKey);
     System.out.println("签名:" + sign);
     boolean status = RSAUtils.verify(data, publicKey, sign);
     System.out.println("验证结果:" + status);
   }
 ​
 }

结果

 私钥加密——公钥解密
 原文字:9876543
 加密后:BuC21nX9C1QaW0M16b+Hxn54lnekLQHD1fNcaQgK7MvHNuQKNiwUQilYsi2vALm/yBEnIsR0SreXWYFFogq75SsbI/4fxF2tFz16JIR5+z5Wdm/uE0AFfQDqVMX2I0aJSKzTRhRmCJgE7+n0ALon/b2WLQfHguxGF8X9WjnqnXM=
 解密后: 9876543
 私钥签名——公钥验证签名
 签名:aO9kIu3T4Q/irSxloqlSw+5Mm7TgNooqqkGFEuIyiFZ+KC2P8RFXnzhr2laggRpWVEEQ4cNysqoSE8uDnc3+Me/Ef4YHjK0F30sas1U8VsLuuBghptB406PZc0aStI7ZMp63AokNN+8FoVQ87ObYzRhkXOoKEy+W4gFjcT/usEg=
 验证结果:true