在现代Web应用中,数据的安全传输至关重要。RSA算法作为一种非对称加密算法,广泛应用于前端公钥加密和后端私钥解密的场景中。通过这种方式,可以确保敏感数据在传输过程中不被窃取或篡改。本文将详细介绍如何使用Java实现前端公钥加密和后端私钥解密的功能,并提供完整的示例代码。通过本文的讲解,读者将能够理解和应用这一技术,提升应用的安全性。
1. 说明
1.RSA是非对称加密。
2.前端采用公钥加密,后端采用私钥解密。
3.此示例是前端加密,后端解密,后端返回的数据未加密。如果后端相应数据也要加密,可以另写注解,采用对称加密。
4.公钥私钥的base64格式可以由RsaUtil工具类生成,参考其中main方法。
5.在需要加密的接口上添加自定义注解@ApiDecryptRsa即可解密。
5.ApiDecryptParamResolver是解析requestParam参数的,这里没写全,需要额外写注解。
2. 前端示例
1.rsa依赖包
npm install jsencrypt
2.页面代码
<template> <el-button type="primary" icon="el-icon-plus" @click="handleTest">测试</el-button> </template> <script> import { save } from "@/api/test"; import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'; export default { name: '测试RSA加密', methods: { handleTest(){ const crypt = new JSEncrypt() // 公钥,由后端接口返回,这里写死作为测试 const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJlmkqsmA28rt/bsBJ2hDEdvbIlEvnJ2fg0gm1++rXxXNEBvGyCnwnDxvztjsHtbootAdeB1D73DVfCKzCj5Le/Wv21llvriG1bAeM3zSEywPKQzW/5zhC3BODdx8vuFe3r1KxunqdXHm/67tnC/VMS85XGtCBkcfAXCJZyNE5rQIDAQAB'; crypt.setPublicKey(publicKey) const data = { "content": "测试", } const encrypted = crypt.encrypt(JSON.stringify(data)) console.log(encrypted) // 调用接口 save(encrypted).then(res=>{ console.log(res.data) }) }, } } </script>
3.api请求
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 后端结构图
2.后端结构图
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 签名自动配置 * */ @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 { /** * 选择加密方式并进行解密 * * @param bodyData byte array * @return 解密结果 */ 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 参数 解析 * */ @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; /** * 请求数据的加密信息解密处理<br> * 本类只对控制器参数中含有<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." + " (解密错误,请检查选择的源数据的加密方式是否正确。)"); } 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"; /** * 是否开启 api 签名 */ private Boolean enabled = Boolean.TRUE; /** * url的参数签名,传递的参数名。例如:/user?data=签名后的数据 */ 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(); /** * 获取方法参数信息 * * @param constructor 构造器 * @param parameterIndex 参数序号 * @return {MethodParameter} */ public static MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) { MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex); methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER); return methodParameter; } /** * 获取方法参数信息 * * @param method 方法 * @param parameterIndex 参数序号 * @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> 泛型标记 * @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> 泛型标记 * @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> 泛型标记 * @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 { /** * 判断空对象 object、map、list、set、字符串、数组 * * @param obj the object to check * @return 数组是否为空 */ public static boolean isEmpty(@Nullable Object obj) { return ObjectUtils.isEmpty(obj); } /** * 对象不为空 object、map、list、set、字符串、数组 * * @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. 公钥负责加密,私钥负责解密; * 2. 私钥负责签名,公钥负责验证。 */ public class RsaUtil { /** * 数字签名,密钥算法 */ 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); // 密钥位数 keyPairGen.initialize(keySize); // 密钥对 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 密钥字符串(经过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 密钥字符串(经过base64编码) * @return PublicKey String */ public static String getPublicKeyToBase64(String base64PubKey) { PublicKey publicKey = getPublicKey(base64PubKey); return getKeyString(publicKey); } /** * 得到私钥 * * @param base64PriKey 密钥字符串(经过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); } } /** * 得到密钥字符串(经过base64编码) * * @param key key * @return base 64 编码后的 key */ public static String getKeyString(Key key) { return Base64Utils.encodeToString(key.getEncoded()); } /** * 得到私钥 base64 * * @param base64PriKey 密钥字符串(经过base64编码) * @return PrivateKey String */ public static String getPrivateKeyToBase64(String base64PriKey) { PrivateKey privateKey = getPrivateKey(base64PriKey); return getKeyString(privateKey); } /** * 共要加密 * * @param base64PublicKey base64 的公钥 * @param data 待加密的内容 * @return 加密后的内容 */ public static byte[] encrypt(String base64PublicKey, byte[] data) { return encrypt(getPublicKey(base64PublicKey), data); } /** * 共要加密 * * @param publicKey 公钥 * @param data 待加密的内容 * @return 加密后的内容 */ public static byte[] encrypt(PublicKey publicKey, byte[] data) { return rsa(publicKey, data, Cipher.ENCRYPT_MODE); } /** * 私钥加密,用于 qpp 内,公钥解密 * * @param base64PrivateKey base64 的私钥 * @param data 待加密的内容 * @return 加密后的内容 */ public static byte[] encryptByPrivateKey(String base64PrivateKey, byte[] data) { return encryptByPrivateKey(getPrivateKey(base64PrivateKey), data); } /** * 私钥加密,加密成 base64 字符串,用于 qpp 内,公钥解密 * * @param base64PrivateKey base64 的私钥 * @param data 待加密的内容 * @return 加密后的内容 */ public static String encryptByPrivateKeyToBase64(String base64PrivateKey, byte[] data) { return Base64Utils.encodeToString(encryptByPrivateKey(base64PrivateKey, data)); } /** * 私钥加密,用于 qpp 内,公钥解密 * * @param privateKey 私钥 * @param data 待加密的内容 * @return 加密后的内容 */ public static byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] data) { return rsa(privateKey, data, Cipher.ENCRYPT_MODE); } /** * 公钥加密 * * @param base64PublicKey base64 公钥 * @param data 待加密的内容 * @return 加密后的内容 */ @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 数据 * @return 解密后的数据 */ public static byte[] decrypt(String base64PrivateKey, byte[] data) { return decrypt(getPrivateKey(base64PrivateKey), data); } /** * 解密 * * @param base64publicKey base64 公钥 * @param data 数据 * @return 解密后的数据 */ public static byte[] decryptByPublicKey(String base64publicKey, byte[] data) { return decryptByPublicKey(getPublicKey(base64publicKey), data); } /** * 解密 * * @param privateKey privateKey * @param data 数据 * @return 解密后的数据 */ public static byte[] decrypt(PrivateKey privateKey, byte[] data) { return rsa(privateKey, data, Cipher.DECRYPT_MODE); } /** * 解密 * * @param publicKey PublicKey * @param data 数据 * @return 解密后的数据 */ public static byte[] decryptByPublicKey(PublicKey publicKey, byte[] data) { return rsa(publicKey, data, Cipher.DECRYPT_MODE); } /** * rsa 加、解密 * * @param key key * @param data 数据 * @param mode 模式 * @return 解密后的数据 */ 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 数据解密 * * @param base64PublicKey base64 公钥 * @param base64Data base64数据 * @return 解密后的数据 */ public static byte[] decryptByPublicKeyFromBase64(String base64PublicKey, byte[] base64Data) { return decryptByPublicKey(getPublicKey(base64PublicKey), base64Data); } /** * base64 数据解密 * * @param base64PrivateKey base64 私钥 * @param base64Data base64数据 * @return 解密后的数据 */ @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 数据解密 * * @param base64PrivateKey base64 私钥 * @param base64Data base64数据 * @return 解密后的数据 */ public static byte[] decryptFromBase64(String base64PrivateKey, byte[] base64Data) { return decrypt(base64PrivateKey, Base64Utils.decode(base64Data)); } /** * base64 数据解密 * * @param base64PublicKey base64 公钥 * @param base64Data base64数据 * @return 解密后的数据 */ @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("加密数据:"+encryptToBase64(publicBase64, "hello world")); System.out.println("解密数据:"+decryptFromBase64(privateBase64, encryptToBase64(publicBase64, "hello world"))); String data = "hu5u8UyEg6fcn+/4wKFRSUVGETrXGifVE6/RzRBQCVxAQt+XMA7C+xVR6Ws2ZXFmYVFoS0YL29u6oVkxvmESdRc9Zj/bf0M6ykqa57vyvvRRmrrqCSYUD6STo/QRdPFK4sxlsseTU2/XjZQYohnrMmouYspWykJ3fcN34uoieHc="; // System.out.println("解密数据:"+decryptFromBase64(privateBase64, data)); System.out.println("解密数据:"+RsaUtil.decryptFromBase64(privateBase64, data)); } }
3.16 SpringBootLearningApplication启动类
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. 调用截图
总结
通过本文的详细讲解,我们学习了如何使用Java实现前端公钥加密和后端私钥解密的功能。我们首先介绍了RSA算法的基本原理和应用场景,然后逐步构建了前端和后端的示例代码。通过这些示例代码,读者可以清楚地看到如何生成公钥和私钥、如何在前端使用公钥进行加密、以及如何在后端使用私钥进行解密。希望本文的内容能够帮助大家更好地理解和应用RSA算法,提升Web应用的安全性。同时,我们也提醒大家在实际应用中注意密钥的管理和安全性,确保系统的整体安全。
本文来源于#王佑辉,由@蜜芽 整理发布。如若内容造成侵权/违法违规/事实不符,请联系本站客服处理!
该文章观点仅代表作者本人,不代表本站立场。本站不承担相关法律责任。
如若转载,请注明出处:https://www.zhanid.com/biancheng/2418.html