Springboot+vue项目使用RSA公私钥对返回数据加解密

发布时间:2023年12月17日

针对于项目数据安全,对后台返回数据使用 RSA加密方式 进行加密处理

  1. RSA 加密方法类
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class RSAUtils {

    public static final String PUBLIC_KEY = "public_key";

    public static final String PRIVATE_KEY = "private_key";


    public static Map<String, String> generateRasKey() {
        Map<String, String> rs = new HashMap<>();
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = null;
            keyPairGen = KeyPairGenerator.getInstance("RSA");
            keyPairGen.initialize(1024, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥 公钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
            // 将公钥和私钥保存到Map
            rs.put(PUBLIC_KEY, publicKeyString);
            rs.put(PRIVATE_KEY, privateKeyString);
        } catch (Exception e) {
            throw new RuntimeException("RsaUtils 生成公钥失败...");
        }
        return rs;
    }

    /**
     * 公钥加密
     * @param str 加密字符串
     **/
    public static String encrypt(String str, String publicKey) {
        try {
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            //当长度过长的时候,需要分割后加密 117个字节
            byte[] resultBytes = getMaxResultEncrypt(str, cipher);
            return Base64.encodeBase64String(resultBytes);
        } catch (Exception e) {
            throw new RuntimeException("RsaUtils 加密失败");
        }
    }

    /**
     *  私钥解密
     * @param str 解密字符串
     **/
    public static String decrypt(String str, String privateKey) {

        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            return new String(cipher.doFinal(inputByte));
        } catch (Exception e) {
            throw new RuntimeException("RsaUtils 解密失败.");
        }
    }

    /**
     * 私钥加密
     * @param str 加密字符串
     **/
    public static String encryptPrivateKey(String str, String privateKey) {
        try {
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            //RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            //当长度过长的时候,需要分割后加密 117个字节
            byte[] resultBytes = getMaxResultEncrypt(str, cipher);
            return Base64.encodeBase64String(resultBytes);
        } catch (Exception e) {
            throw new RuntimeException("RsaUtils 加密失败");
        }
    }

    /**
     * 公钥解密
     **/
    public static String decryptPublicKey(String str, String publicKey) {

        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey puKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, puKey);
            return new String(cipher.doFinal(inputByte));
        } catch (Exception e) {
            throw new RuntimeException("RsaUtils 解密失败.");
        }
    }
    private static byte[] getMaxResultEncrypt(String str,  Cipher cipher) throws IllegalBlockSizeException, BadPaddingException {
        byte[] inputArray = str.getBytes(StandardCharsets.UTF_8);
        int inputLength = inputArray.length;
        // 最大加密字节数,超出最大字节数需要分组加密
        int MAX_ENCRYPT_BLOCK = 117;
        // 标识
        int offSet = 0;
        byte[] resultBytes = {};
        byte[] cache = {};
        while (inputLength - offSet > 0) {
            if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
                offSet += MAX_ENCRYPT_BLOCK;
            } else {
                cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                offSet = inputLength;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
        }
        return resultBytes;
    }
}
  1. 添加拦截器对所有的response请求的body进行加密
import com.alibaba.cloud.commons.io.Charsets;
import com.common.core.utils.RSAUtils;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 对所有的response请求的body进行加密
 * @author yanbixing
 */
@Component
public class GlobalResponseBodyEncodeFilter implements GlobalFilter, Ordered {

    @Value("${gateCustom.privateKey}")
    private String privateKey;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                        String s = null;
                        try {
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer join = dataBufferFactory.join(dataBuffer);
                            byte[] content = new byte[join.readableByteCount()];
                            join.read(content);
                            DataBufferUtils.release(join);
                            // 流转为字符串
                            String responseData = new String(content, Charsets.UTF_8);
                            // 使用私钥加密数据
                            s = RSAUtils.encryptPrivateKey(responseData, privateKey);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        return bufferFactory.wrap(s.getBytes(StandardCharsets.UTF_8));
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }
}

  1. 前端代码
    3.1 使用公钥解密

    3.1.1安装 node-rsa 插件

    npm i node-rsa --save  --legacy-peer-deps
    

    3.1.2 编写rsa 解密方法

    const NodeRSA = require('node-rsa')//私钥加密 公钥解密
    // 密钥对生成 http://web.chacuo.net/netrsakeypair
    
    const publicKey = '这里是公钥'
    
    
    // 解密
    export function decrypt (txt) {
        //公钥解密
        let pubkey = '-----BEGIN PUBLIC KEY-----\n' + publicKey + '\n-----END PUBLIC KEY-----'
        try {
            const nodersa2 = new NodeRSA(pubkey);
            return nodersa2.decryptPublic(txt, "utf8");
        } catch (error) {
            return ''
        }
    }
    

    3.1.3 使用

    import { decrypt } from '@/utils/nodersa'
    service.interceptors.response.use(res => {
    res.data = JSON.parse(decrypt(res.data));
    });
    

    3.2 使用私钥解密
    3.2.1 安装 jsencrypt 插件

    npm install jsencrypt --legacy-peer-deps
    

    3.2.2 编写rsa 私钥解密方法

    import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'	
    const publicKey = '公钥'
    
    const privateKey = '私钥'
    
    // 加密
    export function encrypt(txt) {
      const encryptor = new JSEncrypt()
      encryptor.setPublicKey(publicKey) // 设置公钥
      return encryptor.encrypt(txt) // 对数据进行加密
    }
    
    // 解密
    export function decrypt(txt) {
      const encryptor = new JSEncrypt()
      encryptor.setPrivateKey(privateKey) // 设置私钥
      return encryptor.decrypt(txt) // 对数据进行解密
    }
    
    

    3.2.3 使用

    import { decrypt } from '@/utils/jsencrypt'
    service.interceptors.response.use(res => {
    res.data = JSON.parse(decrypt(res.data));
    });
    
文章来源:https://blog.csdn.net/zhangbinlong/article/details/134936112
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。