java加密使用

news2025/1/12 17:49:59

加解密

  • 概念
    • 算法分类
      • 对称加解密算法
      • 非对称加解密算法
      • 信息摘要算法
    • 数字签名和消息验签
      • 数字签名过程
      • 消息验签过程
      • 数字签名分类
    • AES使用
      • 生成秘钥
      • 使用秘钥加解密
    • RSA使用
      • 生成公私钥
      • 加密、加签、验签、解密
    • SM2使用
      • 将公钥和私钥证书文件转化为字符串存储

概念

算法分类

对称加解密算法

加密和解密使用相同的秘钥,常见算法有DES、TDES、AES、SM4、RC2/4
在这里插入图片描述

非对称加解密算法

加密和解密使用不同的秘钥,公钥加密私钥解密,私钥加密公钥解密。常见算法有RSA、SM2、ECC

信息摘要算法

类似于hash,不可逆。常见的信息摘要算法有:MD2/4/5、SHA1/SHA224/SHA256/SHA384、SM3算法、MAC算法等
在这里插入图片描述

数字签名和消息验签

【数字签名】主要解决了两个核心问题:发送的消息是完整的,未被篡改的;接收的消息一定就是对应发送者发送的,别人无法仿制。前者体现的是数据的完整性,后者体现的是数据的不可抵赖性

数字签名过程

数字签名的应用公式如下所示,其中M表示消息原文,S表示数字签名,P表示非对称算法的私钥运算,D表示信息摘要算法的运算。

P(D(M [with any length])) = S [with fixed length]

具体来说,发送方产生一个数据签名,需要经过以下几个步骤:

  • 使用【信息摘要算法】,对任意长度的信息原文做摘要运算,得到一段固定长度的摘要数据;
  • 如果该摘要数据的长度,没有达到非对称加密算法做加解密运算的输入长度,通常还需要使用填充 标准对摘要数据进行必要的填充,以达到非对称算法的运算条件;常用的填充标准有PKCS1-padding;
  • 使用【非对称加密算法】的私钥对填充后的摘要数据做加密运算,得到一段固定长度的数字签名;
  • 发送方将数字签名拼接在信息原文的尾部,一同发送给接收方,完成数据的单方向传输。

经过以上的步骤后,发送方就成功将信息原文和对应的数字签名,传递给了接收方;剩余的事,就是接收方对数据的验签操作。

消息验签过程

接收方收到发送方发送的数据报文(信息原文+数字签名)后,需要经历以下步骤来完成对报文消息的验签操作:

  • 首先,对数据报文进行分解,提取出信息原文部分和数字签名部分;

  • 与产生数字签名流程一样,使用相同的信息摘要算法对信息原文做摘要运算,得出消息原文的摘要D1;

  • 与产生数字签名流程相反,使用【非对称加密算法】中签名私钥对应的公钥对数字签名部分做解密 运算,解密后得到原始发送方发送的经填充后的摘要D2;
    与产生数字签名流程相反,使用相同的数据填充标准对摘要D2做去填充操作,得到原始消息的附带的摘要D3;

  • 比较D3和D1;如果两者相等,则表示对数字签名的验签是OK的,消息原文的数据是可信任的;反之,若D3不等于D1,则可以认为消息原文是不可信任的,数字签名中的【完整性】和【不可抵赖性】可能遭到了破坏;我们应该摒弃信息原文。

数字签名分类

数字签名算法,就是使用RSA、MD5、SM2、SHA、SM3等非对称算法和信息摘要算法进行混搭组合。数字签名算法的基本表示格式为:xxxWithYYYEncryption,其中xxx表示信息摘要算法,yyy表示非对称加密算法。常见有的以下几种:

  1. md5WithRSAEncryption:摘要运算采用MD5,非对称算法使用RSA;
  2. sha1WithRSAEncryption:摘要运算采用SHA1,非对称算法使用RSA;
  3. sha256WithRSAEncryption:摘要运算采用SHA256,非对称算法使用RSA;【常用】
  4. sm3WithSM2Encryption:摘要运算采用SM3,非对称算法使用SM2。

AES使用

生成秘钥

