非对称加解密之前后端操作

非对称之前端解密

首先安装jsencrypt依赖包
npm install jsencrypt
然后在需要使用的文件中引入JSEncrypt

```import { JSEncrypt } from 'jsencrypt' 
 //或者下面这种方式引入
import JSEncrypt from 'jsencrypt/bin/jsencrypt'

## 加密

```javascript
/**
 * RSA非对称加密
 * @param data 需要加密的数据
 */
export function rsaEncrypt(data) {
  // 使用公钥加密
  const encrypt = new JSEncrypt()
  encrypt.setPublicKey(PUBLIC_KEY)
  let result = encrypt.encrypt(data)
  return result
}

解密

/**
 * RSA 解密
 * @param data 需要解密的数据
 */
export function rsaDecrypt(data) {
  //使用私钥解密
  const decrypt = new JSEncrypt()
  decrypt.setPrivateKey(PRIVATE_KEY)
  let result = decrypt.decrypt(data)
  return result
}

测试

import { rsaEncrypt, rsaDecrypt } from '@/utils'

// 在需要的地方使用
console.log('加密:', rsaEncrypt('123456'))
console.log('解密:', rsaDecrypt (rsaEncrypt('123456')))

java 后端加解密

package com.xxx.xxx.xxx.xx;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 支持AES、DES、RSA加密、数字签名以及生成对称密钥和非对称密钥对
 */
public class CryptoUtils {

    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private static final Encoder BASE64_ENCODER = Base64.getEncoder();
    private static final Decoder BASE64_DECODER = Base64.getDecoder();

    private static final Map<Algorithm, KeyFactory> KEY_FACTORY_CACHE = new ConcurrentHashMap<>();
    private static final Map<Algorithm, Cipher> CIPHER_CACHE = new HashMap<>();

