java实现国密加解密

1. pom依赖
 <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15to18</artifactId>
            <version>1.66</version>
        </dependency>
2. SM3封装
package com.yl.encrypt.sm;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

/**
 * SM3算法(类似MD5),不可逆
 * 
 * @author liuxb
 * @date 2021年10月24日 下午8:09:01
 */
public class SM3Util {
	/**
	 * sm3算法加密
	 * @param paramStr  待加密字符串
	 * @return 返回加密后,固定长度=32的16进制字符串
	 */
	public static String encryptHexString(String paramStr) {
		byte[] resultHash = hash(paramStr.getBytes());
		return ByteUtils.toHexString(resultHash);
	}

	/**
	 * 返回长度=32的byte数组
	 * 
	 * @explain 生成对应的hash值
	 * @param srcData
	 * @return
	 */
	private static byte[] hash(byte[] srcData) {
		SM3Digest digest = new SM3Digest();
		digest.update(srcData, 0, srcData.length);
		byte[] hash = new byte[digest.getDigestSize()];
		digest.doFinal(hash, 0);
		return hash;
	}

	/**
	 * 通过密钥进行加密
	 * 
	 * @explain 指定密钥进行加密
	 * @param keyBytes   密钥
	 * @param srcData    被加密的byte数组
	 * @return
	 */
	public static byte[] hashByKey(byte[] keyBytes, byte[] srcData) {
		KeyParameter keyParameter = new KeyParameter(keyBytes);
		SM3Digest digest = new SM3Digest();
		HMac mac = new HMac(digest);
		mac.init(keyParameter);
		mac.update(srcData, 0, srcData.length);
		byte[] result = new byte[mac.getMacSize()];
		mac.doFinal(result, 0);
		return result;
	}

	public static void main(String[] args) {
		String encrypt = encryptHexString("都开始考虑时空裂缝看了看");
		System.out.println(encrypt);
		byte[] SM4_KEY_IV = { 1, 3, 5, 7, 9, 11 };
		byte[] hashByKey = hashByKey(SM4_KEY_IV, "I Love You Every Day".getBytes());
		String hexString = ByteUtils.toHexString(hashByKey);
		System.out.println(hexString);

	}

}

3. SM4封装
package com.yl.encrypt.sm;

import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

/**
 * SM4国密算法工具类
* @author liuxb 
* @date 2021年10月24日 下午7:04:17
 */
public class SM4Util {
	
    /**
     * 初始化算法提供者信息,必须单例
     */
   private static synchronized BouncyCastleProvider getProviderInstance() {
	   BouncyCastleProvider provider = null;
       if(provider == null){
           provider = new BouncyCastleProvider();
       }
       return provider;
   }

    /**
     * 秘钥空间大小
     */
    public static final int SM4_KEY_SIZE = 128;

    /**
     * 默认秘钥空间为128,Key的长度是16
     */
    public static final int SM4_KEY_LENGTH = 16;

    /**
     * 算法编号
     */
    public static final String ALGORITHM_NAME  = "SM4";

    /**
     * ECB模式串
     */
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
    /**
     * CBC模式串
     */
    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";
    
    /**
     * 首次加密初始向量  01030507090B0D0F11131517191B1D1F
     */
    public static final byte[] SM4_KEY_IV = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 };

    /**
     * 生成SM4算法的KEY
     * @return 生成的SM4秘钥
     * @throws Exception
     */
    public static byte[] createSm4Key() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_NAME, getProviderInstance());
        keyGenerator.init(SM4_KEY_SIZE, new SecureRandom());
        return keyGenerator.generateKey().getEncoded();
    }

    /**
     * 处理SM4算法
     * @param algorithmName 算法名称
     * @param mode 加密/解密模式 Cipher.ENCRYPT_MODE 1/ Cipher.DECRYPT_MODE 2
     * @param plainBytes 待加密明文内容/待解密密文
     * @param sm4KeyBytes 秘钥内容
     * @return SM4算法实例
     */
    public static byte[] generateSm4Cipher(String algorithmName, int mode, byte[] plainBytes, byte[] sm4KeyBytes) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, getProviderInstance());
        Key secretKey = new SecretKeySpec(sm4KeyBytes, ALGORITHM_NAME);
        if(algorithmName.contains("ECB")) {
        	cipher.init(mode, secretKey);
        }else {
        	 IvParameterSpec ivParameterSpec = new IvParameterSpec(SM4_KEY_IV);
             cipher.init(mode, secretKey, ivParameterSpec);
        }
        return cipher.doFinal(plainBytes);
    }

    
    public static void main(String[] args) throws Exception {
         byte[] plainText = "I Love You Every Day".getBytes();
         byte[] sm4Key = Hex.decode("64EC7C763AB7BF64E2D75FF83A319918");
         byte[] cipherText = generateSm4Cipher(ALGORITHM_NAME_ECB_PADDING, 1, plainText, sm4Key);
         System.out.println(Hex.toHexString(cipherText));
         // 文本加解密测试.
         byte[] decryptText = generateSm4Cipher(ALGORITHM_NAME_ECB_PADDING, 2, cipherText, sm4Key);
         System.out.println(new String(decryptText));

         //CBC
        byte[] cipherText2 = generateSm4Cipher(ALGORITHM_NAME_CBC_PADDING, 1, plainText, sm4Key);
        System.out.println(Hex.toHexString(cipherText2));
        // 文本加解密测试.
        byte[] decryptText2 = generateSm4Cipher(ALGORITHM_NAME_CBC_PADDING, 2, cipherText2, sm4Key);
        System.out.println(new String(decryptText2));


	}

}

