web项目中非对称加密的使用

  • 非对称加密
  • 非对称加密基本原理
  • 使用非对称加密的两种基本姿势
  • 项目中的使用实例


非对称加密

非对称加密是整个算法世界最重要的算法之一,理由很简单,保证了对于需要通信的双方,通信的数据的安全。 加密基本分为对称加密和非对称加密,所谓对称加密即通信双方采取对通信数据的同等加密方式比较传输前后的数据一致性。非对称加密通信的双方不必要对数据采取一致策略。

非对称加密基本原理

基本原理是:在使用非对称加密之前首先生成一对钥匙,公钥和私钥(其实就是两个字符串),两个钥匙的特点是,公钥可以加密数据,加密后的数据只能被对应的私钥解密。私钥对数据生成签名,这个签名只能被对应的公钥验签。通常私钥由自己保存,公钥可以随意散播

使用非对称加密的两种基本姿势

情形一:
假设现在A、B需要进行通信,由A利用机器生成了非对称加密需要使用的一串钥匙。那么A会选择将公钥交给B,自己保存私钥。当B想给A写一封信,他可以将信件使用公钥加密,加密完成之后认为,除了持有私钥的A,无任何人可以解密这封信的内容。如果A想给B回信,A可以利用自己的私钥将信件进行签名,B收到信件之后首先用公钥验证签名,通过之后认为这的确是A给自己的信件。但此时可能存在更加复杂的情形,C偷偷将B保存的公钥换成了自己的公钥,再利用自己的私钥生成签名之后发送给B,此时B验签无误,拿到的其实是C给自己的信却还以为这是A给自己的回信,这种情形下,B可以找到一个第三方,将A的公钥告诉这个第三方每次要验证信件签名的时候,首先去问下这到底是不是A的公钥。
情形二:
假设B不想去找第三方进行公证的话,其实还有别的办法解决以上问题。那就是B自己也生成一对公钥和私钥,往后双方进行通信的流程如下:
case1:A和B都需要产生一对用于加密和解密的公钥和私钥。
case2:A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
case3:A要给B发送信息时,A用B的公钥加密信息,利用自己的私钥为数据生成签名。
case4:B收到这个消息后,B用A的公钥验签,验证通过,用自己的私钥解密消息。
case5:B回信时,利用A的公钥加密数据,利用自己的私钥生成签名。
case6:A收到回信,利用B的公钥验证签名,验签通过,用自己的私钥解密消息。
case7:往后双方通信均按照此流程。

项目中的使用实例

首先引入案例的jar包,为我们封装了双方加解密的细节

<!--引入阿里做非对称加密的依赖-->
        <dependency>
            <groupId>com.alipay.api</groupId>
            <artifactId>k12-alipay-sdk</artifactId>
            <version>0.0.1-beta</version>
        </dependency>

示例代码

package com.bytter.faceid.util;

import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.XmlUtils;

/**
 * 
 * @author wuwensheng
 * 2019-10-09
 * @version
 */
public class CryptoUtil2 {

