RSA+SHA256+BASE64对数据进行加密解密及校验

雨点打透心脏的1/2处 2021-06-30 08:41 958阅读 0赞

#需求
需要实现加密的认证机制
##认证原理
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的实现

  1. import javax.crypto.Cipher;
  2. import java.security.*;
  3. import java.security.interfaces.RSAPrivateKey;
  4. import java.security.interfaces.RSAPublicKey;
  5. import java.security.spec.PKCS8EncodedKeySpec;
  6. import java.security.spec.X509EncodedKeySpec;
  7. import java.util.HashMap;
  8. import java.util.Map;
  9. public class RSAUtils {
  10. /**
  11. * 获取公钥的key
  12. */
  13. private static final String PUBLIC_KEY = "RSAPublicKey";
  14. /**
  15. * 获取私钥的key
  16. */
  17. private static final String PRIVATE_KEY = "RSAPrivateKey";
  18. /**
  19. * 随机生成密钥对
  20. */
  21. public static Map<String, String> genKeyPair() {
  22. // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
  23. KeyPairGenerator keyPairGen = null;
  24. try {
  25. keyPairGen = KeyPairGenerator.getInstance("RSA");
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. // 初始化密钥对生成器,密钥大小为96-1024位
  30. keyPairGen.initialize(1024,new SecureRandom());
  31. // 生成一个密钥对,保存在keyPair中
  32. KeyPair keyPair = keyPairGen.generateKeyPair();
  33. // 得到私钥
  34. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  35. // 得到公钥
  36. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  37. try {
  38. // 使用Base64对公钥加密得到字符串
  39. String publicKeyString = Base64Utils.encode(publicKey.getEncoded());
  40. // 使用Base64对私钥加密得到字符串
  41. String privateKeyString = Base64Utils.encode(privateKey.getEncoded());
  42. Map<String, String> keyMap = new HashMap<String, String>(2);
  43. keyMap.put(PUBLIC_KEY, publicKeyString);
  44. keyMap.put(PRIVATE_KEY, privateKeyString);
  45. return keyMap;
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. return null;
  49. }
  50. }
  51. /**
  52. * 从字符串中加载公钥
  53. * @param publicKeyStr 公钥数据字符串
  54. * @return RSAPublicKey 加载出来的公钥
  55. * @exception Exception 加载公钥时产生的异常
  56. */
  57. public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
  58. throws Exception {
  59. try {
  60. byte[] buffer = Base64Utils.decode(publicKeyStr);
  61. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  62. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
  63. return (RSAPublicKey) keyFactory.generatePublic(keySpec);
  64. } catch (Exception e) {
  65. throw new Exception(e);
  66. }
  67. }
  68. /**
  69. * 从字符串中加载私钥
  70. * @param privateKeyStr 私钥数据字符串
  71. * @return RSAPublicKey 加载出来的私钥
  72. * @exception Exception 加载私钥时产生的异常
  73. */
  74. public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
  75. throws Exception {
  76. try {
  77. byte[] buffer = Base64Utils.decode(privateKeyStr);
  78. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
  79. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  80. return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
  81. } catch (Exception e) {
  82. throw new Exception(e);
  83. }
  84. }
  85. /**
  86. * 公钥加密过程
  87. * @param publicKey 公钥
  88. * @param plainTextData 明文数据
  89. * @return byte[] 加密结果
  90. * @throws Exception 加密过程中的异常信息
  91. */
  92. public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
  93. throws Exception {
  94. if (publicKey == null) {
  95. throw new Exception("加密公钥为空, 请设置");
  96. }
  97. Cipher cipher = null;
  98. try {
  99. // 使用默认RSA
  100. cipher = Cipher.getInstance("RSA");
  101. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  102. byte[] output = cipher.doFinal(plainTextData);
  103. return output;
  104. } catch (Exception e) {
  105. throw new Exception(e);
  106. }
  107. }
  108. /**
  109. * 私钥加密过程
  110. * @param privateKey 私钥
  111. * @param plainTextData 明文数据
  112. * @return byte[] 加密结果
  113. * @throws Exception 加密过程中的异常信息
  114. */
  115. public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
  116. throws Exception {
  117. if (privateKey == null) {
  118. throw new Exception("加密私钥为空, 请设置");
  119. }
  120. Cipher cipher = null;
  121. try {
  122. // 使用默认RSA
  123. cipher = Cipher.getInstance("RSA");
  124. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  125. byte[] output = cipher.doFinal(plainTextData);
  126. return output;
  127. } catch (Exception e) {
  128. throw new Exception(e);
  129. }
  130. }
  131. /**
  132. * 私钥解密过程
  133. * @param privateKey 私钥
  134. * @param cipherData 密文数据
  135. * @return 明文
  136. * @throws Exception 解密过程中的异常信息
  137. */
  138. public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
  139. throws Exception {
  140. if (privateKey == null) {
  141. throw new Exception("解密私钥为空, 请设置");
  142. }
  143. Cipher cipher = null;
  144. try {
  145. // 使用默认RSA
  146. cipher = Cipher.getInstance("RSA");
  147. // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
  148. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  149. byte[] output = cipher.doFinal(cipherData);
  150. return output;
  151. } catch (Exception e) {
  152. throw new Exception(e);
  153. }
  154. }
  155. /**
  156. * 公钥解密过程
  157. * @param publicKey 公钥
  158. * @param cipherData 密文数据
  159. * @return 明文
  160. * @throws Exception 解密过程中的异常信息
  161. */
  162. public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
  163. throws Exception {
  164. if (publicKey == null) {
  165. throw new Exception("解密公钥为空, 请设置");
  166. }
  167. Cipher cipher = null;
  168. try {
  169. // 使用默认RSA
  170. cipher = Cipher.getInstance("RSA");
  171. // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
  172. cipher.init(Cipher.DECRYPT_MODE, publicKey);
  173. byte[] output = cipher.doFinal(cipherData);
  174. return output;
  175. } catch (Exception e) {
  176. throw new Exception(e);
  177. }
  178. }
  179. /**
  180. * 获取私钥
  181. * @param keyMap 密钥对
  182. * @return
  183. * @throws Exception
  184. */
  185. public static String getPrivateKey(Map<String, String> keyMap)
  186. throws Exception {
  187. String privateKey = keyMap.get(PRIVATE_KEY);
  188. return privateKey;
  189. }
  190. /**
  191. * 获取公钥
  192. * @param keyMap 密钥对
  193. * @return
  194. * @throws Exception
  195. */
  196. public static String getPublicKey(Map<String, String> keyMap)
  197. throws Exception {
  198. String publicKey = keyMap.get(PUBLIC_KEY);
  199. return publicKey;
  200. }
  201. }

##SHA256与Base64实现
commons.codec包有这两个算法的实现,分别如下:
###SHA256

  1. import org.apache.commons.codec.digest.DigestUtils;
  2. public class SHA256Utils {
  3. /**
  4. * sha256加密
  5. * */
  6. public static String sha256Hex(String data){
  7. return DigestUtils.sha256Hex(data);
  8. }
  9. }

###Base64

  1. import org.apache.commons.codec.binary.Base64;
  2. public class Base64Utils
  3. {
  4. /**
  5. * 使用Base64加密字符串
  6. * @return 加密之后的字符串
  7. * @exception Exception
  8. */
  9. public static String encode(byte[] data){
  10. Base64 base64 = new Base64();
  11. String encodedData = base64.encodeAsString(data);
  12. return encodedData;
  13. }
  14. /**
  15. * 使用Base64解密
  16. * @return 解密之后的字符串
  17. * @exception Exception
  18. */
  19. public static byte[] decode(String data){
  20. Base64 base64 = new Base64();
  21. byte[] decodedData = base64.decodeBase64(data);
  22. return decodedData;
  23. }
  24. }

#Springmvc的实现
当前端对服务端进行调用时,需要在springmvc中编写一个拦截器,实现一个class继承HandlerInterceptorAdapter,并重写preHandle函数,实现如下:
在dispatcher中添加拦截器:

  1. <mvc:interceptors>
  2. <bean class="com.zyuc.fw.web.util.tokenInterceptor"/>
  3. </mvc:interceptors>

##拦截器代码实现

  1. import com.commons.common.support.spring.security.SecurityInterceptor;
  2. import com.commons.common.utils.PropUtil;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  6. import org.apache.commons.codec.binary.Base64;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.security.interfaces.RSAPrivateKey;
  10. import java.util.*;
  11. public class tokenInterceptor extends HandlerInterceptorAdapter {
  12. private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class);
  13. public tokenInterceptor() {
  14. }
  15. private String getPrivateValues(byte[] decodeByte) throws Exception{
  16. String privateKeyString = PropUtil.get("RSA.PrivateKey");
  17. RSAPrivateKey privateKey = RSAUtils.loadPrivateKeyByStr(privateKeyString);
  18. logger.info("[tokenInterceptor getPrivateValues] : privateKey = %s.", privateKey);
  19. //私钥解密
  20. byte[] decodedData = RSAUtils.decrypt(privateKey, decodeByte);
  21. String token = new String(decodedData);
  22. return token;
  23. }
  24. /*
  25. * 使用拦截器在客户端访问之前对请求的数据进行校验
  26. */
  27. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  28. String token = "";
  29. String serviceToken = "";
  30. String requestValues = "";
  31. String requestUrl = request.getRequestURL().toString();//得到请求的URL地址
  32. requestValues += requestUrl;
  33. Map params = request.getParameterMap();//得到所有请求的参数
  34. Iterator it = params.keySet().iterator();
  35. /*获取URL+body的字符串集合*/
  36. while(it.hasNext()){
  37. String paramName = (String) it.next();
  38. String paramValue = request.getParameter(paramName);
  39. requestValues += paramName;
  40. requestValues += paramValue;
  41. }
  42. /*获取token,并对token做base64解码*/
  43. Enumeration<String> reqHeadInfos = request.getHeaderNames();//获取所有的请求头
  44. while (reqHeadInfos.hasMoreElements()) {
  45. token = request.getHeader("Authorization");//根据请求头的名字获取token的值
  46. break;
  47. }
  48. /*如果没有添加token,默认不进行校验*/
  49. if (null == token) {
  50. return super.preHandle(request, response, handler);
  51. }
  52. byte[] decodeByte = Base64.decodeBase64(token);
  53. /*获取私钥解密之后的token值*/
  54. token = getPrivateValues(decodeByte);
  55. serviceToken = SHA256Utils.sha256Hex(requestValues);
  56. if (!serviceToken.equals(token)) {//判断两次的token值是否相同
  57. return false;
  58. }
  59. return super.preHandle(request, response, handler);
  60. }
  61. }

发表评论

表情:
评论列表 (有 0 条评论,958人围观)

还没有评论,来说两句吧...

相关阅读

    相关 base64加密解密

    1.定义 Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2