RSA前台加密后台解密

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27063119/article/details/74279754
RSA-前台加密 后台解密

一.对称与非对称加密

1.对称加密

    对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种方法在密码学中叫做对称加密算法。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。

2.非对称加密

    非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。


二.使用情景说明
    由于业务的需要,用户提交的数据需要在用户端进行加密,我们的系统是web形式,所以需要在网页中对用户填写的数据进行加密传输至服务器端,最简单的方式采用对称加密方式,但是不安全,因为加密解密密码一致,在传输过程中密码存在被截取的可能性,于是决定使用非对称加密方式,主要实现思路为:服务器会自动产生公钥-私钥对,用户填写的数据采用公钥加密,加密后的数据传输至服务器端时,在必要时使用对应的私钥进行解密。公钥暴露向客户端,私钥在服务器端,因此整个加密解密的过程是安全可靠的。
    这篇文章主要介绍整个加密解密实现过程,采用最具安全性的非对称加密方式-RSA。

三.具体实现-demo
    由于代码不可泄露因素,这里放上demo案例,可以实现整个加密解密过程,并支持中文加密解密,两种存放密钥对方式
    需要下载jar包:
bcprov-jdk14-145.jar(必要)
commons-codec-1.9.jar
commons-io-2.0.1.jar
commons-lang3-3.1.jar
gson-2.3.1.jar  (不必要)

前台加密借用了js
Barrett.js
BigInt.js
RSA.js(本项目对此文件进行了修改,源文件直接在本项目中使用会出现问题)

下载地址为:http://www.ohdave.com/rsa/

    
整个工程目录如下图所示:




1.后台RSA工具类代码:

package cn.nuohy.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
 
import javax.crypto.Cipher;
 
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
/**
 * RSA 加解密  工具类
 * @author yangnuo
 * 创建时间:2017年7月3日
 */
public class RSAUtil {
 
        /** 算法名称 */
        private static final String ALGORITHOM = "RSA";
         
        /**保存生成的密钥对的文件名称。 */
        private static final String RSA_PAIR_FILENAME = "/_RSA_ENCRYPTION.txt";
         
        /** 密钥大小 */
        private static final int KEY_SIZE = 1024;
         
        /** 默认的安全服务提供者 */
        private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
 
        private static KeyPairGenerator keyPairGen = null;
         
        private static KeyFactory keyFactory = null;
         
        /** 缓存的密钥对。 */
        private static KeyPair oneKeyPair = null;
 
        private static File rsaPairFile = null;
 
        static {
            try {
                keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
                keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            } catch (NoSuchAlgorithmException ex) {
            }
            rsaPairFile = new File(getRSAPairFilePath());
        }
 
        private RSAUtil() { }
 
