Android使用RSA加密实现接口调用时的校验功能
作者:霸道的程序猿 发布时间:2023-11-06 15:24:51
RSA算法是一种非对称加密算法,那么何为非对称加密算法呢?
一般我们理解上的加密是这样子进行的:原文经过了一把钥匙(密钥)加密后变成了密文,然后将密文传递给接收方,接收方再用这把钥匙(密钥)解开密文。在这个过程中,其实加密和解密使用的是同一把钥匙,这种加密方式称为对称加密。
而非对称加密就是和对称加密相对,加密用的钥匙和解密所用的钥匙,并不是同一把钥匙。非对称加密首先会创建两把钥匙,而这两把钥匙是成对的分别称为公钥和私钥。在进行加密时我们使用公钥进行加密,而在解密的时候就必须要使用私钥才能进行解密,这就是非对称加密算法。
假如使用非对称加密,甲发送消息给乙,这时候乙会预先创建好两把钥匙,私钥乙自己保存好,然后把公钥发送给甲,甲使用公钥对信息进行加密,然后传给乙。最后乙使用自己的私钥对数据进行解密。这个过程中,公钥还是有可能被第三者所截获,但是不同的是,这个第三者纵然得到了公钥,也无法解开密文,因为解密密文所需要的私钥从始至终一直在乙的手里。因此这个过程是安全的。
在一个Android应用中录音完成后将录音文件上传到SpringBoot搭建的后台接口中。
由于Android应用中没有登录功能,所以需要对一串自定义字符串进行加密并传输,然后在SpringBoot后台进行解密验证。防止上传接口暴露。
实现
首先在SpringBoot端新建一个RsaUtils工具类
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
//java 后端
public class RsaUtils {
//私钥
public static String privateKey = "自己生成的私钥";
//公钥
private static String publicKey = "自己生成的公钥";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 获取密钥对
*
* @return 密钥对
*/
public static KeyPair getKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(1024);
return generator.generateKeyPair();
}
/**
* 获取私钥
*
* @param privateKey 私钥字符串
* @return
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = com.sun.org.apache.xerces.internal.impl.dv.util.Base64.decode(new String(privateKey.getBytes()));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
return keyFactory.generatePrivate(keySpec);
}
/**
* 获取公钥
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
return keyFactory.generatePublic(keySpec);
}
/**
* RSA加密
*
* @param data 待加密数据
* @param publicKey 公钥
* @return
*/
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int inputLen = data.getBytes().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.getBytes(), offset, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
// 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
// 加密后的字符串
return new String(Base64.encode((encryptedData)));
}
/**
* RSA解密
*
* @param data 待解密数据
* @param privateKey 私钥
* @return
*/
public static String decrypt(String data, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] dataBytes = Base64.decode(data);
int inputLen = dataBytes.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(dataBytes, offset, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
// 解密后的内容
return new String(decryptedData, "UTF-8");
}
/**
* 签名
*
* @param data 待签名数据
* @param privateKey 私钥
* @return 签名
*/
public static String sign(String data, PrivateKey privateKey) throws Exception {
byte[] keyBytes = privateKey.getEncoded();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey key = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(key);
signature.update(data.getBytes());
return Base64.encode(signature.sign());
}
/**
* 验签
*
* @param srcData 原始字符串
* @param publicKey 公钥
* @param sign 签名
* @return 是否验签通过
*/
public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
byte[] keyBytes = publicKey.getEncoded();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(key);
signature.update(srcData.getBytes());
return signature.verify(Base64.decode(sign));
}
/* public static void main(String[] args) {
try {
// 生成密钥对
KeyPair keyPair = getKeyPair();
String privateKey = new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()));
String publicKey = new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded()));
System.out.println("私钥:" + privateKey);
System.out.println("公钥:" + publicKey);
// RSA加密
*//* String data = "待加密的文字内容";
String encryptData = encrypt(data, getPublicKey(publicKey));
System.out.println("加密后内容:" + encryptData);
// RSA解密
String decryptData = decrypt("encryptData ", getPrivateKey(privateKey));
System.out.println("解密后内容:" + decryptData);
// RSA签名
String sign = sign(data, getPrivateKey(privateKey));
// RSA验签
boolean result = verify(data, getPublicKey(publicKey), sign);
System.out.print("验签结果:" + result);*//*
} catch (Exception e) {
e.printStackTrace();
System.out.print("加解密异常");
}
}*/
}
然后运行此工具类的main方法中的生成密钥对的方法,获取到生成的公钥和密钥对。
然后将它们赋值到最上面的privateKey和publicKey。
然后在Android端中也新建一个工具类RsaUtils
package com.badao.badaoimclient.common;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RsaUtils{
//公钥
public static String publicKey="跟Java端同样的公钥";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 获取公钥
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey =Base64.decode(publicKey.getBytes(), Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
return keyFactory.generatePublic(keySpec);
}
/**
* RSA加密
*
* @param data 待加密数据
* @param publicKey 公钥
* @return
*/
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher ;
cipher= Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int inputLen = data.getBytes().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.getBytes(), offset, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
// 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
// 加密后的字符串
return new String(Base64.encode(encryptedData, Base64.DEFAULT));
}
}
这里的公钥与上面生成的公钥一致。
注意着两个工具类的区别
在Android工具类中的Base64引入的是
import android.util.Base64;
而在Java中引入的Base64是
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
注意这里为什么不是引用java.util.Base64,因为会有换行导致的转移字符的问题。
然后在Android中对字符串进行加密
//获取加密字符串
String escode = "";
try {
escode = RsaUtils.encrypt(key,RsaUtils.getPublicKey(RsaUtils.publicKey));
} catch (Exception e) {
e.printStackTrace();
}
将其作为接口调用的参数传递到Java中进行解密
if(decode.equals(RsaUtils.decrypt(key,RsaUtils.getPrivateKey(RsaUtils.privateKey))))
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url);
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}else {
return AjaxResult.error("非法访问");
}
这样就限制了只能通过指定的移动端对文件上传接口进行访问。
在移动端调用接口进行测试
可见调用接口前加密成功
并且能用过后台接口的解密校验
这样别的第三方请求接口就没法请求
来源:https://www.cnblogs.com/badaoliumangqizhi/p/14166479.html


