当前位置:   article > 正文

安全扫描:敏感数据加密传输和保存(国密)_敏感信息密文保存

敏感信息密文保存

记难受的老项目进行安全扫描的坑:敏感数据加密传输和保存

首先我们先创建这么一个JAVA工具类,用里面的main方法来得到SM2加密时需要用到的公钥和私钥,需要注意的是,执行一次就拿到这两个值来放到另一个类中或者数据库中来永久使用,需要调用时从里面调用即可,记得保密!

  1. package com.cn.zj.sm;
  2. import java.math.BigInteger;
  3. import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
  4. import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
  5. import org.bouncycastle.crypto.params.ECPublicKeyParameters;
  6. import org.bouncycastle.math.ec.ECPoint;
  7. import org.bouncycastle.util.encoders.Hex;
  8. public class SMutil
  9. {
  10. public static class SM2Key{
  11. public String publicKey; //公钥
  12. public String privateKey; //私钥
  13. }
  14. private static boolean isEmpty(String str)
  15. {
  16. if(str==null || str.trim().equals("")){
  17. return true;
  18. }
  19. return false;
  20. }
  21. /**
  22. * 生成SM2秘钥
  23. */
  24. @SuppressWarnings("deprecation")
  25. public static SM2Key generateSM2Key(){
  26. SM2 sm2 = SM2.Instance();
  27. AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
  28. ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
  29. ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
  30. BigInteger privateKey = ecpriv.getD();
  31. ECPoint publicKey = ecpub.getQ();
  32. SM2Key sm2Key = new SM2Key();
  33. sm2Key.publicKey = Util.byteToHex(publicKey.getEncoded());
  34. sm2Key.privateKey = Util.byteToHex(privateKey.toByteArray());
  35. return sm2Key;
  36. }
  37. /**
  38. * SM2加密
  39. * @param publickey 公钥
  40. * @param src 待加密的明文
  41. * @return
  42. */
  43. public static String sm2encrypt(String publickey, String str){
  44. if(isEmpty(publickey) || isEmpty(str)){
  45. return null;
  46. }
  47. try {
  48. return SM2Utils.encrypt(Util.hexToByte(publickey), str.getBytes());
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. return null;
  53. }
  54. /**
  55. * SM2解密
  56. * @param privatekey 私钥
  57. * @param src 待解密的密文
  58. * @return
  59. */
  60. public static String sm2decrypt(String privatekey, String str){
  61. if(isEmpty(privatekey) || isEmpty(str)){
  62. return null;
  63. }
  64. try {
  65. return new String(SM2Utils.decrypt(Util.hexToByte(privatekey), Util.hexToByte(str)));
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. return null;
  70. }
  71. /**
  72. * SM3加密
  73. * @param str 待加密的明文
  74. * @return
  75. */
  76. public static String sm3encrypt(String str){
  77. if(isEmpty(str)){
  78. return null;
  79. }
  80. byte[] md = new byte[32];
  81. byte[] msg1 = str.getBytes();
  82. SM3Digest sm3 = new SM3Digest();
  83. sm3.update(msg1, 0, msg1.length);
  84. sm3.doFinal(md, 0);
  85. return new String(Hex.encode(md));
  86. }
  87. /**
  88. * sm3密码校验
  89. * @param str 待校验的明文
  90. * @param sm3Str sm3加密后的密文
  91. * @return
  92. */
  93. public static boolean sm3decrypt(String str, String sm3Str){
  94. if(isEmpty(str) || isEmpty(sm3Str)){
  95. return false;
  96. }
  97. return sm3Str.equalsIgnoreCase(sm3encrypt(str));
  98. }
  99. /**
  100. * SM4加密
  101. * @param str 待加密的明文
  102. * @return
  103. */
  104. public static String sm4encrypt(String str){
  105. if(isEmpty(str)){
  106. return null;
  107. }
  108. String ret = new SM4Utils().encryptData_ECB(str);
  109. return ret;
  110. }
  111. /**
  112. * SM4加密
  113. * @param str 待解密的密文
  114. * @return
  115. */
  116. public static String sm4decrypt(String str){
  117. if(isEmpty(str)){
  118. return null;
  119. }
  120. String ret = new SM4Utils().decryptData_ECB(str);
  121. return ret;
  122. }
  123. public static void main(String[] args){
  124. SM2Key sm2Key = generateSM2Key();
  125. System.out.println("私钥privateKey:"+sm2Key.privateKey);
  126. System.out.println("公钥publicKey: "+sm2Key.publicKey);
  127. }
  128. }

 这是一个在上面的工具类基础上写出的另一个更加功能完善的工具类,可以直接调用,公钥和私钥都已经放在上面

  1. package com.cn.zj.sm;
  2. import org.apache.commons.lang3.ArrayUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.stereotype.Service;
  6. import com.xquant.xqa.component.util.utils.StringUtil;
  7. /**
  8. * @program: SMHandler
  9. * @description: 国密加密解密
  10. * @author: zhangjun
  11. * @create: 2021/03/30
  12. **/
  13. @Service
  14. public class SMHandler {
  15. //SM2私钥
  16. private static final String privatekey = "24F2401757F59665DED44ECEC08C7314E14F74E95B0720D0FA03E7992440CF1A";
  17. //SM2公钥
  18. private static final String pubkeyHex = "04509AEB08F6645C6AC92B965A5EAA6EE7761908A4AE1454DA537A855F1ADF0D611D45486362D856D7DFB45688EC969B96FD32E5E008FFE9E74E4A424A422DF3AC";
  19. private Logger logger = LoggerFactory.getLogger(SMHandler.class);
  20. /**
  21. * @Title: passWordCryptBySM2_3
  22. * @Description: 解析前端传入密文,转译成数据库存储密文,
  23. * 前端加密逻辑要求:密文 = SM2 (明文)+SM3 (明文)
  24. * 存入数据库密文要求:密文 = SM3 (明文)
  25. * @param str 前端传入密文
  26. * @return: java.lang.String 密码明文
  27. * @throws
  28. */
  29. public String passWordCryptBySM2_3(String str){
  30. //【1】分割传输过来的密文,得到 0.SM2加密过的明文 1.SM3算法加密后的密文
  31. String[] strArr = StringUtil.split(str,"|");
  32. if(ArrayUtils.isEmpty(strArr) || strArr.length != 2){
  33. logger.info("完整性校验失败:"+ str);
  34. return null;
  35. }
  36. //【2】用SM2私钥解密传输过来的密文,获取明文
  37. String privateKey = privatekey;
  38. String passWord = SMutil.sm2decrypt(privateKey,strArr[0]);
  39. String passWd = SMutil.sm2decrypt(privateKey,strArr[1]);
  40. //【3】完整性校验——判断明文与加密后的密文是否相同
  41. // if(!SMutil.sm3decrypt(passWord,strArr[1])){
  42. if(!SMutil.sm3decrypt(passWord,passWd)){
  43. logger.info("完整性校验失败:"+ str);
  44. return null;
  45. }
  46. // System.out.println("传入密文:"+str);
  47. // System.out.println("SM2密钥加密密文:"+strArr[0]);
  48. // System.out.println("SM3加密密文:"+strArr[1]);
  49. // System.out.println("密码:"+passWord);
  50. //【4】返回SM3加密后明文
  51. // return strArr[1];
  52. //【4】返回密码明文
  53. return passWord;
  54. }
  55. /**
  56. * @Title: passWordCryptBySM2_3_4
  57. * @Description: 解析前端传入密文,转译成数据库存储密文,
  58. * 前端加密逻辑要求:密文 = SM2 (明文+SM3 (明文))
  59. * 存入数据库密文要求:密文 = SM4 (明文)
  60. * @param str 前端传入密文
  61. * @return: java.lang.String 数据库存储密文
  62. * @throws
  63. */
  64. public String passWordCryptBySM2_3_4(String str){
  65. //【1】用SM2私钥解密传输过来的密文,得到SM3算法加密后的密文及明文
  66. String privateKey = privatekey;
  67. String mm = SMutil.sm2decrypt(privateKey,str);
  68. //根据标识符切割【0】:SM3算法加密后的密文,【1】明文
  69. String[] mmArr = StringUtil.split(mm,"|");
  70. if(ArrayUtils.isEmpty(mmArr) || mmArr.length != 2){
  71. logger.info("传入密文解密失败:"+ str);
  72. return null;
  73. }
  74. String mw_sm3 = mmArr[0];
  75. String passWord = mmArr[1];
  76. //【2】完整性校验——判断明文与加密后的密文是否相同
  77. if(!SMutil.sm3decrypt(passWord,mw_sm3)){
  78. logger.info("完整性校验失败:"+ mw_sm3);
  79. return null;
  80. }
  81. //【3】SM4加密明文,存入数据库
  82. String mw_sm4 = SMutil.sm4encrypt(passWord);
  83. // System.out.println("传入密文:"+str);
  84. // System.out.println("SM2密钥解密后密文:"+mm);
  85. // System.out.println("SM3加密后密文:"+mw_sm3);
  86. // System.out.println("SM4加密后密文:"+mw_sm4);
  87. // System.out.println("密码:"+passWord);
  88. return mw_sm4;
  89. }
  90. /**
  91. * @Title: accountDecryptBySM2
  92. * @Description: 解析前端传入密文,转译成明文
  93. * 前端加密逻辑要求:密文 = SM2 (明文)
  94. * @param str
  95. * @return: java.lang.String
  96. * @throws
  97. */
  98. public String accountDecryptBySM2(String str){
  99. String privateKey = privatekey;
  100. String mm = SMutil.sm2decrypt(privateKey,str);
  101. if(mm == null){
  102. logger.info("传入密文解密失败:"+ str);
  103. return null;
  104. }
  105. return mm;
  106. }
  107. /**
  108. * @Title: passWordEnryptBySM3
  109. * @Description: 加密密码存入数据库
  110. * 加密要求:密文 = SM3(明文)
  111. * @param str
  112. * @return: java.lang.String
  113. * @throws
  114. */
  115. public String passWordEnryptBySM3(String str){
  116. String mm = SMutil.sm3encrypt(str);
  117. if(mm == null){
  118. logger.info("加密失败:"+ str);
  119. return null;
  120. }
  121. return mm;
  122. }
  123. /**
  124. * @Title: passWordEnryptBySM2
  125. * @Description: 加密密码存入数据库
  126. * 加密要求:密文 = SM2(公钥,明文)
  127. * @param str
  128. * @return
  129. * @throws
  130. */
  131. public String passWordEnryptBySM2(String str) {
  132. String publicKey = ConfigSupport.getProperty("SM2.pubkeyHex", pubkeyHex);
  133. String mm = SMutil.sm2encrypt(publicKey, str);
  134. if(mm == null){
  135. logger.info("加密失败:"+ str);
  136. return null;
  137. }
  138. return mm;
  139. }
  140. /**
  141. * @Title: passWordDecryptBySM2
  142. * @Description: 返回解密后的明文
  143. * 解密要求:明文 = SM2(私钥, 密文)
  144. * @param str
  145. * @return
  146. * @throws
  147. */
  148. public String passWordDecryptBySM2(String str) {
  149. String privateKey = privatekey;
  150. String passWord = SMutil.sm2decrypt(privateKey, str);
  151. if(passWord == null){
  152. logger.info("解密失败:"+ str);
  153. return null;
  154. }
  155. return passWord;
  156. }
  157. public static void main(String[] args) {
  158. String publicKey = ConfigSupport.getProperty("SM2.pubkeyHex", pubkeyHex);
  159. String mm = SMutil.sm2encrypt(publicKey, "111111");
  160. String str2 = "16ebf7bd3f730247ff2df62ddfe30201487c0c0ebbfb0b0326d2212735490287";
  161. System.out.println(SMutil.sm2decrypt("00C1C7D8BF35BA59F4F0B28959EBBB1AAE6606140AAEAC4C379A8D57CCA508D16D", str2));
  162. }
  163. }

所以在java代码层面的加密和解密的代码只需要调用SMHandler这个工具类即可,代码如下:

  1. //加密---begin
  2. if(StringUtil.isNotEmpty(role.getRoleName())){
  3. String name = sMHandler.passWordEnryptBySM2(role.getRoleName());
  4. if(StringUtil.isEmpty(name)){
  5. return new CommResponse(false,"操作失败");
  6. }else{
  7. role.setRoleName(name);
  8. }
  9. }
  10. //加密---end
  11. //解密---begin
  12. if(StringUtil.isNotEmpty(role.getRoleName())){
  13. String name = sMHandler.passWordDecryptBySM2(role.getRoleName());
  14. if(StringUtil.isEmpty(name)){
  15. return new CommResponse(false,"操作失败");
  16. }else{
  17. role.setRoleName(name);
  18. }
  19. }
  20. //解密---end

接下来就是JS层面的加密解密,首先我们先找到sm.js这个文件,在里面写三个function方法,获取公钥私钥和加密解密,当然你也可以自己创建一个新的js文件,代码如下:

  1. function getSm2pubkeyHex() {
  2. var pubkey = '04509AEB08F6645C6AC92B965A5EAA6EE7761908A4AE1454DA537A855F1ADF0D611D45486362D856D7DFB45688EC969B96FD32E5E008FFE9E74E4A424A422DF3AC'
  3. return pubkey;
  4. }
  5. function getSm2prikeyHex() {
  6. var prikey = '24F2401757F59665DED44ECEC08C7314E14F74E95B0720D0FA03E7992440CF1A'
  7. return prikey ;
  8. }
  9. function SMutil()
  10. {
  11. this.sm2encrypt = function(data, publickey){
  12. var msgData = CryptoJS.enc.Utf8.parse(data);
  13. var pubkeyHex = publickey;
  14. if (pubkeyHex.length > 64 * 2) {
  15. pubkeyHex = pubkeyHex.substr(pubkeyHex.length - 64 * 2);
  16. }
  17. var xHex = pubkeyHex.substr(0, 64);
  18. var yHex = pubkeyHex.substr(64);
  19. var cipher = new SM2Cipher("0");
  20. var userKey = cipher.CreatePoint(xHex, yHex);
  21. msgData = cipher.GetWords(msgData.toString());
  22. var encryptData = cipher.Encrypt(userKey, msgData);
  23. return '04' + encryptData;
  24. }
  25. this.sm3encrypt = function(str){
  26. var sm3 = new window.SM3Digest();
  27. str = new SM2Cipher().GetWords(CryptoJS.enc.Utf8.parse(str).toString());
  28. sm3.BlockUpdate(str,0,str.length);
  29. var md = new Array(32);
  30. sm3.DoFinal(md, 0);
  31. var words = [ ];
  32. var j = 0;
  33. for (var i = 0; i < md.length * 2; i += 2) {
  34. words[i >>> 3] |= parseInt(md[j]) << (24 - (i % 8) * 4);
  35. j++;
  36. }
  37. var encryptData = new CryptoJS.lib.WordArray.init(words, md.length).toString();
  38. return encryptData;
  39. }
  40. this.sm2Decrypt = function(privateKey,encrypted) {
  41. encrypted = encrypted.substr(2);
  42. var privKey = new BigInteger(privateKey, 16);
  43. var cipher = new SM2Cipher("0");
  44. var decryptData = cipher.Decrypt(privKey, encrypted);
  45. return decryptData;
  46. }

那我们在js中加密解密方法就只需要调用sm文件里面这个方法即可,代码如下:

  1. //加密---begin
  2. var smutil = new SMutil();
  3. var pubkey = smutil.getSm2pubkeyHex();
  4. smutil.sm2encrypt(str, pubkey);
  5. //加密---end
  6. //解密---begin
  7. var smutil = new SMutil();
  8. var prikey = smutil.getSm2prikeyHex();
  9. smutil.sm2Decrypt(prikey, str);
  10. //解密---end

因为公钥和私钥在前端和后端的一致性,所以前端加密的数据可以在后端解密,后端加密的数据也可以在前端解密。这就是最简单快捷的国密SM2加密解密,当然我的方法中还有sm3和sm2混合加密解密,sm4加密解密,我就不一一介绍了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/702907
推荐阅读
相关标签
  

闽ICP备14008679号