private static SecretKey generateKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128); // 秘钥长度为 128 位
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey;
    }

    /**
     * 二进制byte[]转十六进制string
     */
    public static String byteToHexString(byte[] bytes){
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String strHex=Integer.toHexString(bytes[i]);
            if(strHex.length() > 3){
                sb.append(strHex.substring(6));
            } else {
                if(strHex.length() < 2){
                    sb.append("0" + strHex);
                } else {
                    sb.append(strHex);
                }
            }
        }
        return  sb.toString();
    }

 public static void main(String[] args) {
	SecretKey secretKey = generateKey();
	System.out.println(byteToHexString(secretKey.getEncoded()));
	// b30957dc3e032f462866c917ff461088
}

使用秘钥加解密

// 使用hutool工具类
 String aesKey = "b30957dc3e032f462866c917ff461088";
 AES aes = SecureUtil.aes(aesKey.getBytes());
// 加密 encrpy = 9OqWLbnVeW/EsL6nevQfZQ==
 String encrypt = aes.encryptBase64("你好");
// 解密 decrypt = 你好
String decrypt = aes.decryptStr(encrypt);

RSA使用

生成公私钥

public static void genKeyPair() {
        try {
            // 生成RSA密钥对
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024); // 设置密钥长度
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            // 获取公钥和私钥
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            String publicKeyStr = encoder.encodeToString(publicKey.getEncoded());
            String privateKeyStr = encoder.encodeToString(privateKey.getEncoded());
            // 打印公钥和私钥
            System.out.println("公钥: " + publicKeyStr);
            System.out.println("私钥: " + privateKeyStr);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpG4FQWx7NMG8DQF1VJNegLBxtsyGjvQGdoMDl0mXnZT7eU+DrJ0G5nKdKI+CWr+1tvSR/1dIblYsJK+M1cotSjUN9l4qraxnFha5Js1ldfxcTlJuWOBgWAWVJ+C3hZGkzAo8F+0CCtwij9dpLd+5kbHpdBd9Vh3V0WgiBY2M3nQIDAQAB
私钥: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKkbgVBbHs0wbwNAXVUk16AsHG2zIaO9AZ2gwOXSZedlPt5T4OsnQbmcp0oj4Jav7W29JH/V0huViwkr4zVyi1KNQ32XiqtrGcWFrkmzWV1/FxOUm5Y4GBYBZUn4LeFkaTMCjwX7QIK3CKP12kt37mRsel0F31WHdXRaCIFjYzedAgMBAAECgYBOwnOwtC+dSzB46DJP5G/Utpaq9OH2+6FUA7mzkBFL+xiTvackfk0bIH29hwYjyF4hXRUxwKkxla2CoQEaNHX0Q6MX8LxdbEGzHypLuaB+gNQSbWT41AVLB+GmikLc6yaNKAbr6/rdGWCIYVzzf4XuH8FI4d0Zr2HV7vBeBCeV9QJBANu9LkT7+8VRI8fq/XE9gsMPQSO5gBqBprPvag32wwiP3Hsv/9BYs7BbvQASijgqzuoC74YJioPi66kyWS8XFjcCQQDFA2hCQjYHd6rzkjWBL707+scl4ddfIccl1YBE2fyM2djXzZEVkgqW4NILIZC3nMEvGoBiympdelnq7n0LQzbLAkEAwCosaZW4M3HnCbFenQZ+8VjIzZYvCn8xqxAHvlh7bWRqG6z5WVoJIoTHv2V3TPFa7FlO4Pg9E2OCVgA68CyPdwJAK9OVNuApysF5OxP0aReonhYshSXXVmdaOPVkwmxHvUGc9mzZcJX7WxMKRsWhvubVJthbZR6oSME2DYgeMwoxvwJAaxrWhkBVde5L1/nFaN19Yb4w82/z+lmjd2itjLybhe62Z1HqS86pc4rZKOaoegBeHT0omcCBMnGxYnYlYlgWpg==

加密、加签、验签、解密

package com.echo.java8.encipher;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;

/**
 * RSA签名,加解密处理核心文件,注意:密钥长度1024
 */
public class RSAHelper {
    @SuppressWarnings("unused")
    private static Logger LOGGER = LoggerFactory.getLogger(RSAHelper.class);

    /*
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
    /*
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";
    /*
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /*
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    public static void genKeyPair() {
        try {
            // 生成RSA密钥对
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024); // 设置密钥长度
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            // 获取公钥和私钥
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            String publicKeyStr = encoder.encodeToString(publicKey.getEncoded());
            String privateKeyStr = encoder.encodeToString(privateKey.getEncoded());
            // 打印公钥和私钥
            System.out.println("公钥: " + publicKeyStr);
            System.out.println("私钥: " + privateKeyStr);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    /**
     * 签名字符串
     *
     * @param text       需要签名的字符串
     * @param privateKey 私钥(BASE64编码)
     * @param charset    编码格式
     * @return 签名结果(BASE64编码)
     * @throws Exception
     */
    public static String sign(String text, String privateKey, String charset) throws Exception {
        return sign(text, privateKey, charset, SIGNATURE_ALGORITHM);
    }

    public static String sign(String text, String privateKey, String charset,
                              String signatureAlgorithm) throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(signatureAlgorithm);
            signature.initSign(privateK);
            signature.update(getContentBytes(text, charset));
            return Base64Utils.encodeToString(signature.sign());
        } catch (Exception e) {
            throw new Exception("RSA sign exception:" + e.getMessage());
        }
    }


    /**
     * 验签字符串
     *
     * @param text      需要签名的字符串
     * @param sign      客户签名结果
     * @param publicKey 公钥(BASE64编码)
     * @param charset   编码格式
     * @return 验签结果
     * @throws Exception
     */
    public static boolean verify(String text, String sign, String publicKey, String charset) throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicK = keyFactory.generatePublic(keySpec);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(publicK);
            signature.update(getContentBytes(text, charset));
            return signature.verify(Base64Utils.decodeFromString(sign));
        } catch (Exception e) {
            LOGGER.warn("RSA verify exception", e);
            throw new Exception("RSA verify exception:" + e.getMessage());
        }
    }

    /**
     * <P>
     * 私钥解密
     * </p>
     *
     * @param encryptedData 已加密数据
     * @param privateKey    私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;

    }
    public static String decryptByPublicKey(String encryptedData, String publicKey) throws Exception {
        byte[] bytes = decryptByPublicKey(Base64Utils.decodeFromString(encryptedData), publicKey);
        return new String(bytes);
    }
    /**
     * <p>
     * 公钥解密
     * </p>
     *
     * @param encryptedData 已加密数据
     * @param publicKey     公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }
    
    /**
     * <p>
     * 公钥加密
     * </p>
     *
     * @param data      源数据
     * @param publicKey 公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey, String cipherArgs) throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = null;
        if (Objects.isNull(cipherArgs)) {
            cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        } else {
            cipher = Cipher.getInstance(cipherArgs);
        }
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;

    }


    /**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data       源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;

    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }


    public static void main(String[] args) throws Exception {
        String text = "hello";
//        rsaKeyGenerate("test");
        String publicKeyStr = " MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLSTLXzr70geYHPD8uSLj8it7LvdZRz4hhYPHPQ6MvdJ9mLuooiXtXEwOgTWAIWtXXWL2EYoIo/AhaE3B91hpkIsXtdlotaMJSLv3vilZnd6nLISJXQiWJ7IKOShAByXJFGr8aT+blTQOwYUayKKXycXL1Sg1KINjJSiNKfZF+KwIDAQAB";
        String privateKeyStr = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAItJMtfOvvSB5gc8Py5IuPyK3su91lHPiGFg8c9Doy90n2Yu6iiJe1cTA6BNYAha1ddYvYRigij8CFoTcH3WGmQixe12Wi1owlIu/e+KVmd3qcshIldCJYnsgo5KEAHJckUavxpP5uVNA7BhRrIopfJxcvVKDUog2MlKI0p9kX4rAgMBAAECgYB7YDxEAqMMq99Yu1nvooURVeUhracg0maocxneELiEeZYUCixp+dWh/HqyzLbqz6MpXDaLBELtEMpJF30GSdcXWh+/9kN7IeWnlTZxmpc4FxeQydCGOJdgLv+GsR0ulYp4vH8L5cEDy6TZ4C7AHRv8KZOzrwBkZSTL1UayzIDncQJBAM267L4Tz51G/pxXsxjzMfM1mzgr/SvsWlj5OpwECYm7s2kGVxrVtdsCMj2rSYbjrR0TCZe7cKIXRR0lARIxTikCQQCtUfnBqoFHny5twGD/HlvDYoalnxxCYJJg+mBdR5s5ElMzkpjuKRWrvxTeroY+vPpL+7RHSU0qNCpXTvqmDQwzAkAVU817Hv6k5Vk7x/OvIHcLKYF/3z+NsCDlnGCxD9IVTzoYJyochA8oNyASOJGUxEGMBA84hZv1kcf+b3me8zGRAkBrC89jAskYEEOfu4rs5rYsRcT9s/jDMlwWE23DDv/azuueVbOonK1qxvi/1DDLvPImTc55nNdQ8qkYBYqfVj2rAkAnHEKLtgxWXreWRAbujoMgLOR2AEUyG7Vbw+0s/JPSU04DGex3Wj6/+bJQdejAiXUTJSTJjE69aHKwPKBx3fBN";

        byte[] bytes = encryptByPrivateKey(text.getBytes("UTF-8"), privateKeyStr);
        String s = Base64Utils.encodeToString(bytes);
        System.out.println("s:"+s);
        String sign = sign(s, privateKeyStr, "UTF-8");
        System.out.println(sign);
        System.out.println(verify(s, sign, publicKeyStr, "UTF-8"));


        System.out.println(decryptByPublicKey(s, publicKeyStr));
    }
}

SM2使用

openssl生成RSA证书对,证书生成参考 密码:zsqq

将公钥和私钥证书文件转化为字符串存储

	// 将公钥文件转化为字符串
   public static String parsePubStr( String publicFile) throws Exception {
        InputStream is = new FileInputStream(publicFile);
        CertificateFactory cf = CertificateFactory.getInstance("x509");
        X509Certificate cerCert = (X509Certificate) cf.generateCertificate(is);
        // 生成PublicKey
        PublicKey publicKey = cerCert.getPublicKey();
        BASE64Encoder base64Encoder = new BASE64Encoder();
        String publicKeyString = base64Encoder.encode(publicKey.getEncoded());
        return publicKeyString;
    }
  // 将私钥文件转化为字符串
  public static String parsePriStr( String privateFile) throws Exception {
        InputStream is = new FileInputStream(privateFile);
        KeyStore tKeyStore = KeyStore.getInstance("PKCS12");
        tKeyStore.load(is, "ht123456".toCharArray());
        Enumeration e = tKeyStore.aliases();
        String tAliases = null;
        while (e.hasMoreElements()) {
            tAliases = (String) e.nextElement();
            break;
        }
        PrivateKey privateKey = (PrivateKey) tKeyStore.getKey(tAliases, "ht123456".toCharArray());
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(privateKey.getEncoded());
        return s;
    }

加密、加签、验签、解密

package com.echo.java8.encipher;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECFieldFp;
import java.security.spec.EllipticCurve;


/**
 * @description:
 * @author: echo
 * @Date: 2023/10/10 11:02
 * @Version: 1.0.0
 */