    /**
     * 生成对称密钥,目前支持的算法有AES、DES
     *
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String generateSymmetricKey(Algorithm algorithm) throws NoSuchAlgorithmException {
        KeyGenerator generator = KeyGenerator.getInstance(algorithm.getName());
        generator.init(algorithm.getKeySize());
        SecretKey secretKey = generator.generateKey();
        return BASE64_ENCODER.encodeToString(secretKey.getEncoded());
    }

    /**
     * 生成非对称密钥对,目前支持的算法有RSA、DSA。备注:默认生成的密钥格式为PKCS8
     *
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static AsymmetricKeyPair generateAsymmetricKeyPair(Algorithm algorithm) throws NoSuchAlgorithmException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithm.getName());
        generator.initialize(algorithm.getKeySize());
        KeyPair keyPair = generator.generateKeyPair();
        String publicKey = BASE64_ENCODER.encodeToString(keyPair.getPublic().getEncoded());
        String privateKey = BASE64_ENCODER.encodeToString(keyPair.getPrivate().getEncoded());
        return new AsymmetricKeyPair(publicKey, privateKey);
    }

    public static String encryptByRSA(String publicKeyText, String plainText) throws Exception {
        return encryptAsymmetrically(publicKeyText, plainText, Algorithm.Encryption.RSA_ECB_PKCS1);
    }

    public static String decryptByRSA(String privateKeyText, String ciphertext) throws Exception {
        return decryptAsymmetrically(privateKeyText, ciphertext, Algorithm.Encryption.RSA_ECB_PKCS1);
    }

    /**
     * RSA公钥分段加密
     *
     * @param str       加密字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 加密过程中的异常信息
     */
    public static String encrypt(String publicKey, String str) throws Exception {

        //分段加密
        byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] bytes = str.getBytes();
        int inputLen = bytes.length;
        int offLen = 0;//偏移量
        int i = 0;
        ByteArrayOutputStream bops = new ByteArrayOutputStream();
        while (inputLen - offLen > 0) {
            byte[] cache;
            if (inputLen - offLen > 117) {
                cache = cipher.doFinal(bytes, offLen, 117);
            } else {
                cache = cipher.doFinal(bytes, offLen, inputLen - offLen);
            }
            bops.write(cache);
            i++;
            offLen = 117 * i;
        }
        bops.close();
        byte[] encryptedData = bops.toByteArray();
        return org.apache.commons.codec.binary.Base64.encodeBase64String(encryptedData);

    }

    /**
     * RSA私钥分段解密
     *
     * @param str        加密字符串
     * @param privateKey 私钥
     * @return 铭文
     * @throws Exception 解密过程中的异常信息
     */
    public static String decrypt(String privateKey, String str) throws Exception {

        //分段解密
        byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);

        byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(str);
        int inputLen = bytes.length;
        int offLen = 0;
        int i = 0;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        while (inputLen - offLen > 0) {
            byte[] cache;
            if (inputLen - offLen > 128) {
                cache = cipher.doFinal(bytes, offLen, 128);
            } else {
                cache = cipher.doFinal(bytes, offLen, inputLen - offLen);
            }
            byteArrayOutputStream.write(cache);
            i++;
            offLen = 128 * i;

        }
        byteArrayOutputStream.close();
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        return new String(byteArray);
    }

    /**
     * SHA1签名算法和DSA加密算法结合使用生成数字签名
     *
     * @param privateKeyText
     * @param msg
     * @return 数字签名
     * @throws Exception
     */
    public static String signBySHA1WithDSA(String privateKeyText, String msg) throws Exception {
        return doSign(privateKeyText, msg, Algorithm.Encryption.DSA, Algorithm.Signing.SHA1WithDSA);
    }

    /**
     * SHA1签名算法和RSA加密算法结合使用生成数字签名
     *
     * @param privateKeyText 私钥
     * @param msg            待加签内容
     * @return 数字签名
     * @throws Exception
     */
    public static String signBySHA1WithRSA(String privateKeyText, String msg) throws Exception {
        return doSign(privateKeyText, msg, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA1WithRSA);
    }

    /**
     * SHA256签名算法和RSA加密算法结合使用生成数字签名
     *
     * @param privateKeyText 私钥
     * @param msg            待加签内容
     * @return 数字签名
     * @throws Exception
     */
    public static String signBySHA256WithRSA(String privateKeyText, String msg) throws Exception {
        return doSign(privateKeyText, msg, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA256WithRSA);
    }

    /**
     * SHA1签名算法和DSA加密算法检验数字签名
     *
     * @param publicKeyText 公钥
     * @param msg           待验签内容
     * @param signatureText 数字
     * @return 检验是否成功
     * @throws Exception
     */
    public static boolean verifyBySHA1WithDSA(String publicKeyText, String msg, String signatureText) throws Exception {
        return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.DSA, Algorithm.Signing.SHA1WithDSA);
    }

    /**
     * SHA1签名算法和RSA加密算法检验数字签名
     *
     * @param publicKeyText 公钥
     * @param msg           待验签内容
     * @param signatureText 签名
     * @return 校验是否成功
     * @throws Exception
     */
    public static boolean verifyBySHA1WithRSA(String publicKeyText, String msg, String signatureText) throws Exception {
        return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA1WithRSA);
    }

    /**
     * SHA256签名算法和RSA加密算法检验数字签名
     *
     * @param publicKeyText 公钥
     * @param msg           待验签内容
     * @param signatureText 签名
     * @return 校验是否成功
     * @throws Exception
     */
    public static boolean verifyBySHA256WithRSA(String publicKeyText, String msg, String signatureText) throws Exception {
        return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA256WithRSA);
    }

    /**
     * 对称加密
     *
     * @param secretKey 密钥
     * @param iv        加密向量,只有CBC模式才支持,如果是CBC则必传
     * @param plainText 明文
     * @param algorithm 对称加密算法,如AES、DES
     * @return
     * @throws Exception
     */
    public static String encryptSymmetrically(String secretKey, String iv, String plainText, Algorithm algorithm) throws Exception {
        SecretKey key = decodeSymmetricKey(secretKey, algorithm);
        IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv);
        byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);
        byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, key, ivParameterSpec, plainTextInBytes);

        return BASE64_ENCODER.encodeToString(ciphertextInBytes);
    }

    /**
     * 对称解密
     *
     * @param secretKey  密钥
     * @param iv         加密向量,只有CBC模式才支持,如果是CBC则必传
     * @param ciphertext 密文
     * @param algorithm  对称加密算法,如AES、DES
     * @return
     * @throws Exception
     */
    public static String decryptSymmetrically(String secretKey, String iv, String ciphertext, Algorithm algorithm) throws Exception {
        SecretKey key = decodeSymmetricKey(secretKey, algorithm);
        IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv);
        byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext);
        byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, key, ivParameterSpec, ciphertextInBytes);
        return new String(plainTextInBytes, DEFAULT_CHARSET);
    }

    /**
     * 非对称加密
     *
     * @param publicKeyText 公钥
     * @param plainText     明文
     * @param algorithm     非对称加密算法
     * @return
     * @throws Exception
     */
    public static String encryptAsymmetrically(String publicKeyText, String plainText, Algorithm algorithm) throws Exception {
        PublicKey publicKey = regeneratePublicKey(publicKeyText, algorithm);
        byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET);
        byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, publicKey, plainTextInBytes);
        return BASE64_ENCODER.encodeToString(ciphertextInBytes);
    }

    /**
     * 非对称解密
     *
     * @param privateKeyText 私钥
     * @param ciphertext     密文
     * @param algorithm      非对称加密算法
     * @return
     * @throws Exception
     */
    public static String decryptAsymmetrically(String privateKeyText, String ciphertext, Algorithm algorithm) throws Exception {
        PrivateKey privateKey = regeneratePrivateKey(privateKeyText, algorithm);
        byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext);
        byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, privateKey, ciphertextInBytes);
        return new String(plainTextInBytes, DEFAULT_CHARSET);
    }

    /**
     * 生成数字签名
     *
     * @param privateKeyText      私钥
     * @param msg                 传输的数据
     * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
     * @param signatureAlgorithm  签名算法,见Algorithm中的签名算法
     * @return 数字签名
     * @throws Exception
     */
    public static String doSign(String privateKeyText, String msg, Algorithm encryptionAlgorithm, Algorithm signatureAlgorithm)
            throws Exception {
        PrivateKey privateKey = regeneratePrivateKey(privateKeyText, encryptionAlgorithm);
        // Signature只支持签名算法
        Signature signature = Signature.getInstance(signatureAlgorithm.getName());
        signature.initSign(privateKey);
        signature.update(msg.getBytes(DEFAULT_CHARSET));
        byte[] signatureInBytes = signature.sign();
        return BASE64_ENCODER.encodeToString(signatureInBytes);
    }

    /**
     * 数字签名验证
     *
     * @param publicKeyText       公钥
     * @param msg                 传输的数据
     * @param signatureText       数字签名
     * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法
     * @param signatureAlgorithm  签名算法,见Algorithm中的签名算法
     * @return 校验是否成功
     * @throws Exception
     */
    public static boolean doVerify(String publicKeyText, String msg, String signatureText, Algorithm encryptionAlgorithm,
                                   Algorithm signatureAlgorithm) throws Exception {
        PublicKey publicKey = regeneratePublicKey(publicKeyText, encryptionAlgorithm);
        Signature signature = Signature.getInstance(signatureAlgorithm.getName());
        signature.initVerify(publicKey);
        signature.update(msg.getBytes(DEFAULT_CHARSET));
        return signature.verify(BASE64_DECODER.decode(signatureText));
    }

    /**
     * 将密钥进行Base64位解码,重新生成SecretKey实例
     *
     * @param secretKey 密钥
     * @param algorithm 算法
     * @return
     */
    private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorithm) {
        byte[] key = BASE64_DECODER.decode(secretKey);
        return new SecretKeySpec(key, algorithm.getName());
    }

    private static IvParameterSpec decodeIv(String iv) {
        byte[] ivInBytes = BASE64_DECODER.decode(iv);
        return new IvParameterSpec(ivInBytes);
    }

    private static PublicKey regeneratePublicKey(String publicKeyText, Algorithm algorithm)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyInBytes = BASE64_DECODER.decode(publicKeyText);
        KeyFactory keyFactory = getKeyFactory(algorithm);
        // 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpec
        KeySpec publicKeySpec = new X509EncodedKeySpec(keyInBytes);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
        return publicKey;
    }

    private static PrivateKey regeneratePrivateKey(String key, Algorithm algorithm) throws Exception {
        byte[] keyInBytes = BASE64_DECODER.decode(key);
        KeyFactory keyFactory = getKeyFactory(algorithm);
        // 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec
        KeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyInBytes);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
        return privateKey;
    }

    private static KeyFactory getKeyFactory(Algorithm algorithm) throws NoSuchAlgorithmException {
        KeyFactory keyFactory = KEY_FACTORY_CACHE.get(algorithm);
        if (keyFactory == null) {
            keyFactory = KeyFactory.getInstance(algorithm.getName());
            KEY_FACTORY_CACHE.put(algorithm, keyFactory);
        }

        return keyFactory;
    }

    private static byte[] transform(Algorithm algorithm, int mode, Key key, byte[] msg) throws Exception {
        return transform(algorithm, mode, key, null, msg);
    }

    private static byte[] transform(Algorithm algorithm, int mode, Key key, IvParameterSpec iv, byte[] msg) throws Exception {
        Cipher cipher = CIPHER_CACHE.get(algorithm);
        // double check,减少上下文切换
        if (cipher == null) {
            synchronized (CryptoUtils.class) {
                if ((cipher = CIPHER_CACHE.get(algorithm)) == null) {
                    cipher = determineWhichCipherToUse(algorithm);
                    CIPHER_CACHE.put(algorithm, cipher);
                }
                cipher.init(mode, key, iv);
                return cipher.doFinal(msg);
            }
        }

        synchronized (CryptoUtils.class) {
            cipher.init(mode, key, iv);
            return cipher.doFinal(msg);
        }
    }

    private static Cipher determineWhichCipherToUse(Algorithm algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
        Cipher cipher;
        String transformation = algorithm.getTransformation();
        // 官方推荐的transformation使用algorithm/mode/padding组合,SunJCE使用ECB作为默认模式,使用PKCS5Padding作为默认填充
        if (StringUtils.isNotEmpty(transformation)) {
            cipher = Cipher.getInstance(transformation);
        } else {
            cipher = Cipher.getInstance(algorithm.getName());
        }

        return cipher;
    }

    /**
     * 算法分为加密算法和签名算法,更多算法实现见:<br/>
     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl">jdk8中的标准算法</a>
     */
    public static class Algorithm {

        public interface Encryption {
            Algorithm AES_ECB_PKCS5 = new Algorithm("AES", "AES/ECB/PKCS5Padding", 128);
            Algorithm AES_CBC_PKCS5 = new Algorithm("AES", "AES/CBC/PKCS5Padding", 128);
            Algorithm DES_ECB_PKCS5 = new Algorithm("DES", "DES/ECB/PKCS5Padding", 56);
            Algorithm DES_CBC_PKCS5 = new Algorithm("DES", "DES/CBC/PKCS5Padding", 56);
            Algorithm RSA_ECB_PKCS1 = new Algorithm("RSA", "RSA/ECB/PKCS1Padding", 1024);
            Algorithm DSA = new Algorithm("DSA", 1024);
        }

        public interface Signing {
            Algorithm SHA1WithDSA = new Algorithm("SHA1withDSA", 1024);
            Algorithm SHA1WithRSA = new Algorithm("SHA1WithRSA", 2048);
            Algorithm SHA256WithRSA = new Algorithm("SHA256WithRSA", 2048);
        }

        @Getter
        private String name;
        @Getter
        private String transformation;
        @Getter
        private int keySize;

        public Algorithm(String name, int keySize) {
            this(name, null, keySize);
        }

        public Algorithm(String name, String transformation, int keySize) {
            this.name = name;
            this.transformation = transformation;
            this.keySize = keySize;
        }

    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class AsymmetricKeyPair {

        private String publicKey;
        private String privateKey;
    }


    /**
     * @Description: 生成密钥
     * @Param:
     * @author: jony
     * @date: 2024/3/3 15:49
     **/
    public static void main(String[] args) throws Exception {
        AsymmetricKeyPair asymmetricKeyPair = CryptoUtils.generateAsymmetricKeyPair(Algorithm.Encryption.RSA_ECB_PKCS1);
        /*公钥*/
        String publicKey = asymmetricKeyPair.publicKey;
        /*私钥*/
        String privateKey = asymmetricKeyPair.getPrivateKey();
        System.out.println("公钥:" + publicKey + "私钥:" + privateKey);
        System.out.println("私钥:" + privateKey);
        String s = CryptoUtils.encryptByRSA(publicKey, "shentaisiyu8888");
        System.out.println("token:" + s);

        System.out.println("解密:" + CryptoUtils.decryptByRSA(privateKey,s));


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是个好孩子啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值