猜你喜欢
- 本文实例讲述了Java中的异常和处理机制。分享给大家供大家参考,具体如下:简介程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期
- 在生产型Android客户端软件(企业级应用)开发中,界面可能存在多个输入(EditText)和多个操作(MotionEvent和KeyEv
- 在搜索引擎的开发中,我们需要对Html进行解析。本文介绍C#解析HTML的两种方法。AD: 在搜索引擎的开发中,我们需要对网页的Html内容
- Spring AOP proxyTargetClass的行为要点列表形式proxyTargetClasstrue目标对象实现了接口 – 使用
- Join子句一、简介使用join子句可以将来自不同源序列并且在对象模型中没有直接关系的元素相关联,唯一的要求是每个源中的元素需要共享某个可以
- /// <summary> /// 删除掉空
- BigDecimal 和 0 比较大小调用BigDecimal中的compareTo方法, 如:int i = bigDecimal.com
- 🚀 ChatGPT是最近很热门的AI智能聊天机器人🚀 本文使用SpringBoot+OpenAI的官方API接口,自己实现一个可以返回对话数
- 汉诺塔游戏一旦掌握了规律,其实是有点单调和无聊的,不过却是学习递归的一个绝佳例子,想当初学习老谭C的时候,就卡在这儿好长时间。对初学编程的人
- 目录关于日志级别为什么选用log4j2排除 spring-boot 自带的 logback 依赖添加 log4j2 依赖配置文件节点解析根节
- 众所周知Java中的数据类型是强数据类型,基本数据类型之间的转换尤其固定的规则,当数据宽度比较窄的数据类型(如int)转换成数据类型比较宽的
- // 获取国家省市区信息$(document).ready(function(){//从程序
- 我们日常的工作中都使用开发工具(IntelliJ IDEA 或 Eclipse 等)可以很方便的调试程序,或者是通过打包工具把项目打包成 j
- 1.EazyEmail邮件发送类库Net 类库自带了邮件发送功能。笔者对该类库,从使用的角度进行了二次封装,nuget上可搜索EazyEma
- 1.返回String“长度”方法你如何确定给定String的长度?java提供了一种称为“length()”的方法。将它用于您需要查找Str
- 本文实例总结了C#中WinForm程序退出方法技巧。分享给大家供大家参考。具体分析如下:在c#中退出WinForm程序包括有很多方法,如:t
- 一、题目给出二叉搜索树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值
- 在使用C#进行桌面应用开发中,经常会有对文件进行操作的情况,这时可能会需要对文件夹进行文件扫描,获取所有文件做法如下/// <summ
- C#异步方法返回void和Task的区别如果异步(async关键字)方法有返回值,返回类型为T时,返回类型必然是 Task<T>
- 本文实例为大家分享了Android实现象棋游戏的具体代码,供大家参考,具体内容如下主要是实现两人对战象棋,没有实现人机对战,主要不会判断下一