@Slf4j
public class SmUtils {
    // 添加 Bouncy Castle 提供者
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 以下为SM2推荐曲线参数
     */
    public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
    public static final BigInteger SM2_ECC_P = CURVE.getQ();
    public static final BigInteger SM2_ECC_A = CURVE.getA().toBigInteger();
    public static final BigInteger SM2_ECC_B = CURVE.getB().toBigInteger();
    public static final BigInteger SM2_ECC_N = CURVE.getOrder();
    public static final BigInteger SM2_ECC_H = CURVE.getCofactor();
    public static final BigInteger SM2_ECC_GX = new BigInteger(
            "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
    public static final BigInteger SM2_ECC_GY = new BigInteger(
            "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
    public static final org.bouncycastle.math.ec.ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
    public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
            SM2_ECC_N, SM2_ECC_H);

    public static final EllipticCurve JDK_CURVE = new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B);
    public static final java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint(
            G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger());
    public static final java.security.spec.ECParameterSpec JDK_EC_SPEC = new java.security.spec.ECParameterSpec(
            JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue());
    public static final String SM3_SM2 = "SM3withSM2";
    private static String encoding = "GBK";
    private static final String BC = "BC";

    /**
     * 字符串转PublicKey
     * @param publicString
     * @return
     */
    public static BCECPublicKey stringToPublic(String publicString) {
        try {
            String publicKeyHex = ByteUtils.toHexString(Base64.decode(publicString.getBytes(StandardCharsets.UTF_8)));
            BouncyCastleProvider provider = new BouncyCastleProvider();
            // 椭圆曲线参数规格
            ECParameterSpec ecParameterSpec = new ECParameterSpec(CURVE, G_POINT,
                    SM2_ECC_N, SM2_ECC_H);
            // 将私钥HEX字符串转换为X值
            BigInteger bigInteger = new BigInteger(publicKeyHex, 16);
            // 将公钥HEX字符串转换为椭圆曲线对应的点
            ECPoint ecPoint = CURVE.decodePoint(bigInteger.toByteArray());
            // 获取椭圆曲线KEY生成器
            KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
            // 将椭圆曲线点转为公钥KEY对象
            return (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException("字符串转公钥失败");
        }
    }

    /**
     * 字符串转PrivateKey
     * @param privateString
     * @return
     */
    public static BCECPrivateKey stringToPrivate(String privateString) {
        try {
            String privateHex = ByteUtils.toHexString(Base64.decode(privateString.getBytes(StandardCharsets.UTF_8)));
            BouncyCastleProvider provider = new BouncyCastleProvider();
            BigInteger bigInteger = new BigInteger(privateHex, 16);
            // 将X值转为私钥KEY对象
            KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
            return (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, new ECParameterSpec(CURVE, G_POINT, SM2_ECC_N)));
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException("字符串转私钥失败");
        }
    }