4. SM2封装
package com.cmbchina.encrypt.sm;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;

import java.io.IOException;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

/**
 * 可以加解密,加签验签搞不定
 *
 * @author liuxb
 * @date 2021年10月24日 下午9:14:26
 */
@Slf4j
public class SM2Util {
	/**
	 * 规范默认, 否则影响验签
	 */
	private static final String USER_ID = "1234567812345678";

	/**
	 * 获取椭圆曲线
	 */
	public static synchronized ECDomainParameters getECDomainParameters() {
		ECDomainParameters domainParameters = null;
		X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
		if (domainParameters == null) {
			domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
		}
		return domainParameters;
	}

	/**
	 * 获取公钥私钥对
	 * @return
	 */
	public static Map<String, String> createKeyPair() {
		Map<String, String> map = new HashMap<String, String>();
		try {
			// 生成密钥对
			ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
			keyPairGenerator.init(new ECKeyGenerationParameters(getECDomainParameters(), SecureRandom.getInstance("SHA1PRNG")));
			AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
			BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
			ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();

			map.put("privateKey", ByteUtils.toHexString(privatekey.toByteArray()));
			// 把公钥放入map中,默认压缩公钥
			// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
			map.put("publicKey", ByteUtils.toHexString(ecPoint.getEncoded(false)));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 加密
	 * @param msg  字节数组
	 * @param publicKey
	 * @param modeType  1 标准 2 BC模式
	 * @return
	 * @throws IOException
	 */
	public static String encrypt(byte[] msg, String publicKey, int modeType) throws IOException {
		//加密模式
		SM2Engine.Mode mode;
		if (modeType == 1) {
			mode = SM2Engine.Mode.C1C3C2;
		} else {
			mode = SM2Engine.Mode.C1C2C3;
		}
		ECDomainParameters domainParameters = getECDomainParameters();
		//提取公钥点
		ECPoint pukPoint = domainParameters.getCurve().decodePoint(ByteUtils.fromHexString(publicKey));
		// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
		ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

		SM2Engine sm2Engine = new SM2Engine(mode);
		sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
		byte[] arrayOfBytes = null;
		try {
			arrayOfBytes = sm2Engine.processBlock(msg, 0, msg.length);
		} catch (Exception e) {
			log.error("SM2加密时出现异常:", e);
		}
		return ByteUtils.toHexString(arrayOfBytes);

	}

	/**
	 *
	 * @param cipherDataByte 密文字节数组
	 * @param privateKeyHex
	 * @param modeType  1 标准 2 BC模式
	 * @return
	 * @throws InvalidCipherTextException
	 */
	public static String decrypt(byte[] cipherDataByte, String privateKeyHex, int modeType) throws InvalidCipherTextException {
		//解密模式
		SM2Engine.Mode mode;
		if (modeType == 1) {
			mode = SM2Engine.Mode.C1C3C2;
		} else {
			mode = SM2Engine.Mode.C1C2C3;
		}
		BigInteger privateKeyD = new BigInteger(privateKeyHex, 16);
		ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, getECDomainParameters());

		SM2Engine sm2Engine = new SM2Engine(mode);
		sm2Engine.init(false, privateKeyParameters);
		try {
			byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
			return new String(arrayOfBytes, "utf-8");
		} catch (Exception e) {
			log.error("SM2解密时出现异常:", e);
		}
		return null;
	}
	/**
	 * 初始化算法提供者信息,必须单例
	 */
	private static synchronized BouncyCastleProvider getProviderInstance() {
		BouncyCastleProvider provider = null;
		if(provider == null){
			provider = new BouncyCastleProvider();
		}
		return provider;
	}

	public static void main(String[] args) throws Exception {
//		Map<String, String> createKeyPair = createKeyPair();
//		System.out.println(createKeyPair);
		String privateKeyHex = "6ab376dea8a49f57b98639fff3d80bf380014b38403224c4b62b752f3aaf74fa";
		String publicKey = "045c3a43e62d68bdff904bb6ce62b8acf50ca9ed6a80af22f9a78a6f2b6a4e0c57774d8eb9a05af7d3494afb0ff698c3f87000ae824c482402754d531222eadff1";
		String text = "微微儿";
		String encrypt = encrypt(text.getBytes(), publicKey, 1);
		System.out.println(encrypt);
		String decrypt = decrypt(Hex.decode(encrypt), privateKeyHex, 1);
		System.out.println(decrypt);
	}
}

5. vue版本实现
https://gitee.com/bestman_456/sm2_sm3_sm4.git, vue版本和java版本,前后端完美匹配
  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值