国密SM2,SM3,SM4的前后台(js和java)加解密写法

目录

  • SM2加解密
    • js
    • java
  • SM3加密
    • js
    • java
    • sm3前后台(js/java)加密不一致原因
  • SM4加解密
    • js
    • java

之前做一个项目的时候需要用到国密SM2,SM3,SM4的加解密方法,网上搜到的方法存在一些问题,例如sm2的前台解密方法没有找到,sm3相同参数前后台加密不一致等。写个文章记录总结一下,给后来的朋友提供一点帮助。

SM2加解密

js

/**
 * sm2加密方法
 */
function encodepwdSM2(username){
	var pubkeyHex ="*********";//密钥
    var msgData =CryptoJS.enc.Utf8.parse(username);
    if (pubkeyHex.length > 130) {
        pubkeyHex = pubkeyHex.substr(pubkeyHex.length - 130);
    }
	var cipherMode = "0";//加密方式 1:c1c3c2,2:c1c2c3
    var cipher = new SM2Cipher(cipherMode);
    var userKey = cipher.CreatePoint(pubkeyHex);
	msgData = cipher.str2Bytes(msgData.toString());
    var encryptData = cipher.Encrypt(userKey, msgData);
    return encryptData;
}
/**
 *sm2解密方法
 */
function decodepwdSM2(username){
	var privateKey = "**************";//密钥
	var msgData =CryptoJS.enc.Utf8.parse(username);
    if (privateKey.length > 130) {
    	privateKey = privateKey.substr(privateKey.length - 130);
    }
	var cipherMode = "0";//加密方式 1:c1c3c2,2:c1c2c3
    var cipher = new SM2Cipher(cipherMode);
    var userKey = new BigInteger(privateKey, 16);
	msgData = username;
    var decryptData = cipher.Decrypt(userKey, msgData);
    return decryptData;
}

java

/**
 * sm2加密方法
 */
  public static String encrypt(byte[] publicKey, byte[] data)
    throws IOException
  {
    if ((publicKey == null) || (publicKey.length == 0))
    {
      return null;
    }

    if ((data == null) || (data.length == 0))
    {
      return null;
    }

    byte[] source = new byte[data.length];
    System.arraycopy(data, 0, source, 0, data.length);

    Cipher cipher = new Cipher();
    SM2 sm2 = SM2.Instance();
    ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

    ECPoint c1 = cipher.Init_enc(sm2, userKey);
    cipher.Encrypt(source);
    byte[] c3 = new byte[32];
    cipher.Dofinal(c3);

    return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);
  }
/**
 * sm2解密方法
 */
  public static String decrypt(String pk, String encryptedDataParam)
    throws IOException
  {
    if ((pk == null) || (pk.length() == 0))
    {
      return null;
    }

    if ((encryptedDataParam == null) || (encryptedDataParam.length() == 0))
    {
      return null;
    }

    byte[] privateKey = Util.hexToByte(pk);
    byte[] encryptedData = Util.hexToByte(encryptedDataParam);

    String data = Util.byteToHex(encryptedData);

    byte[] c1Bytes = Util.hexToByte(data.substring(0, 130));
    int c2Len = encryptedData.length - 97;
    byte[] c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len));
    byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));

    SM2 sm2 = SM2.Instance();
    BigInteger userD = new BigInteger(1, privateKey);

    ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
    Cipher cipher = new Cipher();
    cipher.Init_dec(userD, c1);
    cipher.Decrypt(c2);
    cipher.Dofinal(c3);

    return new String(c2);
  }

SM3加密

js

/**
 * sm3加密方法
 */
function encodepwdSM3(msg){
	var msgData = CryptoJS.enc.Utf8.parse(msg);
	var sm3keycur = new SM3Digest();
	msgData = sm3keycur.GetWords(msgData.toString());
	sm3keycur.BlockUpdate(msgData, 0, msgData.length);
	var c3 = new Array(32);
	sm3keycur.DoFinal(c3, 0);
	//解决sm3相同参数前后台加密不一致的问题
	for(var i = 0,len = c3.length; i < len; i++){
		if(256 == c3[i]){
			c3[i]=0;
		}
	}
	var hashHex = sm3keycur.GetHex(c3).toString();
	return hashHex;
}

java

import org.bouncycastle.util.encoders.Hex;

public class SM3Utils
{
  public String encrypt(String msg)
  {
    byte[] md3 = new byte[32];
    byte[] msg3 = msg.getBytes();
    SM3Digest sm3 = new SM3Digest();
    sm3.update(msg3, 0, msg3.length);
    sm3.doFinal(md3, 0);
    String s3 = new String(Hex.encode(md3));
    return s3;
  }
}

sm3前后台(js/java)加密不一致原因

经过比对加密过程每一步的数据,发现加密完之后获得的byte[]不一致,后台数组中每个元素在[-128,127]之间,前台在[1,256]之间,相当前台于将后台的负数通过+256的形式转换为正数,但把0也转换成了256,导致讲byte[]转换为String格式之后不一致,只需要将前台byte[]中的256替换回0即可。

SM4加解密

js

/**
 * sm4加密方法
 */
function encodepwdSM4(username){
	//sm4加密数字时会出问题,所以先将数字转换为字符串
	var type=typeof(username);
	if(type=="number"){
		username=username+"";
	}
    var  sm4 = new SM4Util();
    var encryptData=sm4.encryptData_ECB(username);
    return encryptData;
}
/**
*sm4解密
*/
function decodepwd(username){
    var  sm4 = new SM4Util();
    var encryptData=sm4.decryptData_ECB(username);;
    return encryptData;
}

java

	 /**
     * sm4加密
     */
    public String encryptData_ECB(String plainText)
    {
        try 
        {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;
            
            byte[] keyBytes;
            keyBytes = aqzj.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("UTF-8"));
            String cipherText = new BASE64Encoder().encode(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0)
            {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
            return null;
        }
    }
     /**
     * sm4解密
     */
    public String decryptData_ECB(String cipherText)
    {
        try 
        {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;
            
            byte[] keyBytes;
            keyBytes = aqzj.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, new BASE64Decoder().decodeBuffer(cipherText));
            return new String(decrypted, "UTF-8");
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
            return null;
        }
    }

你可能感兴趣的:(国密SM2,SM3,SM4的前后台(js和java)加解密写法)