    private static String encrypt(String data, String publicKeyString) {
        BCECPublicKey bcecPublicKey = stringToPublic(publicKeyString);
        ECPublicKeyParameters pubKeyParameters = convertPublicKeyToParameters(bcecPublicKey);
        SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
        ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());

        engine.init(true, pwr);
        try {
            return Base64.encode(engine.processBlock(data.getBytes(), 0, data.getBytes().length));
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException("加密失败");
        }
    }

    private static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
        ECParameterSpec parameterSpec = ecPubKey.getParameters();
        ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
                parameterSpec.getN(), parameterSpec.getH());
        return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters);
    }

    private static String signSm3WithSm2(String privateKeyString, String data) {
        try {
            PrivateKey privateKey = stringToPrivate(privateKeyString);
            Signature signature = Signature.getInstance(SM3_SM2, BC);
            signature.initSign(privateKey);
            signature.update(data.getBytes(encoding));
            byte signed[] = signature.sign();
            byte sign_asc[] = new byte[signed.length * 2];
            hex2Ascii(signed.length, signed, sign_asc);
            return new String(sign_asc);
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException("加签失败");
        }
    }

    public static boolean verifySign(String publicKeyString,String signedStr,String data) throws Exception{
        BCECPublicKey bcecPublicKey = stringToPublic(publicKeyString);
        Signature signature = Signature.getInstance(SM3_SM2, BC);
        signature.initVerify(bcecPublicKey);
        byte signedData[] = new byte[signedStr.length() / 2];
        ascii2Hex(signedStr.length(), signedStr.getBytes(encoding), signedData);
        signature.update(data.getBytes(encoding));
        return signature.verify(signedData);
    }

    public static String decrypt(String encryptData, String privateString) {
        BCECPrivateKey privateKey = stringToPrivate(privateString);
        byte[] decode = Base64.decode(encryptData.getBytes());
        ECPrivateKeyParameters priKeyParameters = convertPrivateKeyToParameters(privateKey);
        SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
        engine.init(false, priKeyParameters);
        try {
            return new String(engine.processBlock(decode, 0, decode.length));
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException("解密失败");
        }
    }

    private static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
        ECParameterSpec parameterSpec = ecPriKey.getParameters();
        ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
                parameterSpec.getN(), parameterSpec.getH());
        return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
    }



    /**
     * 将十六进制数据转换成ASCII字符串
     *
     * @param len      十六进制数据长度
     * @param data_in  待转换的十六进制数据
     * @param data_out 已转换的ASCII字符串
     */
    private static void hex2Ascii(int len, byte data_in[], byte data_out[]) {
        byte temp1[] = new byte[1];
        byte temp2[] = new byte[1];
        for (int i = 0, j = 0; i < len; i++) {
            temp1[0] = data_in[i];
            temp1[0] = (byte) (temp1[0] >>> 4);
            temp1[0] = (byte) (temp1[0] & 0x0f);
            temp2[0] = data_in[i];
            temp2[0] = (byte) (temp2[0] & 0x0f);
            if (temp1[0] >= 0x00 && temp1[0] <= 0x09) {
                (data_out[j]) = (byte) (temp1[0] + '0');
            } else if (temp1[0] >= 0x0a && temp1[0] <= 0x0f) {
                (data_out[j]) = (byte) (temp1[0] + 0x57);
            }
            if (temp2[0] >= 0x00 && temp2[0] <= 0x09) {
                (data_out[j + 1]) = (byte) (temp2[0] + '0');
            } else if (temp2[0] >= 0x0a && temp2[0] <= 0x0f) {
                (data_out[j + 1]) = (byte) (temp2[0] + 0x57);
            }
            j += 2;
        }
    }

    /**
     * 将ASCII字符串转换成十六进制数据
     *
     * @param len      ASCII字符串长度
     * @param data_in  待转换的ASCII字符串
     * @param data_out 已转换的十六进制数据
     */
    private static void ascii2Hex(int len, byte data_in[], byte data_out[]) {
        byte[] temp1 = new byte[1];
        byte[] temp2 = new byte[1];
        for (int i = 0, j = 0; i < len; j++) {
            temp1[0] = data_in[i];
            temp2[0] = data_in[i + 1];
            if (temp1[0] >= '0' && temp1[0] <= '9') {
                temp1[0] -= '0';
                temp1[0] = (byte) (temp1[0] << 4);
                temp1[0] = (byte) (temp1[0] & 0xf0);
            } else if (temp1[0] >= 'a' && temp1[0] <= 'f') {
                temp1[0] -= 0x57;
                temp1[0] = (byte) (temp1[0] << 4);
                temp1[0] = (byte) (temp1[0] & 0xf0);
            }
            if (temp2[0] >= '0' && temp2[0] <= '9') {
                temp2[0] -= '0';
                temp2[0] = (byte) (temp2[0] & 0x0f);
            } else if (temp2[0] >= 'a' && temp2[0] <= 'f') {
                temp2[0] -= 0x57;
                temp2[0] = (byte) (temp2[0] & 0x0f);
            }
            data_out[j] = (byte) (temp1[0] | temp2[0]);
            i += 2;
        }
    }

    public static void main(String[] args) throws Exception {
        String publicKeyString = "BM6zmWApBExWzuVezdk3QwdE8PTzUBW/6JadWgAbq0XYNzcQcefZmknBZW0Cvo5GvMjDJeOUYYKuyzELNOCNfPQ=";
        String privateKeyString = "AKELqaUjpIrFu3S5xRhWZ1BIXnSosZQ+vKCjzQ47pJJT";

        String dataStr = "张晓慧";
        // 加密
        String encrypt = encrypt(dataStr, publicKeyString);
        System.out.println("加密后数据:"+encrypt);
        String decrypt = decrypt(encrypt, privateKeyString);
        System.out.println("机密后数据:"+decrypt);
        // 加签
        String sign = signSm3WithSm2(privateKeyString, encrypt);
        System.out.println("加密后数据加签:"+sign);
        // 验签
        boolean verifySign = verifySign(publicKeyString, sign, encrypt);
        System.out.println("是否验签成功:"+verifySign);
        
        // 打印数据
//        加密后数据:BLmEbT49DDfVT5IHvRcP+4yTGfLSfSbSo1U0hgUuKLWKYS6zkpIvaAurNSNG9KrfqXZInZJDUqw6W2jN82nJwcPbzECtaBmkgvXjaPRq5pG/kjBqfonSEF+hU7CUuRq0RdB39aP1Srl82g==
//                机密后数据:张晓慧
//        加密后数据加签:304502207c01cc3feef31f4a8b0ea1c5b9f45464e6ab6cd02dae6225f9d4c9ec0a4ddffc022100df39ee367d893d774f8529412698fd60c13bb1f5d97f85dbf62122a9a1d87f50
//        是否验签成功:true
    }
}

