java加密使用

概念

算法分类

对称加解密算法

加密和解密使用相同的秘钥,常见算法有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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RSA算法是一种非对称加密算法,它可以用于加密数据和数字签名。在Java中,可以使用Java Cryptography Architecture(JCA)提供的API来实现RSA加密和解密。下面是简单的示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; public class RSAEncryption { public static void main(String[] args) throws Exception { String plainText = "Hello World"; // 生成RSA公钥和私钥 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // 使用公钥加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] cipherText = cipher.doFinal(plainText.getBytes()); // 使用私钥解密 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedText = cipher.doFinal(cipherText); System.out.println("Plain Text: " + plainText); System.out.println("Encrypted Text: " + new String(cipherText)); System.out.println("Decrypted Text: " + new String(decryptedText)); } } ``` 上面的代码先生成了一个2048位的RSA公钥和私钥,然后使用公钥加密了一个字符串,再使用私钥解密获得原始字符串。在实际使用中,我们通常需要将公钥和私钥保存在文件中,以便在不同的应用程序中使用。可以使用PKCS8EncodedKeySpec和X509EncodedKeySpec类来将公钥和私钥换为字节数组,以便在文件中保存。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值