前端RSA加密java后端解密示例代碼
更新時(shí)間:2024年11月23日 14:49:26 作者:王佑輝
這篇文章主要介紹了RSA非對(duì)稱加密的原理,前端使用公鑰加密數(shù)據(jù),后端使用私鑰解密,提供了前端和后端實(shí)現(xiàn)的示例代碼,包括依賴、接口、工具類等,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
1. 說(shuō)明
- 1.RSA是非對(duì)稱加密。
- 2.前端采用公鑰加密,后端采用私鑰解密。
- 3.此示例是前端加密,后端解密,后端返回的數(shù)據(jù)未加密。如果后端相應(yīng)數(shù)據(jù)也要加密,可以另寫(xiě)注解,采用對(duì)稱加密。
- 4.公鑰私鑰的base64格式可以由RsaUtil工具類生成,參考其中main方法。
- 5.在需要加密的接口上添加自定義注解@ApiDecryptRsa即可解密。
- 5.ApiDecryptParamResolver是解析requestParam參數(shù)的,這里沒(méi)寫(xiě)全,需要額外寫(xiě)注解。
2. 前端示例
- 1.rsa依賴包
npm install jsencrypt
- 2.頁(yè)面代碼
<template>
<el-button type="primary" icon="el-icon-plus" @click="handleTest">測(cè)試</el-button>
</template>
<script>
import { save } from "@/api/test";
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
export default {
name: '測(cè)試RSA加密',
methods: {
handleTest(){
const crypt = new JSEncrypt()
// 公鑰,由后端接口返回,這里寫(xiě)死作為測(cè)試
const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlmkqsmA28rt/bsBJ2hDEdvbIlEvnJ2fg0gm1++rXxXNEBvGyCnwnDxvztjsHtbootAdeB1D73DVfCKzCj5Le/Wv21llvriG1bAeM3zSEywPKQzW/5zhC3BODdx8vuFe3r1KxunqdXHm/67tnC/VMS85XGtCBkcfAXCJZyNE5rQIDAQAB';
crypt.setPublicKey(publicKey)
const data = {
"content": "測(cè)試",
}
const encrypted = crypt.encrypt(JSON.stringify(data))
console.log(encrypted)
// 調(diào)用接口
save(encrypted).then(res=>{
console.log(res.data)
})
},
}
}
</script>
- 3.api請(qǐng)求
import request from "@/axios";
export const save = row => {
return request({
url: '/xapi/test/save',
headers: {
'Content-Type': 'text/plain'
},
method: 'post',
data: row,
});
};
3. 后端示例
3.1 pom依賴
- 1.pom依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>my-springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.40</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>
3.2 后端結(jié)構(gòu)圖
- 2.后端結(jié)構(gòu)圖