参考文档:https://blog.csdn.net/rtthreadiotos/article/details/121033533

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1076140.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt编程-QTableView冻结行或冻结列或冻结局部单元格

前言 Qt编程-QTableView冻结行或冻结列或冻结局部单元格。如题&#xff0c;先看效果是不是你需要的。网上找到的代码片段要么不全要么不是想要的。如果你需要同时冻结行和列的效果&#xff0c;请看下篇博客 Qt编程-QTableView同时冻结行和列。 冻结列&#xff1a; 冻结行&a…

[stm32]外中断控制灯光

在STM32CubeMX中配置外部中断功能和参数 1、将上拉输入的引脚设置为&#xff1a;GPIO_EXTI功能 2、GPIO模式设为下降沿触发外部中断&#xff0c;使能上拉电阻&#xff0c;用户标签 3、要将NVIC的相关中断勾选 只有将中断源进行勾选&#xff0c;相关的中断请求才能得到内核的…

华为云云耀云服务器L实例评测|企业项目最佳实践之云服务器介绍(一)

华为云云耀云服务器L实例评测&#xff5c;企业项目最佳实践系列&#xff1a; 华为云云耀云服务器L实例评测&#xff5c;企业项目最佳实践之云服务器介绍(一) 华为云云耀云服务器L实例评测&#xff5c;企业项目最佳实践之华为云介绍(二) 华为云云耀云服务器L实例评测&#xff5…

