RSA+SHA256+BASE64对数据进行加密解密及校验
来源:互联网 发布:黔都云商微盘看盘软件 编辑:程序博客网 时间:2024/05/21 18:39
需求
需要实现加密的认证机制
认证原理
a) 密钥分配:RSA算法通过工具或方法调用生成公钥和私钥(1024bit),请求端使用公钥,服务端使用私钥。
b) 加密方式:请求端通过密钥分配获取公钥,根据RSA加密算法将进行哈希后的明文请求进行公钥加密生成token;服务端通过密钥分配获取私钥,根据RSA解密算法将请求端的token进行私钥解密。
c) 认证方式:在服务端,如果明文请求的哈希值和私钥解密后信息的哈希值是一致的,则认为认证成功,完成授权。
d) 数据传输:RSA加密生成的是乱码,为了传输,将数据进行Base64封装,服务端收到之后进行解封装。
认证流程
a) 请求端的认证流程,如下图所示:
b) 服务端的认证流程,如下图所示:
c) 整体流程
编码方法的实现
Commons codec,是项目中用来处理常用的编码方法的工具类包,例如DES、SHA1、MD5、Base64,URL,Soundx等等。不仅是编码,也可用于解码。其中MD5/SHA是不可逆算法,BASE64是可逆算法。目前最新版本是1.11。RSA不在commons codec里。
RSA的实现
import javax.crypto.Cipher;import java.security.*;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;public class RSAUtils { /** * 获取公钥的key */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * 获取私钥的key */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 随机生成密钥对 */ public static Map<String, String> genKeyPair() { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = null; try { keyPairGen = KeyPairGenerator.getInstance("RSA"); } catch (Exception e) { e.printStackTrace(); } // 初始化密钥对生成器,密钥大小为96-1024位 keyPairGen.initialize(1024,new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); // 得到私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); try { // 使用Base64对公钥加密得到字符串 String publicKeyString = Base64Utils.encode(publicKey.getEncoded()); // 使用Base64对私钥加密得到字符串 String privateKeyString = Base64Utils.encode(privateKey.getEncoded()); Map<String, String> keyMap = new HashMap<String, String>(2); keyMap.put(PUBLIC_KEY, publicKeyString); keyMap.put(PRIVATE_KEY, privateKeyString); return keyMap; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 从字符串中加载公钥 * @param publicKeyStr 公钥数据字符串 * @return RSAPublicKey 加载出来的公钥 * @exception Exception 加载公钥时产生的异常 */ public static RSAPublicKey loadPublicKeyByStr(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 (Exception e) { throw new Exception(e); } } /** * 从字符串中加载私钥 * @param privateKeyStr 私钥数据字符串 * @return RSAPublicKey 加载出来的私钥 * @exception Exception 加载私钥时产生的异常 */ public static RSAPrivateKey loadPrivateKeyByStr(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 (Exception e) { throw new Exception(e); } } /** * 公钥加密过程 * @param publicKey 公钥 * @param plainTextData 明文数据 * @return byte[] 加密结果 * @throws Exception 加密过程中的异常信息 */ public static byte[] 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 output; } catch (Exception e) { throw new Exception(e); } } /** * 私钥加密过程 * @param privateKey 私钥 * @param plainTextData 明文数据 * @return byte[] 加密结果 * @throws Exception 加密过程中的异常信息 */ public static byte[] 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 output; } catch (Exception e) { throw new Exception(e); } } /** * 私钥解密过程 * @param privateKey 私钥 * @param cipherData 密文数据 * @return 明文 * @throws Exception 解密过程中的异常信息 */ public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception { if (privateKey == null) { throw new Exception("解密私钥为空, 请设置"); } Cipher cipher = null; try { // 使用默认RSA cipher = Cipher.getInstance("RSA"); // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] output = cipher.doFinal(cipherData); return output; } catch (Exception e) { throw new Exception(e); } } /** * 公钥解密过程 * @param publicKey 公钥 * @param cipherData 密文数据 * @return 明文 * @throws Exception 解密过程中的异常信息 */ public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData) throws Exception { if (publicKey == null) { throw new Exception("解密公钥为空, 请设置"); } Cipher cipher = null; try { // 使用默认RSA cipher = Cipher.getInstance("RSA"); // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider()); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] output = cipher.doFinal(cipherData); return output; } catch (Exception e) { throw new Exception(e); } } /** * 获取私钥 * @param keyMap 密钥对 * @return * @throws Exception */ public static String getPrivateKey(Map<String, String> keyMap) throws Exception { String privateKey = keyMap.get(PRIVATE_KEY); return privateKey; } /** * 获取公钥 * @param keyMap 密钥对 * @return * @throws Exception */ public static String getPublicKey(Map<String, String> keyMap) throws Exception { String publicKey = keyMap.get(PUBLIC_KEY); return publicKey; }}
SHA256与Base64实现
commons.codec包有这两个算法的实现,分别如下:
SHA256
import org.apache.commons.codec.digest.DigestUtils;public class SHA256Utils { /** * sha256加密 * */ public static String sha256Hex(String data){ return DigestUtils.sha256Hex(data); }}
Base64
import org.apache.commons.codec.binary.Base64;public class Base64Utils{ /** * 使用Base64加密字符串 * @return 加密之后的字符串 * @exception Exception */ public static String encode(byte[] data){ Base64 base64 = new Base64(); String encodedData = base64.encodeAsString(data); return encodedData; } /** * 使用Base64解密 * @return 解密之后的字符串 * @exception Exception */ public static byte[] decode(String data){ Base64 base64 = new Base64(); byte[] decodedData = base64.decodeBase64(data); return decodedData; }}
Springmvc的实现
当前端对服务端进行调用时,需要在springmvc中编写一个拦截器,实现一个class继承HandlerInterceptorAdapter,并重写preHandle函数,实现如下:
在dispatcher中添加拦截器:
<mvc:interceptors> <bean class="com.zyuc.fw.web.util.tokenInterceptor"/></mvc:interceptors>
拦截器代码实现
import com.commons.common.support.spring.security.SecurityInterceptor;import com.commons.common.utils.PropUtil;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import org.apache.commons.codec.binary.Base64;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.security.interfaces.RSAPrivateKey;import java.util.*;public class tokenInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class); public tokenInterceptor() { } private String getPrivateValues(byte[] decodeByte) throws Exception{ String privateKeyString = PropUtil.get("RSA.PrivateKey"); RSAPrivateKey privateKey = RSAUtils.loadPrivateKeyByStr(privateKeyString); logger.info("[tokenInterceptor getPrivateValues] : privateKey = %s.", privateKey); //私钥解密 byte[] decodedData = RSAUtils.decrypt(privateKey, decodeByte); String token = new String(decodedData); return token; } /* * 使用拦截器在客户端访问之前对请求的数据进行校验 */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = ""; String serviceToken = ""; String requestValues = ""; String requestUrl = request.getRequestURL().toString();//得到请求的URL地址 requestValues += requestUrl; Map params = request.getParameterMap();//得到所有请求的参数 Iterator it = params.keySet().iterator(); /*获取URL+body的字符串集合*/ while(it.hasNext()){ String paramName = (String) it.next(); String paramValue = request.getParameter(paramName); requestValues += paramName; requestValues += paramValue; } /*获取token,并对token做base64解码*/ Enumeration<String> reqHeadInfos = request.getHeaderNames();//获取所有的请求头 while (reqHeadInfos.hasMoreElements()) { token = request.getHeader("Authorization");//根据请求头的名字获取token的值 break; } /*如果没有添加token,默认不进行校验*/ if (null == token) { return super.preHandle(request, response, handler); } byte[] decodeByte = Base64.decodeBase64(token); /*获取私钥解密之后的token值*/ token = getPrivateValues(decodeByte); serviceToken = SHA256Utils.sha256Hex(requestValues); if (!serviceToken.equals(token)) {//判断两次的token值是否相同 return false; } return super.preHandle(request, response, handler); }}
阅读全文
1 0
- RSA+SHA256+BASE64对数据进行加密解密及校验
- C#.NET 加密解密:AES/DES/Base64/RSA/MD5/SHA256
- C#.NET 加密解密:AES/DES/Base64/RSA/MD5/SHA256
- C#.NET 加密解密:AES/DES/Base64/RSA/MD5/SHA256
- iOS中使用RSA对数据进行加密解密
- iOS中使用RSA对数据进行加密解密
- iOS中使用RSA对数据进行加密解密
- MAC系统用RSA 对数据进行加密解密
- iOS中使用RSA对数据进行加密解密
- iOS中使用RSA对数据进行加密解密
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)
- Java使用RSA加密解密签名及校验
- Java使用RSA加密解密签名及校验
- Java使用RSA加密解密签名及校验
- Java使用RSA加密解密签名及校验
- Java使用RSA加密解密签名及校验
- 2017-10-31C#引申的一个例题——不重复抽取元素的组合
- IOS项目新手引导页图片适配方案
- PCI/PCIe基础——配置空间
- SpringBoot和PostGIS环境搭建(Hibernate4)
- InnosetUp打包配置多语言
- RSA+SHA256+BASE64对数据进行加密解密及校验
- IOS 自定义tabBar的按钮添加点击放大缩小的动画
- div之“可编辑”属性,按下“回车键”之后出现的兼容性问题的处理办法
- Apache ActiveMQ
- Android内核开发:系统启动速度优化
- Java项目打包JAR文件并运行
- ListView设置分割线
- bootstrap初试
- C# => Lambda表达式理解