        /**
         * 生成并返回RSA密钥对。
         */
        private static synchronized KeyPair generateKeyPair() {
            try {
                keyPairGen.initialize(KEY_SIZE, new SecureRandom());
                oneKeyPair = keyPairGen.generateKeyPair();
                saveKeyPair(oneKeyPair);
                return oneKeyPair;
            } catch (InvalidParameterException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
 
        /**
         * 返回生成/读取的密钥对文件的路径。
         */
        private static String getRSAPairFilePath() {
            String urlPath = RSAUtil.class.getResource("/").getPath();
            return (new File(urlPath).getParent() + RSA_PAIR_FILENAME);
        }
 
        /**
         * 若需要创建新的密钥对文件,则返回 {@code true},否则 {@code false}。
         */
        private static boolean isCreateKeyPairFile() {
            // 是否创建新的密钥对文件
            boolean createNewKeyPair = false;
            if (!rsaPairFile.exists() || rsaPairFile.isDirectory()) {
                createNewKeyPair = true;
            }
            return createNewKeyPair;
        }
 
        /**
         * 将指定的RSA密钥对以文件形式保存。
         * 
         * @param keyPair 要保存的密钥对。
         */
        private static void saveKeyPair(KeyPair keyPair) {
            FileOutputStream fos = null;
            ObjectOutputStream oos = null;
            try {
                fos = FileUtils.openOutputStream(rsaPairFile);
                oos = new ObjectOutputStream(fos);
                oos.writeObject(keyPair);
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                IOUtils.closeQuietly(oos);
                IOUtils.closeQuietly(fos);
            }
        }
 
        /**
         * 返回RSA密钥对。
         */
        public static KeyPair getKeyPair() {
            // 首先判断是否需要重新生成新的密钥对文件
            if (isCreateKeyPairFile()) {
                // 直接强制生成密钥对文件,并存入缓存。
                return generateKeyPair();
            }
            if (oneKeyPair != null) {
                return oneKeyPair;
            }
            return readKeyPair();
        }
         
        // 同步读出保存的密钥对
        private static KeyPair readKeyPair() {
            FileInputStream fis = null;
            ObjectInputStream ois = null;
            try {
                fis = FileUtils.openInputStream(rsaPairFile);
                ois = new ObjectInputStream(fis);
                oneKeyPair = (KeyPair) ois.readObject();
                return oneKeyPair;
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                IOUtils.closeQuietly(ois);
                IOUtils.closeQuietly(fis);
            }
            return null;
        }
 
        /**
         * 根据给定的系数和专用指数构造一个RSA专用的公钥对象。
         * 
         * @param modulus 系数。
         * @param publicExponent 专用指数。
         * @return RSA专用公钥对象。
         */
        public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) {
            RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus),
                    new BigInteger(publicExponent));
            try {
                return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
            } catch (InvalidKeySpecException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
 
        /**
         * 根据给定的系数和专用指数构造一个RSA专用的私钥对象。
         * 
         * @param modulus 系数。
         * @param privateExponent 专用指数。
         * @return RSA专用私钥对象。
         */
        public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) {
            RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus),
                    new BigInteger(privateExponent));
            try {
                return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
            } catch (InvalidKeySpecException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
         
        /**
         * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的私钥对象。
         * 
         * @param modulus 系数。
         * @param privateExponent 专用指数。
         * @return RSA专用私钥对象。
         */
        public static RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
            if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPrivateExponent)) {
                return null;
            }
            byte[] modulus = null;
            byte[] privateExponent = null;
            try {
                modulus = Hex.decodeHex(hexModulus.toCharArray());
                privateExponent = Hex.decodeHex(hexPrivateExponent.toCharArray());
            } catch(DecoderException ex) {
            }
            if(modulus != null && privateExponent != null) {
                return generateRSAPrivateKey(modulus, privateExponent);
            }
            return null;
        }
         
        /**
         * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的公钥对象。
         * 
         * @param modulus 系数。
         * @param publicExponent 专用指数。
         * @return RSA专用公钥对象。
         */
        public static RSAPublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent) {
            if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPublicExponent)) {
                return null;
            }
            byte[] modulus = null;
            byte[] publicExponent = null;
            try {
                modulus = Hex.decodeHex(hexModulus.toCharArray());
                publicExponent = Hex.decodeHex(hexPublicExponent.toCharArray());
            } catch(DecoderException ex) {
            }
            if(modulus != null && publicExponent != null) {
                return generateRSAPublicKey(modulus, publicExponent);
            }
            return null;
        }
 
        /**
         * 使用指定的公钥加密数据。
         * 
         * @param publicKey 给定的公钥。
         * @param data 要加密的数据。
         * @return 加密后的数据。
         */
        public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
            Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            ci.init(Cipher.ENCRYPT_MODE, publicKey);
            return ci.doFinal(data);
        }
 
        /**
         * 使用指定的私钥解密数据。
         * 
         * @param privateKey 给定的私钥。
         * @param data 要解密的数据。
         * @return 原数据。
         */
        public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
            Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            ci.init(Cipher.DECRYPT_MODE, privateKey);
            return ci.doFinal(data);
        }
 
        /**
         * 使用给定的公钥加密给定的字符串。
         * 若 {@code publicKey} 为 {@code null},或者 {@code plaintext} 为 {@code null} 则返回 {@code
         * null}。
         * 
         * @param publicKey 给定的公钥。
         * @param plaintext 字符串。
         * @return 给定字符串的密文。
         */
        public static String encryptString(PublicKey publicKey, String plaintext) {
            if (publicKey == null || plaintext == null) {
                return null;
            }
            byte[] data = plaintext.getBytes();
            try {
                byte[] en_data = encrypt(publicKey, data);
                return new String(Hex.encodeHex(en_data));
            } catch (Exception ex) {
            }
            return null;
        }
         
        /**
         * 使用默认的公钥加密给定的字符串。
         * 若{@code plaintext} 为 {@code null} 则返回 {@code null}。
         * 
         * @param plaintext 字符串。
         * @return 给定字符串的密文。
         */
        public static String encryptString(String plaintext) {
            if(plaintext == null) {
                return null;
            }
            byte[] data = plaintext.getBytes();
            KeyPair keyPair = getKeyPair();
            try {
                byte[] en_data = encrypt((RSAPublicKey)keyPair.getPublic(), data);
                return new String(Hex.encodeHex(en_data));
            } catch(NullPointerException ex) {
            } catch(Exception ex) {
            }
            return null;
        }
 
        /**
         * 使用给定的私钥解密给定的字符串。
         * 若私钥为 {@code null},或者 {@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
         * 私钥不匹配时,返回 {@code null}。
         * 
         * @param privateKey 给定的私钥。
         * @param encrypttext 密文。
         * @return 原文字符串。
         */
        public static String decryptString(PrivateKey privateKey, String encrypttext) {
            if (privateKey == null || StringUtils.isBlank(encrypttext)) {
                return null;
            }
            try {
                byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
                byte[] data = decrypt(privateKey, en_data);
                return new String(data);
            } catch (Exception ex) {
            }
            return null;
        }
         
        /**
         * 使用默认的私钥解密给定的字符串。
         * 若{@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
         * 私钥不匹配时,返回 {@code null}。
         * 
         * @param encrypttext 密文。
         * @return 原文字符串。
         */
        public static String decryptString(String encrypttext) {
            if(StringUtils.isBlank(encrypttext)) {
                return null;
            }
            KeyPair keyPair = getKeyPair();
            try {
                byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
                byte[] data = decrypt((RSAPrivateKey)keyPair.getPrivate(), en_data);
                return new String(data);
            } catch(NullPointerException ex) {
            } catch (Exception ex) {
            }
            return null;
        }
         
        /**
         * 使用默认的私钥解密由JS加密(使用此类提供的公钥加密)的字符串。
         * 
         * @param encrypttext 密文。
         * @return {@code encrypttext} 的原文字符串。
         */
        public static String decryptStringByJs(String encrypttext) {
            String text = decryptString(encrypttext);
            if(text == null) {
                return null;
            }
            return StringUtils.reverse(text);
        }
        /**
         * 与文中参考的博客不同,添加了该方法
         * @param privateKey
         * @param encrypttext
         * @return
         */
        public static String decryptStringByJs(RSAPrivateKey privateKey, String encrypttext) {
            String text = decryptString(privateKey, encrypttext);
            if(text == null) {
                return null;
            }
            return StringUtils.reverse(text);
        }
         
         
        /** 返回已初始化的默认的公钥。*/
        public static RSAPublicKey getDefaultPublicKey() {
            KeyPair keyPair = getKeyPair();
            if(keyPair != null) {
                return (RSAPublicKey)keyPair.getPublic();
            }
            return null;
        }
         
        /** 返回已初始化的默认的私钥。*/
        public static RSAPrivateKey getDefaultPrivateKey() {
            KeyPair keyPair = getKeyPair();
            if(keyPair != null) {
                return (RSAPrivateKey)keyPair.getPrivate();
            }
            return null;
        }
        
        
        public static void main(String[] args) throws DecoderException {
            RSAPublicKey publicKey = getDefaultPublicKey();
            RSAPrivateKey privateKey = getDefaultPrivateKey();
            
            System.out.println("publicKey-->"+publicKey);
            System.out.println("privateKey-->"+privateKey);
             
            String data = "123456";
            //加密
            String codeString = encryptString(publicKey, data);
            System.out.println(codeString);
            //解密
            System.out.println(decryptString(privateKey, codeString));
       }
}