Hudi第三章:集成Flink

系列文章目录 Hudi第一章&#xff1a;编译安装 Hudi第二章&#xff1a;集成Spark Hudi第二章&#xff1a;集成Spark(二) Hudi第三章&#xff1a;集成Flink 文章目录 系列文章目录前言一、环境准备1.上传并解压2.修改配置文件3.拷贝jar包4.启动sql-client1.启动hadoop2.启动ses…

2023年中国助消化药物行业现状分析:消化不良患者逐年上升,提升需求量[图]

助消化药物主要分为促胃动力药物、消化酶抑制剂、胃酸抑制药物和消食剂4种类型。促胃动力药物的作用机制是通过增强胃肠道平滑肌动力促进胃酸分泌&#xff0c;从而达到助消化的目的&#xff0c;临床常用药物包括多潘立酮、莫沙必利、西沙比利等。 助消化药物分类 资料来源&…

SI314兼容替代 GTX314L—低功耗14通道电容触摸传感器芯片 应用智能门锁

1.介绍 Si314是一款具有自动灵敏度校准功能的14通道电容传感器&#xff0c;其工作电压范围为1.8~5.5v.Si314设置休眠模式来节省功耗&#xff0c;此时&#xff0c;功耗电流为10uA3. 3V。 Si314各个感应通道可实现独立使能、校准、灵敏度调节&#xff0c;可以确保可靠性&#x…

