简介
吹水时间开始了,是这样的,公司自研开发一个app,因为要运营和上架需要办理安全评估,办理中说到公司app有可能会泄露用户信息,对用户信息没有加密,遇到抓包的可能会导致用户信息泄露,这时我想到了RSA加密数据来保护用户信息,所以自己使用好像有点效果。
一、简单使用RSA加密解密
RSA是jdk自带的,不需要依赖
public class RSA{
private static Map<String, String> map = new HashMap<>();
public static void main(String[] args) throws Exception {
String content = "我喜欢你";
genKeyPair();
String publicKey = Encryption(content, map.get("publicKey"));
System.out.println("加密后:"+publicKey);
System.out.println("解密后:"+Decryption(publicKey,map.get("privateKey")));
}
private static String Encryption(String content,String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] decodeBase64 = Base64.decodeBase64(publicKey);
PublicKey rsa = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decodeBase64));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,rsa);
String outStr = Base64.encodeBase64String(cipher.doFinal(content.getBytes()));
return outStr;
}
private static String Decryption(String publicKey, String privateKey)throws Exception{
byte[] publicKeyByte = Base64.decodeBase64(publicKey.getBytes("UTF-8"));
byte[] privateKeyByte = Base64.decodeBase64(privateKey.getBytes("UTF-8"));
RSAPrivateKey generatePublic = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyByte));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, generatePublic);
return new String(cipher.doFinal(publicKeyByte));
}
public static void genKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateK = keyPair.getPrivate();
PublicKey publicK = keyPair.getPublic();
String privateKey = new String(Base64.encodeBase64(privateK.getEncoded()));
String publicKey = new String(Base64.encodeBase64(publicK.getEncoded()));
System.out.println("公钥:"+publicKey);
System.out.println("私钥:"+privateKey);
map.put("publicKey",publicKey);
map.put("privateKey",privateKey);
}
}
结果:
二、Spring Boot 整合 RSA
可以自己生成一个公钥和私钥,也可以在网站中在线生成:http://www.metools.info/code/c80.html
application.yml
#swagger
lanys:
swagger:
title: 牟某公司
description: 牟某公司
termsOfServiceUrl: https://eurasia.plus/swagger-ui.html
ContactName: xxx
ContactUrl: https://eurasia.plus/swagger-ui.html
ContactEmail: 1090613735@qq.com
version: 1.0
public:
kay: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJVBeO0vImDyMvmRV7bgQJxhzOkLtAAUv6UJSMBP3YtWj6/5DNjaD5Ezt7OXqQ/wz9b+FWTNECsCRC7Nc/kvqiIfHZp4yZYtlzXUbRJk0iu4Y1lv6oKHOXjjnxCjmZwSgXuuDOChNMwqv9GhOQSo5X4HNmrUdTSbAUxfJMfu6WMwIDAQAB
private:
kay: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMlUF47S8iYPIy+ZFXtuBAnGHM6Qu0ABS/pQlIwE/di1aPr/kM2NoPkTO3s5epD/DP1v4VZM0QKwJELs1z+S+qIh8dmnjJli2XNdRtEmTSK7hjWW/qgoc5eOOfEKOZnBKBe64M4KE0zCq/0aE5BKjlfgc2atR1NJsBTF8kx+7pYzAgMBAAECgYEAnwoh7f5vsWcF2aTplm6rG/l3aipk8UPU/DFJl26eBOIRwy29+tMl1Xy+4THfw8jnPxFxhZX7Ck+Q5Zlo1FzMRX3Z6ltqCy5H58n4KI7L85MI+dO5l8tjCtxFgNd7NY1gwRjKCjWUsdKqOHzs/+vaeZR1kp2feljTpMBzGGPqS4ECQQD3kU7Er79XuHpk6qK56ihiLT6O8ZnZzhBPRCHq89MIDmt2s13RnSfxEeLZpKlmKLC7VYbZeypoiLxKOdRq1X9BAkEA0C+Y6wUM6h3VC+HzrH5/x++6siHRFwwnDp4U9VmPeesa2a84krNaqptMZtPcm4wr0heDzr5PLksfrSUoYJdscwJAIrBiqB60IfeAdumFuaU82Vzbmi3yT9mW4XR7iC94D3XtyukhKUDrGtVVwwdWkTD8apN2XLzsWU9nisMFp56YwQJAFqFV6hY+dSSRCB2js1h842r3zG1IoUy84iXk+Vam9gXMgWU+rRO6A1mmUHcvP+lYyhmsRkkBqnKYGuYzIWzUaQJBAII0gYs7yRJ4FckmnehD1bMdpgsivlO03qimh7V+fCePG8MMZSq5NFNDP0rogNyo/HLxk5V+tPT05bitJJmHTGM=
注意:公钥和私钥要放为一行,不然会报错。
SecurityParameter
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecurityParameter {
boolean inDecode() default true;
boolean outEncode() default true;
}
RsaDecodeRequestBodyAdvice
请求我们接口前做数据处理
@ControllerAdvice("com.example.materialboot.modules.usercontroller.conterller")
@Slf4j
public class RsaDecodeRequestBodyAdvice implements RequestBodyAdvice {
@Value("${lanys.private.kay}")
public String privateKay;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
SecurityParameter methodAnnotation = methodParameter.getMethodAnnotation(SecurityParameter.class);
encode = methodAnnotation.inDecode();
}
if (encode) {
log.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
return new MyHttpInputMessage(httpInputMessage);
} else {
return httpInputMessage;
}
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
class MyHttpInputMessage implements HttpInputMessage {
private HttpHeaders httpHeaders;
private InputStream inputStream;
public MyHttpInputMessage(HttpInputMessage httpInputMessage) throws IOException {
this.httpHeaders = httpInputMessage.getHeaders();
String easpString = easpString(IOUtils.toString(httpInputMessage.getBody(), "UTF-8"));
this.inputStream = IOUtils.toInputStream(RSAUtils.decryptDataOnJava(easpString,privateKay));
}
@Override
public InputStream getBody() throws IOException {
return this.inputStream;
}
@Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
public String easpString(String requestData){
if (requestData != null && !requestData.isEmpty()){
String s = "{\"requestData\":";
if (!requestData.startsWith(s)){
throw new RuntimeException("参数【requestData】缺失异常!");
}
int closeLen = requestData.length()-1;
int openLen = "{\"requestData\":".length();
String substring = StringUtils.substring(requestData, openLen, closeLen);
return substring;
}
return null;
}
}
}
EncodeResponseBodyAdvice
获取数据响应时做处理
@Component
@ControllerAdvice("com.example.materialboot.modules.usercontroller.conterller")
@Slf4j
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
@Autowired
private RsaUtil rsaUtil;
@Value("${lanys.public.kay}")
public String publicKay;
@Value("${lanys.private.kay}")
public String privateKay;
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
log.info("------响应数据加密-------");
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
encode = serializedField.outEncode();
}
if (encode) {
log.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
ObjectMapper objectMapper = new ObjectMapper();
try {
String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
String aseKey = getRandomString(16);
String encrypted = RSAUtils.encryptedDataOnJava(aseKey, publicKay);
String requestData = AesEncryptUtils.encrypt(result, aseKey);
System.out.println("解密:"+AesEncryptUtils.decrypt(requestData,aseKey));
Map<String, String> map = new HashMap<>();
map.put("encrypted", encrypted);
map.put("requestData", requestData);
return map;
} catch (Exception e) {
e.printStackTrace();
log.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
}
}
return body;
}
public static String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
RSAUtils
public class RSAUtils {
public static final String KEY_ALGORITHM = "RSA";
private static final int MAX_ENCRYPT_BLOCK = 117;
private static final int MAX_DECRYPT_BLOCK = 128;
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(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 decryptDataOnJava(String data, String PRIVATEKEY) {
String temp = "";
try {
byte[] rs = Base64.decodeBase64(data);
temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return temp;
}
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
byte[] keyBytes = Base64.decodeBase64(publicKey);
Key publicK = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(keyBytes));
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
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;
}
public static String encryptedDataOnJava(String data, String PUBLICKEY) {
try {
data = Base64.encodeBase64String(encryptByPublicKey(data.getBytes(), PUBLICKEY));
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
}
AesEncryptUtils
前端工具:前端传过来的数据也是加密的,我们也会解密
public class AesEncryptUtils {
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
public static String encrypt(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
byte[] b = cipher.doFinal(content.getBytes("utf-8"));
return Base64.encodeBase64String(b);
}
@Value("${lanys.public.kay}")
public String publicKay;
@Value("${lanys.private.kay}")
public String privateKay;
public static String decrypt(String encryptStr, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] encryptBytes = Base64.decodeBase64(encryptStr);
System.out.println(encryptBytes.length);
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
}
2.读入数据
代码如下(示例):
data = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
UserController
@Api(tags = "用户管理")
@RestController
@RequestMapping("v1/user")
public class UserController {
@Autowired
private SysUserService userService;
@SecurityParameter(inDecode = false,outEncode = true)
@GetMapping("list")
@RequiresPermissions("sys:user:save,sys:role:select")
@ApiImplicitParams({ @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "token", required = true, paramType = "header")})
public Result UserList(){
return Result.success().put(userService.userList());
}
}
这时响应加密: encrypted:是加密后的公钥,只需要前端用私钥进行解密获取生成的解密数据秘钥,在根据获取的秘钥对数据进行解密就能获取所响应的数据类型 requestData:指的是加密后的数据
解密测试
@ApiOperation(value = "解密测试")
@PostMapping("/decryption")
@ApiImplicitParam(name = "data",value = "数据",paramType = "query")
@ResponseBody
public Result decryption(String key,String data) throws Exception {
String decryptDataOnJava = RSAUtils.decryptDataOnJava(key, privateKay);
String decrypt = AesEncryptUtils.decrypt(data, decryptDataOnJava);
JSONObject jsonObject = JSON.parseObject(decrypt);
String jsonData = jsonObject.getString("data");
List<SysUser> dataArr = JSONArray.parseArray(jsonData,SysUser.class);
System.out.println(decrypt);
return Result.success().put(dataArr);
}
总结
最后解密后是String类型的数据,输出是JSON的样子,需要JSON对数据进行转换就可以转换自己原有的数据类型,我是参考网上的案例进行使用,其中也有自己改的代码,吹水结束。
|