2.controller层代码:demo中使用了servlet

package cn.nuohy.demo;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/rsaser")
public class RsaServlet extends HttpServlet {

	public RsaServlet() {
		super();
	}

	public void destroy() {
		super.destroy();
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		
		String worktype = request.getParameter("worktype");
		
		if(worktype!=null){
			
			//获取加密所需的参数信息
			if(worktype.equals("turn")){
				
				RSAPublicKey publicKey = RSAUtil.getDefaultPublicKey();
				RSAPrivateKey privateKey = RSAUtil.getDefaultPrivateKey();
				Rsaobj rsaobj =  new Rsaobj(publicKey, privateKey);
				
				
				String publicExponent_16 =  new BigInteger(publicKey.getPublicExponent().toString(), 10).toString(16);
				String modulus_16 = new BigInteger(publicKey.getModulus().toString(), 10).toString(16);
				
				System.out.println("公钥 16 getModulus:"+modulus_16);
				System.out.println("公钥 16 getPublicExponent:"+publicExponent_16);
				
				
				System.out.println("私钥  getModulus  :"+privateKey.getModulus());
				System.out.println("私钥  getPrivateExponent   :"+privateKey.getPrivateExponent());
				
				
				//将私钥的 Exponent  Modulus存放至变量中,以便后来构造私钥
				//MyUtil.PrivateExponent = privateKey.getPrivateExponent();
				//MyUtil.PrivateModulus = privateKey.getModulus();
				
				
				request.getSession().setAttribute("modulus_16",modulus_16);
				request.getSession().setAttribute("publicExponent_16",publicExponent_16);
				request.getSession().setAttribute("rsaobj",rsaobj);
				
				
				request.getRequestDispatcher("./demo.jsp").forward(request, response);
				
			
			//提交加密后的内容 进行解密
			}else if(worktype.equals("decrypt")){
				System.out.println("----------decrypt------------");
				String encrypt_password = request.getParameter("password");
				String unencrypt_password = request.getParameter("unpassword");
				System.out.println("未经过加密的数据为:unencrypt_password:"+unencrypt_password);
				System.out.println("前台加密后的数据为:encrypt_password:"+encrypt_password);
				
				Object object = request.getSession().getAttribute("rsaobj");
				
				if(object!=null){
					Rsaobj rsaobj = (Rsaobj) object;
					
					//从 session 中获取私钥
					//RSAPrivateKey privateKey = rsaobj.getPrivateKey();
					
					//从变量中获取数据 构造私钥
					/*RSAPrivateKey privateKey = new RSAPrivateKey() {
						
						@Override
						public BigInteger getModulus() {
							return MyUtil.PrivateModulus;
						}
						
						@Override
						public String getFormat() {
							return null;
						}
						
						@Override
						public byte[] getEncoded() {
							return null;
						}
						
						@Override
						public String getAlgorithm() {
							return null;
						}
						
						@Override
						public BigInteger getPrivateExponent() {
							return MyUtil.PrivateExponent;
						}
					};*/
					
					
					
					
					
					String decrypt_password = RSAUtil.decryptString(privateKey, encrypt_password);
					
					//对字符串进行URL解码的编码处理
					decrypt_password = java.net.URLDecoder.decode(new String(decrypt_password) ,"UTF-8");
					
					System.out.println("解密后的数据为:"+ decrypt_password);
					
					
					Map<String, Object> map = new HashMap<String, Object>();
					map.put("success", true);
					map.put("content", new String(decrypt_password));
					MyUtil.writeToJson(map, response);
					
				}
				
			}
			
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

	public void init() throws ServletException {
		
	}

}




3.前台页面代码


<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>前端加密-后端解密</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	
	<script type="text/javascript" src="./js/rsa/RSA.js?<%=new Date() %>"></script>
	<script type="text/javascript" src="./js/rsa/BigInt.js?<%=new Date() %>"></script>
	<script type="text/javascript" src="./js/rsa/Barrett.js?<%=new Date() %>>"></script>
	<script type="text/javascript" src="./js/jquery-2.1.1.min.js"></script>
  </head>
  
  <body>
    <input id="modulus" type="hidden" value="${modulus_16 }" />
    <input id="publicExponent" type="hidden" value="${publicExponent_16 }" />
    
    <script type="text/javascript">
	var key ;
    function descptcontent() {
        var thisPwd = $("#password").val();
        var publicExponent = $("#publicExponent").val();
        var modulus = $("#modulus").val();

        setMaxDigits(130);
   		var key = new RSAKeyPair(publicExponent, "", modulus);
    
        //对密码进行加密  
        var password = encryptedString(key, encodeURIComponent(thisPwd));
        
        $.ajax({
        	url : '<%=basePath%>rsaser',
        	type : 'POST',
			data : {"worktype":"decrypt","password":password,"unpassword":thisPwd},
			success : function (returnData){
				$("#showcontent").val(returnData.content);
			},
			error : function(returndata) {
				alert("请检查网络!");
			}
        });
        
    }
 
	</script>
    
        需要加密的数据:<input type='text' name="password" id="password" style='width:400px' value="123456" />   <input id="submitcontent" type="button" value="提交" onclick="descptcontent()" />
    <br/>
    <br/>
  	  解密后的内容:<input readonly="readonly" id="showcontent" type="text" value="">
  </body>
</html>






四.代码说明

1. 前台代码中:
在new RSAKeyPair之前,必须先调用setMaxDigits()函数,setMaxDigits()的参数值根据选用的RSA的Key大小
不同1024位的Key, 应该设置setMaxDigits(130);如果是2048位的则应该设置为260
中文乱码问题通过原生js 方法 encodeURIComponent();可以对中文进行url编码后再进行加密传输。
通过servlet来访问页面,公钥会放在session中,页面会直接获取到session中存放的公钥,拿到公钥后,调用
encryptedString(key, encodeURIComponent(thisPwd)); 对内容进行加密。

2.servlet中存放密钥对有两种,最简单的就是自定义一个密钥对类Rsaobj(有两个属性 RSAPublicKey  RSAPrivateKey),产生密钥对后,将密钥对放置到session等中,前台需要解密调用后台时,后台直接获取session中密钥的私钥后即可进行对数据进行解密。当然这种方式只能测试用,因为对于大部分的密钥可能不知能够什么时候需要解密,如果存放至变量或内存中显然不行,需要我们存储至另外一个地方永久存储住,那么最通俗的就直接用数据库存放,问题来了,数据库怎样存放密钥对呢,代码中已经给出了,公钥只需要记录两个属性即可:
publicKey.getPublicExponent();
publicKey.getModulus();

这里提一下:这两个方法获取的数据是10进制的,需要转化为16进制,
String publicExponent_16 =  new BigInteger(publicKey.getPublicExponent().toString(), 10).toString(16);
String modulus_16 = new BigInteger(publicKey.getModulus().toString(), 10).toString(16);



私钥也只需要存放两个属性:
privateKey.getModulus();
privateKey.getPrivateExponent();

这四个属性就构成了一个密钥组
私钥通过构造方法可以产生,代码也给出了,为了简便这里没有存放至数据库,用静态变量代替了数据库。

RSAPrivateKey privateKey = new RSAPrivateKey() {
	
	@Override
	public BigInteger getModulus() {
		return MyUtil.PrivateModulus;
	}
	
	@Override
	public String getFormat() {
		return null;
	}
	
	@Override
	public byte[] getEncoded() {
		return null;
	}
	
	@Override
	public String getAlgorithm() {
		return null;
	}
	
	@Override
	public BigInteger getPrivateExponent() {
		return MyUtil.PrivateExponent;
	}
};


由于前台防止中文乱码,对提交的数据进行url编码,所以解密后的数据需要解码:

decrypt_password = java.net.URLDecoder.decode(new String(decrypt_password) ,"UTF-8");

效果如下图所示:


针对实时产生密钥对进行补充:!!!

上述使用的RSA工具类使用了文本进行缓存,如果不需要缓存,如何实时进行产生呢?

附上代码:
RsaEncryptionUtil.java
package cn.nuohy.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import cn.nuohy.entity.KeyTwin;
 
/**
 * RSA 加解密  工具类
 * @author yangnuo
 * 创建时间:2017年7月3日
 */
public class RsaEncryptionUtil {
 
        /** 算法名称 */
        private static final String ALGORITHOM = "RSA";
         
        /** 密钥大小 */
        private static final int KEY_SIZE = 1024;
         
        /** 默认的安全服务提供者 */
        private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
 
        private static KeyPairGenerator keyPairGen = null;
         
        private static KeyFactory keyFactory = null;
        
        
        static {
            try {
                keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
                keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            } catch (NoSuchAlgorithmException ex) {
            }
        }
 
        private RsaEncryptionUtil() {
        	
        }
 
        /**
         * 生成并返回RSA密钥对。
         */
        private static synchronized KeyPair generateKeyPair() {
            try {
                keyPairGen.initialize(KEY_SIZE, new SecureRandom());
                return keyPairGen.generateKeyPair();
            } catch (InvalidParameterException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
 
        
        /**
         * 返回RSA密钥对。
         */
        public static KeyPair getKeyPair() {
        	return generateKeyPair();
        }
        
 /*********************************************************************** 加		密  *******************************************************************************************/
        
        /**
         * 使用指定的公钥加密数据。
         * 
         * @param publicKey 给定的公钥。
         * @param data 要加密的数据。
         * @return 加密后的数据。
         */
        public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
            Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            ci.init(Cipher.ENCRYPT_MODE, publicKey);
            return ci.doFinal(data);
        }
        
        
        /**
         * 使用给定的公钥加密给定的字符串。
         * 若 {@code publicKey} 为 {@code null},或者 {@code plaintext} 为 {@code null} 则返回 {@code
         * null}。
         * 
         * @param publicKey 给定的公钥。
         * @param plaintext 字符串。
         * @return 给定字符串的密文。
         */
        public static String encryptString(PublicKey publicKey, String plaintext) {
            if (publicKey == null || plaintext == null) {
                return null;
            }
            byte[] data = plaintext.getBytes();
            try {
                byte[] en_data = encrypt(publicKey, data);
                return new String(Hex.encodeHex(en_data));
            } catch (Exception ex) {
            }
            return null;
        }
        
        /*********************************************************************** 解		密  *******************************************************************************************/
 
        /**
         * 使用指定的私钥解密数据。
         * 
         * @param privateKey 给定的私钥。
         * @param data 要解密的数据。
         * @return 原数据。
         */
        public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
            Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
            ci.init(Cipher.DECRYPT_MODE, privateKey);
            return ci.doFinal(data);
        }
 

        /**
         * 使用给定的私钥解密给定的字符串。
         * 若私钥为 {@code null},或者 {@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
         * 私钥不匹配时,返回 {@code null}。
         * 
         * @param privateKey 给定的私钥。
         * @param encrypttext 密文。
         * @return 原文字符串。
         */
        public static String decryptString(PrivateKey privateKey, String encrypttext) {
            if (privateKey == null || StringUtils.isBlank(encrypttext)) {
                return null;
            }
            try {
                byte[] en_data = Hex.decodeHex(encrypttext.toCharArray());
                byte[] data = decrypt(privateKey, en_data);
                return new String(data);
            } catch (Exception ex) {
            }
            return null;
        }
         
        
        /**
         * 通过密钥 解密经过js加密的内容
         * @param privateKey
         * @param encrypttext
         * @return
         */
        public static String decryptStringByJs(RSAPrivateKey privateKey, String encrypttext) {
            String text = decryptString(privateKey, encrypttext);
            if(text == null) {
                return null;
            }
            return StringUtils.reverse(text);
        }
        
        
        /*******************************************************************	构造 RSA	  ***********************************************************************************************/
         
        /**
         * 根据给定的系数和专用指数构造一个RSA专用的公钥对象。
         * 
         * @param modulus 系数。
         * @param publicExponent 专用指数。
         * @return RSA专用公钥对象。
         */
        public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) {
            RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus),
                    new BigInteger(publicExponent));
            try {
                return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
            } catch (InvalidKeySpecException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
 
        /**
         * 根据给定的系数和专用指数构造一个RSA专用的私钥对象。
         * 
         * @param modulus 系数。
         * @param privateExponent 专用指数。
         * @return RSA专用私钥对象。
         */
        public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) {
            RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus),
                    new BigInteger(privateExponent));
            try {
                return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
            } catch (InvalidKeySpecException ex) {
            } catch (NullPointerException ex) {
            }
            return null;
        }
         
        /**
         * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的私钥对象。
         * 
         * @param modulus 系数。
         * @param privateExponent 专用指数。
         * @return RSA专用私钥对象。
         */
        public static RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
            if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPrivateExponent)) {
                return null;
            }
            byte[] modulus = null;
            byte[] privateExponent = null;
            try {
                modulus = Hex.decodeHex(hexModulus.toCharArray());
                privateExponent = Hex.decodeHex(hexPrivateExponent.toCharArray());
            } catch(DecoderException ex) {
            }
            if(modulus != null && privateExponent != null) {
                return generateRSAPrivateKey(modulus, privateExponent);
            }
            return null;
        }
        
        
        /**
         * 根据给定的16进制系数和专用指数字符串构造一个RSA专用的公钥对象。
         * 
         * @param modulus 系数。
         * @param publicExponent 专用指数。
         * @return RSA专用公钥对象。
         */
        public static RSAPublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent) {
            if(StringUtils.isBlank(hexModulus) || StringUtils.isBlank(hexPublicExponent)) {
                return null;
            }
            byte[] modulus = null;
            byte[] publicExponent = null;
            try {
                modulus = Hex.decodeHex(hexModulus.toCharArray());
                publicExponent = Hex.decodeHex(hexPublicExponent.toCharArray());
            } catch(DecoderException ex) {
            }
            if(modulus != null && publicExponent != null) {
                return generateRSAPublicKey(modulus, publicExponent);
            }
            return null;
        }
        
        /*********************************************************************** 测		试  *******************************************************************************************/
        
        public static void main(String[] args) throws DecoderException {
        
        	KeyPair keyPair = generateKeyPair();
        	
        	RSAPublicKey rsapublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaprivateKey = (RSAPrivateKey) keyPair.getPrivate();
        	
            final KeyTwin keyTwin = new KeyTwin(rsapublicKey.getModulus().toString(), rsapublicKey.getPublicExponent().toString(), rsaprivateKey.getModulus().toString(), rsaprivateKey.getPrivateExponent().toString());
            System.out.println(keyTwin.toString());
            
            String data = "落花雨abc123456";
            
            //构造 公钥
            RSAPublicKey publicKey= new RSAPublicKey() {
				@Override
				public BigInteger getModulus() {
					return new BigInteger(keyTwin.getPulicmodulus());
				}
				
				@Override
				public String getFormat() {
					return null;
				}
				
				@Override
				public byte[] getEncoded() {
					return null;
				}
				
				@Override
				public String getAlgorithm() {
					return null;
				}
				
				@Override
				public BigInteger getPublicExponent() {
					return new BigInteger(keyTwin.getPublicexponent());
				}
			};
            
            String encryptString = encryptString(publicKey, data);
            
            System.out.println("加密后的字符串为:"+encryptString);
        	
            
            //构造私钥
            RSAPrivateKey privateKey = new RSAPrivateKey() {
				@Override
				public BigInteger getModulus() {
					return new BigInteger(keyTwin.getPrivatemodulus());
				}
				
				@Override
				public String getFormat() {
					return null;
				}
				
				@Override
				public byte[] getEncoded() {
					return null;
				}
				
				@Override
				public String getAlgorithm() {
					return null;
				}
				
				@Override
				public BigInteger getPrivateExponent() {
					return new BigInteger(keyTwin.getPrivateexponent());
				}
			};
            
            
            String decryptString = decryptString(privateKey, encryptString);
            System.out.println("解密后的字符串为:"+decryptString);
            
            
            
/*        	KeyPair keyPair = generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            
            
            System.out.println("publicKey-->"+publicKey);
            System.out.println("privateKey-->"+privateKey);
             
            String data = "落花雨abc123456";
            
            //加密
            String codeString = encryptString(publicKey, data);
            System.out.println(codeString);
        	
            //解密
			System.out.println(decryptString(privateKey, codeString));*/
        
        }

}