一款好用的PDF文档解密软件

PDF Decrypter pro 纯免费&#xff0c;没有页数限制&#xff0c;没有额外水印&#xff0c;强烈推荐&#xff01;

使用docker创建redis实例、主从复制、哨兵集群

单机模式 1 拉取镜像 docker pull redis:7.2.1 2 新建redis映射配置文件夹data和conf $ mkdir -p /mydata/redis/data $ mkdir -p /mydata/redis/conf 3 切换到redis配置文件映射目录/mydata/redis/conf cd /mydata/redis/conf 4 编辑配置文件 vim redis.…

算法题:单调递增的数字(贪心算法解决序列问题)

这道题参考了一位网友的思路&#xff0c;采用了贪心算法动态规划&#xff0c;具体思路如下&#xff1a;&#xff08;完整题目附在了最后面&#xff09; 1、从高到低遍历数字的每个位数&#xff0c;找到第一个数值递减&#xff08;<&#xff09;的地方&#xff0c;把当前位-…

[spring] spring jpa - hibernate 名词解释配置

[spring] spring jpa - hibernate 名词解释&配置 之前过了一遍依赖注入的内容&#xff0c;这次过一下数据相关的部分&#xff0c;完成了这部分内容&#xff0c;下篇就涉及到 API 实现了 操作的部分放到下一篇&#xff0c;本篇主要是概念配置 整体课程上来说&#xff0c;…

