RSA加密解密样例

原文地址:RSA加密解密样例

场景:当未启用HTTPS时,用户的登录密码,以及当用户修改密码时,密码在网络中需要加密传输。

一、交互逻辑

  上图中,前端部分运行在浏览器上,所以需要用JavaScript来加密需要传输的密码,后端部分使用Java来实现。

二、前端部分

  前端部分的加密,选择jsencrypt来实现,代码如下:

    //用户修改密码样例
    $("#ModifyPasswordBtn").bind("click",function(){
      if($("#ModifyPasswordForm").valid()){
          //这里的RSA是使用的模块化加载的入口
          var encrypt = new RSA.JSEncrypt();
          //KEY为公钥
          encrypt.setPublicKey(KEY);
          var data = {
              userUuid:USER.userUuid,
              oldPassword:encrypt.encrypt($('#oldPassword').val()),
              newPassword:encrypt.encrypt($('#newPassword').val())
          };
          $.ajax({
              url:getServer()+"your action",
              type:"post",
              data:data,
              success:function(data){
                  var status = data.modifyStatus;
                  if(status==1){
                      Util.alert("修改成功");
                  }else if(status==0){
                      Util.alert("原密码不正确.");
                  }else{
                      Util.alert("修改失败");
                  }
              }
          });
      }

三、后端部分

  后端部分使用Java来实现

工具类
package com.share.util;

import java.security.InvalidKeyException;  
import java.security.KeyFactory;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.NoSuchAlgorithmException;  
import java.security.SecureRandom;  

import java.security.interfaces.RSAPrivateKey;  
import java.security.interfaces.RSAPublicKey;  
import java.security.spec.InvalidKeySpecException;  
import java.security.spec.PKCS8EncodedKeySpec;  
import java.security.spec.X509EncodedKeySpec;  

import java.util.HashMap;

import javax.crypto.BadPaddingException;  
import javax.crypto.Cipher;  
import javax.crypto.IllegalBlockSizeException;  
import javax.crypto.NoSuchPaddingException;  


public class RSATools {  

    /**
     * 生成RAS公钥与私钥字符串,直接返回
     * @return
     */
    public static HashMap<String,String> getKeys(){
        HashMap<String,String> map = new HashMap<String,String>();
         KeyPairGenerator keyPairGen = null;  
         try {  
             keyPairGen = KeyPairGenerator.getInstance("RSA");  
         } catch (NoSuchAlgorithmException e) {  
             // TODO Auto-generated catch block  
             e.printStackTrace();  
         }  
         // 初始化密钥对生成器,密钥大小为96-1024位  
         keyPairGen.initialize(1024,new SecureRandom());  
         // 生成一个密钥对,保存在keyPair中  
         KeyPair keyPair = keyPairGen.generateKeyPair();  
         //得到公钥字符串  
         String publicKey   = base64ToStr(keyPair.getPublic().getEncoded());  
         //得到私钥字符串  
         String privateKey  = base64ToStr(keyPair.getPrivate().getEncoded());  
         map.put("publicKey", publicKey);
         map.put("privateKey", privateKey);
        return map;
    }

    /**
     * 从字符串中加载公钥
     * @param publicKeyStr  公钥字符串
     * @return
     * @throws Exception
     */
    public static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {  
        try {  
            byte[] buffer = javax.xml.bind.DatatypeConverter.parseBase64Binary(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 (NullPointerException e) {  
            throw new Exception("公钥数据为空");  
        }  
    }  

    /**
     * 从字符串中加载私钥
     * @param privateKeyStr     私钥字符串
     * @return
     * @throws Exception
     */
    public static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {  
        try {  
            byte[] buffer = javax.xml.bind.DatatypeConverter.parseBase64Binary(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 (NullPointerException e) {  
            throw new Exception("私钥数据为空");  
        }  
    }  

    /**
     * 公钥加密过程
     * @param publicKey      公钥
     * @param plainTextData  明文数据
     * @return
     * @throws Exception     加密过程中的异常信息
     */  
    public static String encrypt(RSAPublicKey publicKey, byte[] plainTextData)throws Exception {  
        if (publicKey == null) {  
            throw new Exception("加密公钥为空, 请设置");  
        }  
        Cipher cipher = null;  
        try {  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
            byte[] output = cipher.doFinal(plainTextData);  
            return base64ToStr(output);  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("无此加密算法");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("加密公钥非法,请检查");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("明文长度非法");  
        } catch (BadPaddingException e) {  
            throw new Exception("明文数据已损坏");  
        }  
    }  

    /**
     * 私钥加密过程
     *  
     * @param privateKey       私钥
     * @param plainTextData    明文数据
     * @return
     * @throws Exception       加密过程中的异常信息
     */  
    public static String encrypt(RSAPrivateKey privateKey, byte[] plainTextData) throws Exception {  
        if (privateKey == null) {  
            throw new Exception("加密私钥为空, 请设置");  
        }  
        Cipher cipher = null;  
        try {  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);  
            byte[] output = cipher.doFinal(plainTextData);  
            return base64ToStr(output);  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("无此加密算法");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("加密私钥非法,请检查");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("明文长度非法");  
        } catch (BadPaddingException e) {  
            throw new Exception("明文数据已损坏");  
        }  
    }  

    /**
     * 私钥解密过程
     *  
     * @param privateKey   私钥
     * @param cipherData   密文数据
     * @return                明文
     * @throws Exception   解密过程中的异常信息
     */  
    public static String decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {  
        if (privateKey == null) {  
            throw new Exception("解密私钥为空, 请设置");  
        }  
        Cipher cipher = null;  
        try {  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.DECRYPT_MODE, privateKey);  
            byte[] output = cipher.doFinal(cipherData);  
            return new String(output);
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("无此解密算法");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("解密私钥非法,请检查");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("密文长度非法");  
        } catch (BadPaddingException e) {  
            throw new Exception("密文数据已损坏");  
        }  
    }  

    /**
     * 公钥解密过程
     * @param publicKey     公钥
     * @param cipherData    密文数据
     * @return              明文
     * @throws Exception    解密过程中的异常信息
     */  
    public static String decrypt(RSAPublicKey publicKey, byte[] cipherData) throws Exception {  
        if (publicKey == null) {  
            throw new Exception("解密公钥为空, 请设置");  
        }  
        Cipher cipher = null;  
        try {  
            // 使用默认RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.DECRYPT_MODE, publicKey);  
            byte[] output = cipher.doFinal(cipherData);  
            return new String(output);
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("无此解密算法");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("解密公钥非法,请检查");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("密文长度非法");  
        } catch (BadPaddingException e) {  
            throw new Exception("密文数据已损坏");  
        }  
    }

    public static String base64ToStr(byte[] b){
        return javax.xml.bind.DatatypeConverter.printBase64Binary(b);
    }

    public static byte[] strToBase64(String str){
        return javax.xml.bind.DatatypeConverter.parseBase64Binary(str);
    }
}  
生成公钥/私钥

  在第一次请求时生成公钥与私钥,并放到当前线程上。返回公钥给客户端。

      HashMap<String, String> map = RSATools.getKeys();
      session.setAttribute("PD_CurrentRSAKey", map);
私钥解密
      //从session上拿到上次生成的密钥
      HashMap<String, String> map   = (HashMap<String, String>) session.getAttribute("PD_CurrentRSAKey");
      RSAPrivateKey privateKey      = RSATools.loadPrivateKey(map.get("privateKey"));
      //使用私钥解密传输过来的密码
      String userUuid     = request.getParameter("userUuid");
      String oldPassword  = RSATools.decrypt(privateKey, RSATools.strToBase64(request.getParameter("oldPassword")));
      String newPassword  = RSATools.decrypt(privateKey, RSATools.strToBase64(request.getParameter("newPassword")));

四、可运行的样例

  后续提供github地址

My Blog: http://muchstudy.com

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值