3.3 DecryptHttpInputMessage
- 3.DecryptHttpInputMessage
package com.learning.bean;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import java.io.InputStream;
/**
* <p>解密信息輸入流</p>
*
*/
@Getter
@RequiredArgsConstructor
public class DecryptHttpInputMessage implements HttpInputMessage {
private final InputStream body;
private final HttpHeaders headers;
}3.4 ApiCryptoProperties
- 4.ApiCryptoProperties
package com.learning.config;
import com.learning.crypto.advice.ApiDecryptParamResolver;
import com.learning.crypto.props.ApiCryptoProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* api 簽名自動(dòng)配置
*
*/
@AutoConfiguration
@RequiredArgsConstructor
@EnableConfigurationProperties(ApiCryptoProperties.class)
@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
public class ApiCryptoConfiguration implements WebMvcConfigurer {
private final ApiCryptoProperties apiCryptoProperties;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new ApiDecryptParamResolver(apiCryptoProperties));
}
}3.5 TestController
- 5.TestController
package com.learning.controller;
import com.learning.crypto.annotation.ApiDecryptRsa;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping(value = "/save", produces = "text/plain")
@ApiDecryptRsa
public String save(@RequestBody String data){
return data;
}
}3.6 ApiCryptoUtil
- 6.ApiCryptoUtil
package com.learning.crypto.advice;
import com.learning.crypto.props.ApiCryptoProperties;
import java.util.Objects;
import com.learning.util.RsaUtil;
/**
* <p>輔助工具類</p>
*
*/
public class ApiCryptoUtil {
/**
* 選擇加密方式并進(jìn)行解密
*
* @param bodyData byte array
* @return 解密結(jié)果
*/
public static byte[] decryptData(ApiCryptoProperties properties, byte[] bodyData) {
String privateKey = Objects.requireNonNull(properties.getRsaPrivateKey());
return RsaUtil.decryptFromBase64(privateKey, bodyData);
}
}3.7 ApiDecryptParamResolver
- 7.ApiDecryptParamResolver
package com.learning.crypto.advice;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.learning.crypto.annotation.ApiDecryptRsa;
import com.learning.crypto.props.ApiCryptoProperties;
import com.learning.util.Func;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
/**
* param 參數(shù) 解析
*
*/
@RequiredArgsConstructor
public class ApiDecryptParamResolver implements HandlerMethodArgumentResolver {
private final ApiCryptoProperties properties;
@Override
public boolean supportsParameter(MethodParameter parameter) {
return AnnotatedElementUtils.hasAnnotation(parameter.getParameter(), ApiDecryptRsa.class);
}
@Nullable
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
Parameter parameter = methodParameter.getParameter();
String text = webRequest.getParameter(properties.getParamName());
if (Func.isEmpty(text)) {
return null;
}
byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);
byte[] decryptData = ApiCryptoUtil.decryptData(properties, textBytes);
ObjectMapper mapper = new ObjectMapper();
try{
return mapper.readValue(decryptData, parameter.getType());
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}3.8 ApiDecryptRequestBodyAdvice
- 8.ApiDecryptRequestBodyAdvice
package com.learning.crypto.advice;
import com.learning.crypto.annotation.ApiDecryptRsa;
import com.learning.crypto.props.ApiCryptoProperties;
import com.learning.util.ClassUtil;
import com.learning.bean.DecryptHttpInputMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.NonNull;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* 請(qǐng)求數(shù)據(jù)的加密信息解密處理<br>
* 本類只對(duì)控制器參數(shù)中含有<strong>{@link org.springframework.web.bind.annotation.RequestBody}</strong>
* 以及package為<strong><code>ccom.xiaoi.xics.core.crypto.api.signature.annotation.decrypt</code></strong>下的注解有效
*/
@Slf4j
@Order(1)
@AutoConfiguration
@ControllerAdvice
@RequiredArgsConstructor
@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
public class ApiDecryptRequestBodyAdvice implements RequestBodyAdvice {
private final ApiCryptoProperties properties;
@Override
public boolean supports(MethodParameter methodParameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {
return ClassUtil.isAnnotated(methodParameter.getMethod(), ApiDecryptRsa.class);
}
@Override
public Object handleEmptyBody(Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@NonNull
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
// 判斷 body 是否為空
InputStream messageBody = inputMessage.getBody();
if (messageBody.available() <= 0) {
return inputMessage;
}
byte[] decryptedBody = null;
byte[] bodyByteArray = StreamUtils.copyToByteArray(messageBody);
decryptedBody = ApiCryptoUtil.decryptData(properties, bodyByteArray);
if (decryptedBody == null) {
throw new RuntimeException("Decryption error, " +
"please check if the selected source data is encrypted correctly." +
" (解密錯(cuò)誤,請(qǐng)檢查選擇的源數(shù)據(jù)的加密方式是否正確。)");
}
InputStream inputStream = new ByteArrayInputStream(decryptedBody);
return new DecryptHttpInputMessage(inputStream, inputMessage.getHeaders());
}
@NonNull
@Override
public Object afterBodyRead(@NonNull Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}3.9 ApiDecryptRsa
- 9.ApiDecryptRsa
package com.learning.crypto.annotation;
import java.lang.annotation.*;
/**
* rsa 解密
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiDecryptRsa {
}3.10 ApiCryptoProperties
- 10.ApiCryptoProperties
package com.learning.crypto.props;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* api 簽名配置類
*/
@Getter
@Setter
@ConfigurationProperties(ApiCryptoProperties.PREFIX)
public class ApiCryptoProperties {
/**
* 前綴
*/
public static final String PREFIX = "api.crypto";
/**
* 是否開(kāi)啟 api 簽名
*/
private Boolean enabled = Boolean.TRUE;
/**
* url的參數(shù)簽名,傳遞的參數(shù)名。例如:/user?data=簽名后的數(shù)據(jù)
*/
private String paramName = "data";
/**
* rsa 私鑰
*/
private String rsaPrivateKey;
}3.11 KeyPair
- 11.KeyPair
package com.learning.crypto.tuple;
import com.learning.util.RsaUtil;
import lombok.RequiredArgsConstructor;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* rsa 的 key pair 封裝
*
*/
@RequiredArgsConstructor
public class KeyPair {
private final java.security.KeyPair keyPair;
public PublicKey getPublic() {
return keyPair.getPublic();
}
public PrivateKey getPrivate() {
return keyPair.getPrivate();
}
public byte[] getPublicBytes() {
return this.getPublic().getEncoded();
}
public byte[] getPrivateBytes() {
return this.getPrivate().getEncoded();
}
public String getPublicBase64() {
return RsaUtil.getKeyString(this.getPublic());
}
public String getPrivateBase64() {
return RsaUtil.getKeyString(this.getPrivate());
}
@Override
public String toString() {
return "PublicKey=" + this.getPublicBase64() + '\n' + "PrivateKey=" + this.getPrivateBase64();
}
}3.12 Pair
- 12.Pair
package com.learning.crypto.tuple;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
/**
* tuple Pair
**/
@Getter
@ToString
@EqualsAndHashCode
public class Pair<L, R> {
private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);
private final L left;
private final R right;
/**
* Returns an empty pair.
*/
@SuppressWarnings("unchecked")
public static <L, R> Pair<L, R> empty() {
return (Pair<L, R>) EMPTY;
}
/**
* Constructs a pair with its left value being {@code left}, or returns an empty pair if
* {@code left} is null.
*
* @return the constructed pair or an empty pair if {@code left} is null.
*/
public static <L, R> Pair<L, R> createLeft(L left) {
if (left == null) {
return empty();
} else {
return new Pair<>(left, null);
}
}
/**
* Constructs a pair with its right value being {@code right}, or returns an empty pair if
* {@code right} is null.
*
* @return the constructed pair or an empty pair if {@code right} is null.
*/
public static <L, R> Pair<L, R> createRight(R right) {
if (right == null) {
return empty();
} else {
return new Pair<>(null, right);
}
}
public static <L, R> Pair<L, R> create(L left, R right) {
if (right == null && left == null) {
return empty();
} else {
return new Pair<>(left, right);
}
}
private Pair(L left, R right) {
this.left = left;
this.right = right;
}
}3.13 ClassUtil
- 13.ClassUtil
package com.learning.util;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.web.method.HandlerMethod;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 類操作工具
*/
public class ClassUtil extends org.springframework.util.ClassUtils {
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
/**
* 獲取方法參數(shù)信息
*
* @param constructor 構(gòu)造器
* @param parameterIndex 參數(shù)序號(hào)
* @return {MethodParameter}
*/
public static MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) {
MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
return methodParameter;
}
/**
* 獲取方法參數(shù)信息
*
* @param method 方法
* @param parameterIndex 參數(shù)序號(hào)
* @return {MethodParameter}
*/
public static MethodParameter getMethodParameter(Method method, int parameterIndex) {
MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
return methodParameter;
}
/**
* 獲取Annotation
*
* @param method Method
* @param annotationType 注解類
* @param <A> 泛型標(biāo)記
* @return {Annotation}
*/
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
Class<?> targetClass = method.getDeclaringClass();
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtil.getMostSpecificMethod(method, targetClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 先找方法,再找方法上的類
A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType);
;
if (null != annotation) {
return annotation;
}
// 獲取類上面的Annotation,可能包含組合注解,故采用spring的工具類
return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType);
}
/**
* 獲取Annotation
*
* @param handlerMethod HandlerMethod
* @param annotationType 注解類
* @param <A> 泛型標(biāo)記
* @return {Annotation}
*/
public static <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {
// 先找方法,再找方法上的類
A annotation = handlerMethod.getMethodAnnotation(annotationType);
if (null != annotation) {
return annotation;
}
// 獲取類上面的Annotation,可能包含組合注解,故采用spring的工具類
Class<?> beanType = handlerMethod.getBeanType();
return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
}
/**
* 判斷是否有注解 Annotation
*
* @param method Method
* @param annotationType 注解類
* @param <A> 泛型標(biāo)記
* @return {boolean}
*/
public static <A extends Annotation> boolean isAnnotated(Method method, Class<A> annotationType) {
// 先找方法,再找方法上的類
boolean isMethodAnnotated = AnnotatedElementUtils.isAnnotated(method, annotationType);
if (isMethodAnnotated) {
return true;
}
// 獲取類上面的Annotation,可能包含組合注解,故采用spring的工具類
Class<?> targetClass = method.getDeclaringClass();
return AnnotatedElementUtils.isAnnotated(targetClass, annotationType);
}
}3.14 Func
- 14.Func
package com.learning.util;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* 工具類
*/
public class Func {
/**
* 判斷空對(duì)象 object、map、list、set、字符串、數(shù)組
*
* @param obj the object to check
* @return 數(shù)組是否為空
*/
public static boolean isEmpty(@Nullable Object obj) {
return ObjectUtils.isEmpty(obj);
}
/**
* 對(duì)象不為空 object、map、list、set、字符串、數(shù)組
*
* @param obj the object to check
* @return 是否不為空
*/
public static boolean isNotEmpty(@Nullable Object obj) {
return !ObjectUtils.isEmpty(obj);
}
}3.15 RsaUtil
- 15.RsaUtil
package com.learning.util;
import com.learning.crypto.tuple.KeyPair;
import org.springframework.lang.Nullable;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;
import java.util.Objects;
/**
* RSA加、解密工具
*
* 1. 公鑰負(fù)責(zé)加密,私鑰負(fù)責(zé)解密;
* 2. 私鑰負(fù)責(zé)簽名,公鑰負(fù)責(zé)驗(yàn)證。
*/
public class RsaUtil {
/**
* 數(shù)字簽名,密鑰算法
*/
public static final String RSA_ALGORITHM = "RSA";
public static final String RSA_PADDING = "RSA/ECB/PKCS1Padding";
/**
* 獲取 KeyPair
*
* @return KeyPair
*/
public static KeyPair genKeyPair() {
return genKeyPair(1024);
}
/**
* 獲取 KeyPair
*
* @param keySize key size
* @return KeyPair
*/
public static KeyPair genKeyPair(int keySize) {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA_ALGORITHM);
// 密鑰位數(shù)
keyPairGen.initialize(keySize);
// 密鑰對(duì)
return new KeyPair(keyPairGen.generateKeyPair());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 生成RSA私鑰
*
* @param modulus N特征值
* @param exponent d特征值
* @return {@link PrivateKey}
*/
public static PrivateKey generatePrivateKey(String modulus, String exponent) {
return generatePrivateKey(new BigInteger(modulus), new BigInteger(exponent));
}
/**
* 生成RSA私鑰
*
* @param modulus N特征值
* @param exponent d特征值
* @return {@link PrivateKey}
*/
public static PrivateKey generatePrivateKey(BigInteger modulus, BigInteger exponent) {
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exponent);
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 生成RSA公鑰
*
* @param modulus N特征值
* @param exponent e特征值
* @return {@link PublicKey}
*/
public static PublicKey generatePublicKey(String modulus, String exponent) {
return generatePublicKey(new BigInteger(modulus), new BigInteger(exponent));
}
/**
* 生成RSA公鑰
*
* @param modulus N特征值
* @param exponent e特征值
* @return {@link PublicKey}
*/
public static PublicKey generatePublicKey(BigInteger modulus, BigInteger exponent) {
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 得到公鑰
*
* @param base64PubKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @return PublicKey
*/
public static PublicKey getPublicKey(String base64PubKey) {
Objects.requireNonNull(base64PubKey, "base64 public key is null.");
byte[] keyBytes = Base64Utils.decodeFromString(base64PubKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 得到公鑰字符串
*
* @param base64PubKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @return PublicKey String
*/
public static String getPublicKeyToBase64(String base64PubKey) {
PublicKey publicKey = getPublicKey(base64PubKey);
return getKeyString(publicKey);
}
/**
* 得到私鑰
*
* @param base64PriKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @return PrivateKey
*/
public static PrivateKey getPrivateKey(String base64PriKey) {
Objects.requireNonNull(base64PriKey, "base64 private key is null.");
byte[] keyBytes = Base64Utils.decodeFromString(base64PriKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
try {
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
/**
* 得到密鑰字符串(經(jīng)過(guò)base64編碼)
*
* @param key key
* @return base 64 編碼后的 key
*/
public static String getKeyString(Key key) {
return Base64Utils.encodeToString(key.getEncoded());
}
/**
* 得到私鑰 base64
*
* @param base64PriKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @return PrivateKey String
*/
public static String getPrivateKeyToBase64(String base64PriKey) {
PrivateKey privateKey = getPrivateKey(base64PriKey);
return getKeyString(privateKey);
}
/**
* 共要加密
*
* @param base64PublicKey base64 的公鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
public static byte[] encrypt(String base64PublicKey, byte[] data) {
return encrypt(getPublicKey(base64PublicKey), data);
}
/**
* 共要加密
*
* @param publicKey 公鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
public static byte[] encrypt(PublicKey publicKey, byte[] data) {
return rsa(publicKey, data, Cipher.ENCRYPT_MODE);
}
/**
* 私鑰加密,用于 qpp 內(nèi),公鑰解密
*
* @param base64PrivateKey base64 的私鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
public static byte[] encryptByPrivateKey(String base64PrivateKey, byte[] data) {
return encryptByPrivateKey(getPrivateKey(base64PrivateKey), data);
}
/**
* 私鑰加密,加密成 base64 字符串,用于 qpp 內(nèi),公鑰解密
*
* @param base64PrivateKey base64 的私鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
public static String encryptByPrivateKeyToBase64(String base64PrivateKey, byte[] data) {
return Base64Utils.encodeToString(encryptByPrivateKey(base64PrivateKey, data));
}
/**
* 私鑰加密,用于 qpp 內(nèi),公鑰解密
*
* @param privateKey 私鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
public static byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] data) {
return rsa(privateKey, data, Cipher.ENCRYPT_MODE);
}
/**
* 公鑰加密
*
* @param base64PublicKey base64 公鑰
* @param data 待加密的內(nèi)容
* @return 加密后的內(nèi)容
*/
@Nullable
public static String encryptToBase64(String base64PublicKey, @Nullable String data) {
if (Func.isEmpty(data)) {
return null;
}
return Base64Utils.encodeToString(encrypt(base64PublicKey, data.getBytes(StandardCharsets.UTF_8)));
}
/**
* 解密
*
* @param base64PrivateKey base64 私鑰
* @param data 數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decrypt(String base64PrivateKey, byte[] data) {
return decrypt(getPrivateKey(base64PrivateKey), data);
}
/**
* 解密
*
* @param base64publicKey base64 公鑰
* @param data 數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decryptByPublicKey(String base64publicKey, byte[] data) {
return decryptByPublicKey(getPublicKey(base64publicKey), data);
}
/**
* 解密
*
* @param privateKey privateKey
* @param data 數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decrypt(PrivateKey privateKey, byte[] data) {
return rsa(privateKey, data, Cipher.DECRYPT_MODE);
}
/**
* 解密
*
* @param publicKey PublicKey
* @param data 數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decryptByPublicKey(PublicKey publicKey, byte[] data) {
return rsa(publicKey, data, Cipher.DECRYPT_MODE);
}
/**
* rsa 加、解密
*
* @param key key
* @param data 數(shù)據(jù)
* @param mode 模式
* @return 解密后的數(shù)據(jù)
*/
private static byte[] rsa(Key key, byte[] data, int mode) {
try {
Cipher cipher = Cipher.getInstance(RSA_PADDING);
cipher.init(mode, key);
return cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* base64 數(shù)據(jù)解密
*
* @param base64PublicKey base64 公鑰
* @param base64Data base64數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decryptByPublicKeyFromBase64(String base64PublicKey, byte[] base64Data) {
return decryptByPublicKey(getPublicKey(base64PublicKey), base64Data);
}
/**
* base64 數(shù)據(jù)解密
*
* @param base64PrivateKey base64 私鑰
* @param base64Data base64數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
@Nullable
public static String decryptFromBase64(String base64PrivateKey, @Nullable String base64Data) {
if (Func.isEmpty(base64Data)) {
return null;
}
return new String(decrypt(base64PrivateKey, Base64Utils.decodeFromString(base64Data)), StandardCharsets.UTF_8);
}
/**
* base64 數(shù)據(jù)解密
*
* @param base64PrivateKey base64 私鑰
* @param base64Data base64數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
public static byte[] decryptFromBase64(String base64PrivateKey, byte[] base64Data) {
return decrypt(base64PrivateKey, Base64Utils.decode(base64Data));
}
/**
* base64 數(shù)據(jù)解密
*
* @param base64PublicKey base64 公鑰
* @param base64Data base64數(shù)據(jù)
* @return 解密后的數(shù)據(jù)
*/
@Nullable
public static String decryptByPublicKeyFromBase64(String base64PublicKey, @Nullable String base64Data) {
if (Func.isEmpty(base64Data)) {
return null;
}
return new String(decryptByPublicKeyFromBase64(base64PublicKey, Base64Utils.decodeFromString(base64Data)), StandardCharsets.UTF_8);
}
public static void main(String[] args) {
// KeyPair keyPair = genKeyPair();
// System.out.println("私鑰:"+keyPair.getPrivateBase64());
// System.out.println("公鑰:"+keyPair.getPublicBase64());
String privateBase64 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAImWaSqyYDbyu39uwEnaEMR29siUS+cnZ+DSCbX76tfFc0QG8bIKfCcPG/O2Owe1uii0B14HUPvcNV8IrMKPkt79a/bWWW+uIbVsB4zfNITLA8pDNb/nOELcE4N3Hy+4V7evUrG6ep1ceb/ru2cL9UxLzlca0IGRx8BcIlnI0TmtAgMBAAECgYBFSLLIx25f/Teh4jl+dws+g9GeC991FYjf06UEOUl3Qnza4sxPJayDVr5yqW9sYHzQBmg3V2PWkHtn0cx9ZSNF3iyDd0EQOb0ky9M7qWXifCD0uG1Ruc+cb1/vewRrj15VH2qOd9jmgeZhxWelvx0cENRpEMicIJ+zTt0kvX+UQQJBAMECqoBG5A5X3lkSdgsUbLtNbeIsPqH+FLA3+3UT29u+s5b9uPXhWBwVfRt3gtgJxaftiI/LHA7WZbFUYrKcxGUCQQC2fVxhNSFwTeiRCoimx+WID3fILOBNPNzGr75YzOzJdDpdnvHElo2CsUatoGDSk8S2hcUtwI2LSm/yxX9bzJepAkEAg/fYsIDIKe52fxyaTZUXizGz8jMiWAysBJkie7iqWSOZE6JDtwru/bTLp94dPq3f0aQd/YN4mcSKH6d9HHcH6QJAZrDOnkj2oyrEN3I1CZ0tNc52eid+pRgdqJTWyUOv74E/ItXBeP27bhLyEdxQ/851gLxwA9n6DKr7qiKnE3Ji2QJAMcs1ipl0n/aR0NR56/uI0R1cD2AsoimfZjc8hPWdjs/YfpZVQnrcpgQx5Ps4O631F7LQKz22MbwOoBt3UcZYSQ==";
String publicBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlmkqsmA28rt/bsBJ2hDEdvbIlEvnJ2fg0gm1++rXxXNEBvGyCnwnDxvztjsHtbootAdeB1D73DVfCKzCj5Le/Wv21llvriG1bAeM3zSEywPKQzW/5zhC3BODdx8vuFe3r1KxunqdXHm/67tnC/VMS85XGtCBkcfAXCJZyNE5rQIDAQAB";
System.out.println("加密數(shù)據(jù):"+encryptToBase64(publicBase64, "hello world"));
System.out.println("解密數(shù)據(jù):"+decryptFromBase64(privateBase64, encryptToBase64(publicBase64, "hello world")));
String data = "hu5u8UyEg6fcn+/4wKFRSUVGETrXGifVE6/RzRBQCVxAQt+XMA7C+xVR6Ws2ZXFmYVFoS0YL29u6oVkxvmESdRc9Zj/bf0M6ykqa57vyvvRRmrrqCSYUD6STo/QRdPFK4sxlsseTU2/XjZQYohnrMmouYspWykJ3fcN34uoieHc=";
// System.out.println("解密數(shù)據(jù):"+decryptFromBase64(privateBase64, data));
System.out.println("解密數(shù)據(jù):"+RsaUtil.decryptFromBase64(privateBase64, data));
}
}3.16 SpringBootLearningApplication啟動(dòng)類
- 16.SpringBootLearningApplication
package com.learning;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
**/
@SpringBootApplication
@ComponentScan(basePackages = {"com.learning"})
public class SpringBootLearningApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootLearningApplication.class, args);
}
}3.17 配置文件
- 17.application.yaml
api:
crypto:
# 私鑰
rsaPrivateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAImWaSqyYDbyu39uwEnaEMR29siUS+cnZ+DSCbX76tfFc0QG8bIKfCcPG/O2Owe1uii0B14HUPvcNV8IrMKPkt79a/bWWW+uIbVsB4zfNITLA8pDNb/nOELcE4N3Hy+4V7evUrG6ep1ceb/ru2cL9UxLzlca0IGRx8BcIlnI0TmtAgMBAAECgYBFSLLIx25f/Teh4jl+dws+g9GeC991FYjf06UEOUl3Qnza4sxPJayDVr5yqW9sYHzQBmg3V2PWkHtn0cx9ZSNF3iyDd0EQOb0ky9M7qWXifCD0uG1Ruc+cb1/vewRrj15VH2qOd9jmgeZhxWelvx0cENRpEMicIJ+zTt0kvX+UQQJBAMECqoBG5A5X3lkSdgsUbLtNbeIsPqH+FLA3+3UT29u+s5b9uPXhWBwVfRt3gtgJxaftiI/LHA7WZbFUYrKcxGUCQQC2fVxhNSFwTeiRCoimx+WID3fILOBNPNzGr75YzOzJdDpdnvHElo2CsUatoGDSk8S2hcUtwI2LSm/yxX9bzJepAkEAg/fYsIDIKe52fxyaTZUXizGz8jMiWAysBJkie7iqWSOZE6JDtwru/bTLp94dPq3f0aQd/YN4mcSKH6d9HHcH6QJAZrDOnkj2oyrEN3I1CZ0tNc52eid+pRgdqJTWyUOv74E/ItXBeP27bhLyEdxQ/851gLxwA9n6DKr7qiKnE3Ji2QJAMcs1ipl0n/aR0NR56/uI0R1cD2AsoimfZjc8hPWdjs/YfpZVQnrcpgQx5Ps4O631F7LQKz22MbwOoBt3UcZYSQ==
4. 調(diào)用截圖




總結(jié)
到此這篇關(guān)于前端RSA加密java后端解密的文章就介紹到這了,更多相關(guān)前端RSA加密后端解密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Cloud超詳細(xì)i講解Feign自定義配置與使用
這篇文章主要介紹了SpringCloud Feign自定義配置與使用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
Java生態(tài)/Redis中使用Lua腳本的過(guò)程
這篇文章主要介紹了Java生態(tài)/Redis中如何使用Lua腳本,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
簡(jiǎn)單講解java中throws與throw的區(qū)別
這篇文章主要介紹了簡(jiǎn)單講解java中throws與throw的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
使用Thrift實(shí)現(xiàn)跨語(yǔ)言RPC的調(diào)用
Thrift最大的優(yōu)勢(shì)就是可以實(shí)現(xiàn)跨語(yǔ)言RPC調(diào)用,尤其在一些大廠,微服務(wù)各模塊之間使用不同的語(yǔ)言是很常見(jiàn)的,本文就將使用java作為服務(wù)端,用python作為客戶端,實(shí)現(xiàn)不同語(yǔ)言之間的RPC調(diào)用,需要的可以參考下2023-10-10
使用postman傳遞list集合后臺(tái)springmvc接收
這篇文章主要介紹了使用postman傳遞list集合后臺(tái)springmvc接收的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08