c++ pthread库使用

c pthread库使用 1. pthread库安装2. 测试demo3. 配置include/lib路径3.1 添加include路径3.2 配置lib文件路径 4.显示结果5. 遇到的bug参考文献 1. pthread库安装 打开ftp://sourceware.org/pub/pthreads-win32&#xff0c;下载一个安装包&#xff0c;如pthreads-w32-2-8-0-r…

STM32 CubeMX PWM三种模式(HAL库)

STM32 CubeMX PWM两种模式&#xff08;HAL库&#xff09; STM32 CubeMX STM32 CubeMX PWM两种模式&#xff08;HAL库&#xff09;一、互补对称输出STM32 CubeMX设置代码部分 二、带死区互补模式STM32 CubeMX设置代码 三、普通模式STM32 CubeMX设置代码部分 总结 一、互补对称输…

实现Java基于类的代理方式 - CGLIB动态代理(动态代理篇 三)

CGLIB&#xff08;Code Generation Library&#xff09;是一个基于类的动态代理库&#xff0c;它可以在运行时生成字节码来创建代理类。相比于JDK动态代理&#xff0c;CGLIB动态代理不需要接口&#xff0c;可以代理任意类。 CGLIB动态代理的实现原理是通过继承目标类来创建代理…

什么是网络流量监控

随着许多服务迁移到云&#xff0c;网络基础架构的维护变得复杂。虽然云采用在生产力方面是有利的&#xff0c;但它也可能让位于未经授权的访问&#xff0c;使 IT 系统容易受到安全攻击。 为了确保其网络的安全性和平稳的性能&#xff0c;IT 管理员需要监控用户访问的每个链接以…

【C++杂货铺】一文带你走进RBTree

文章目录 一、红黑树的概念二、红黑树的性质三、红黑树结点的定义四、红黑树的插入操作4.1 情况一&#xff1a;uncle 存在且为红4.2 情况二&#xff1a;uncle 不存在4.3 情况三&#xff1a;uncle 存在且为黑4.4 插入完整源码 五、红黑树的验证六、红黑树与 AVL 树的比较七、结语…

可替代allegroA3909的国产芯片GC3909的数据分析

GLOBALCHIP的 GC3909 是一款双通道 12V 直流电机驱动芯片&#xff0c;为摄像机、消费类产品、玩具和其他低压或 者电池供电的运动控制类应用提供了集成的电机驱动解决方案。芯片一般用来驱动两个直流电机 或者驱动一个步进电机。 而GC3909 可以工作在 3.8~12V 的电源电压上&…

Ant Design+react 路由跳转

今天我们来继续探讨react的路由跳转 首先&#xff0c;创建router文件夹中的index import { lazy } from "react"; import { Outlet,useRoutes } from react-router-dom; //引入页面&#xff0c;引用了路由懒加载 const One lazy(() > import(../pages/one)); c…

QT作业二

1、思维导图 https://www.zhixi.com/view/9e899ee0 2、作业 #include <iostream>using namespace std;class Rect {int width;int height; public:void init(int w,int h);//初始化函数void set_w(int w);//更改宽度void set_h(int h);//更改高度void show();//输出矩形…

DEDECMS织梦保存当前栏目更改时失败的解决方法

织梦编辑栏目时提示“保存当前栏目更改时失败&#xff0c;请检查你的输入资料是否存在问题&#xff01;” 那是因为你的后台栏目编辑文件php里有做过二次开发&#xff0c;添加了栏目数据表里不存在的字段。 跟着下面的步骤&#xff0c;让程序告诉你缺少什么引起的保存失败吧。 …

轻松玩转直播带货,铭顺科技揭秘数字人跳舞直播软件亮点

直播带货在商业领域越来越受追捧&#xff0c;而数字人直播作为一种创新推广方式&#xff0c;正逐渐引起关注。在这个竞争激烈的直播行业中&#xff0c;数字人私有化部署解决方案以其独特的优势和亮点&#xff0c;为用户提供了一个轻松玩转直播带货的利器。 数字人私有化部署解决…