	public final static String BT_PRI_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK2eX8qwW7Io8oxHjlrURla8vUyb9YcWn7fHZ+to0ru+EbHeeuZQ92yyJNPxcgys5nxyffx3VjgD0ELmAYP+X8bVcsp8M8hs9XN/LirWHO555wN/z4lbdYGDUjA/1LkLgV4VXnTNpcJpRWwJUdEGjh67vzhRJDlncJnXPrAVWY4vAgMBAAECgYBf80XnY53ZkU2yfx1KT0RsTTSk8RA5TySH0Zk5/Z1xCnMHBPiQ7rA/DxjRVP99x9Q9dJzx+RXaMSlYv3qY8u0EsQKLP24dEJNGQaFWiuews4GL8ALO0oATRTpUPy05+ZsCPLxnEzai73Z4ci5wNSPRm/F5RVVR9eEGMQ7fKDPq2QJBAOe6qp1GEd2B1GliIxbfcRRBM+Ir1W6ieKxHdRka/kScrQAg8N58LNKgiRs+mMrkFej8urhYu4UuYYaPww6Sb8UCQQC/zZh5Zk5HlKbjloX+9vPtjTfIHRIR98/Bet0C0r4Zof21zyXqucek5clYivqhX8kkKaCDw1jhftQcJUQKn1FjAkEApunYFyzvlWP9AmOD7ufHZdWJb7IvLF+vGDjoacr9t6I7IsqXdUpwZs7ns04ldI9SEN5qCHsxpz6/VNOcppRoGQJAbEJggI1FO9PkyurIIRxEnF2sEZCPBYNJSZzOqGxJDnDHoloUvcM0s5dbqVVwl6tX/chdKGIXhdevY1+JYzF/nwJBAI4KY3nZ0si64e3Zrr/4sJv/SZebltCiMw6IvMWLMV+QxVNZT5N7ukEDjoQrp0XhA/P+6tQLgnWwUS3rSh3sTys=";
	public final static String BT_PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtnl/KsFuyKPKMR45a1EZWvL1Mm/WHFp+3x2fraNK7vhGx3nrmUPdssiTT8XIMrOZ8cn38d1Y4A9BC5gGD/l/G1XLKfDPIbPVzfy4q1hzueecDf8+JW3WBg1IwP9S5C4FeFV50zaXCaUVsCVHRBo4eu784USQ5Z3CZ1z6wFVmOLwIDAQAB";
	public final static String OT_PRI_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALlycS/Wzm6BsasbQko1OTARTvNQaMnoyQYsmUW3vU0RPtPISFUg9muANMMBq0oMiJgvRThKoKFbO3o/HXby66PbyYMs4IZs8gtXz4K1/Fs7+m3z2dLjB33bFQbwERWpUDv8pUe+G+u6GQawk0jUyhZjs2u70oNoT/fFCwIHY17hAgMBAAECgYA26YpWjhbGZiUD86hnbOcoMpfcOH0u/H06FM619Dhbr7WY5H92pbISFv6Il9/up1NzLNwkVQTHgspT4oiJBll7xE9Sji+pcMM0GWVp6aF1Rnz83Mk2nOxzx/lhXFdBKkJZP0h58cI6d6AkVPmJxG3kNsXS6CEsTwSsW51d0VsIGQJBAOwShpfHENcpyVYc6uP3x6/MxqnWs/QBLBfzNluUIB5q1usdk6LGwwziaes6qZUz7nL4qb0Jnk1GgNNnzaqyI7MCQQDJGenoyQwLjNSjg76yLmHk9KWoBBQdVxi93c5/2RjgaWX/K7bSOLAhxJwEdRtHMISXPGJ1/BmG/FV1leNoXnkbAkEA5i++O3qoihS9tBDoXLc7Z8j1oZ+vwmnuM8A8LZnGo8IrpAAn9911TTfsbai6uLh1dnfPEnuxdsobTYf2+81NjwJAdTOwGmZJqdWa++1FT20uypQ2k5RE8NCY79b8iZBKKkfjFPMyKpS1Ogju8L4bdsL1E3sy2xZg/kXDvLLthR9CLwJAXA0HecA1ZcD2bZ3PcwMk4hlb3rqDGfUvcaCVUJj2xaWUuUYmePW6OwwuFeJJpT1OFvuWgx/YvAXAOcqr4CsUMg==";
	public final static String OT_PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5cnEv1s5ugbGrG0JKNTkwEU7zUGjJ6MkGLJlFt71NET7TyEhVIPZrgDTDAatKDIiYL0U4SqChWzt6Px128uuj28mDLOCGbPILV8+CtfxbO/pt89nS4wd92xUG8BEVqVA7/KVHvhvruhkGsJNI1MoWY7Nru9KDaE/3xQsCB2Ne4QIDAQAB";
	
	
	public static void main1(String[] args) {
		String content = "abc";
		try{
			System.out.println(content);
			String en = deliver(content,OT_PUB_KEY,BT_PRI_KEY);
			System.out.println(en);
			String de = receive(en,BT_PUB_KEY,OT_PRI_KEY);
			System.out.println(de);
		}catch(Exception e){
			
		}
	}
	public static void main(String[] args) {
		String content = "{\"requestTime\":\"20190926172507\",\"content\":{\"idCard\":\"360735199808080001\",\"name\":\"李华\"}}";
		try{
			String en = deliver(content,BT_PUB_KEY,OT_PRI_KEY);
			System.out.println(en);
		}catch(Exception e){
			
		}
	}
	
	/**
	 * 验签、解密
	 * @param msg
	 * @param otherPublicKey
	 * @param ownPrivateKey
	 * @return
	 * @throws AlipayApiException 
	 */
	public static String receive(String msg,String otherPublicKey,String ownPrivateKey) throws AlipayApiException{
		if(!StringUtils.isBlank(msg)){
			Element e = XmlUtils.getRootElementFromString(msg);
			String content = XmlUtils.getElementValue(e, "response");
			String sign = XmlUtils.getElementValue(e, "sign");
			if(rsaCheckSign(content, sign, otherPublicKey)){
				return rsaDecrypt(content, ownPrivateKey);
			}
		}
		return null;
	}
	
	/**
	 * 加密、签名
	 * @param msg
	 * @param otherPublicKey
	 * @param ownPrivateKey
	 * @return
	 * @throws AlipayApiException 
	 */
	public static String deliver(String msg,String otherPublicKey,String ownPrivateKey) throws AlipayApiException{
		StringBuilder sb = null;
		if(!StringUtils.isBlank(msg)){
			sb = new StringBuilder();
	        sb.append("<?xml version=\"1.0\" encoding=\"" + AlipayConstants.CHARSET_UTF8 + "\"?>");
            sb.append("<alipay>");
            String encrypted = rsaEncrypt(msg, otherPublicKey);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>RSA</encryption_type>");
            String sign = rsaSign(encrypted, ownPrivateKey);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>RSA</sign_type>");
            sb.append("</alipay>");
		}
		return sb.toString();
	}
    
    
	public static String rsaEncrypt(String msg,String publicKey) throws AlipayApiException {
		return AlipaySignature.rsaEncrypt(msg, publicKey, AlipayConstants.CHARSET_UTF8);
 	}
	
	public static String rsaSign(String msg,String privateKey) throws AlipayApiException {
		return AlipaySignature.rsaSign(msg, privateKey, AlipayConstants.CHARSET_UTF8);
 	}
 	
	public static String rsaDecrypt(String msg,String privateKey) throws AlipayApiException {
 		return AlipaySignature.rsaDecrypt(msg, privateKey, AlipayConstants.CHARSET_UTF8);
 	}
 	
	public static boolean rsaCheckSign(String msg,String sign,String publicKey) throws AlipayApiException {
 		return AlipaySignature.rsaCheck(msg, sign,publicKey, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA);
 	}
	

}

代码中双方通信方式按照第二种情形,数据采取xml传输,main()方法解释了具体通信过程。