实体类:KeyTwin.java

package cn.nuohy.entity;


/**
 * 密钥对
 * @author yangnuo
 * 创建时间:2017年7月4日
 */
public class KeyTwin {
	
	/**	主键	*/
	private int id;
	/**	公钥 modules	*/
	private String pulicmodulus;
	/**	公钥exponent	*/
	private String publicexponent;
	/**	私钥 modules	*/
	private String privatemodulus;
	/**	私钥exponent	*/
	private String privateexponent;
	
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getPulicmodulus() {
		return pulicmodulus;
	}
	public void setPulicmodulus(String pulicmodulus) {
		this.pulicmodulus = pulicmodulus;
	}
	public String getPublicexponent() {
		return publicexponent;
	}
	public void setPublicexponent(String publicexponent) {
		this.publicexponent = publicexponent;
	}
	public String getPrivatemodulus() {
		return privatemodulus;
	}
	public void setPrivatemodulus(String privatemodulus) {
		this.privatemodulus = privatemodulus;
	}
	public String getPrivateexponent() {
		return privateexponent;
	}
	public void setPrivateexponent(String privateexponent) {
		this.privateexponent = privateexponent;
	}
	public KeyTwin(int id, String pulicmodulus, String publicexponent,
			String privatemodulus, String privateexponent) {
		super();
		this.id = id;
		this.pulicmodulus = pulicmodulus;
		this.publicexponent = publicexponent;
		this.privatemodulus = privatemodulus;
		this.privateexponent = privateexponent;
	}
	public KeyTwin(String pulicmodulus, String publicexponent,
			String privatemodulus, String privateexponent) {
		super();
		this.pulicmodulus = pulicmodulus;
		this.publicexponent = publicexponent;
		this.privatemodulus = privatemodulus;
		this.privateexponent = privateexponent;
	}
	public KeyTwin() {
		super();
	}
	@Override
	public String toString() {
		return "KeyTwin [id=" + id + ", pulicmodulus=" + pulicmodulus
				+ ", publicexponent=" + publicexponent + ", privatemodulus="
				+ privatemodulus + ", privateexponent=" + privateexponent + "]";
	}
	
}



最后附上源码下载链接: http://download.csdn.net/detail/qq_27063119/9887901

(整个网上关于RSA前台加密后台解密的文章也有不少,不过都是有问题的,本人也花了不少时间才弄出来了,8个金币支持下,无金币可以至邮箱:[email protected] )

--感谢您的阅读





猜你喜欢

转载自blog.csdn.net/qq_27063119/article/details/74279754
今日推荐