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方法中的生成密钥对的方法,获取到生成的公钥和密钥对。

Android使用RSA加密实现接口调用时的校验功能

然后将它们赋值到最上面的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("非法访问");
 }

这样就限制了只能通过指定的移动端对文件上传接口进行访问。

在移动端调用接口进行测试

Android使用RSA加密实现接口调用时的校验功能

可见调用接口前加密成功

并且能用过后台接口的解密校验

Android使用RSA加密实现接口调用时的校验功能

这样别的第三方请求接口就没法请求

Android使用RSA加密实现接口调用时的校验功能

来源:https://www.cnblogs.com/badaoliumangqizhi/p/14166479.html

标签:Android,rsa加密,接口调用
0
投稿

猜你喜欢

  • Spring boot集成swagger2生成接口文档的全过程

    2021-07-29 14:28:07
  • Java中ShardingSphere分库分表实战

    2023-11-24 09:20:37
  • Android自定义LinearLayout布局显示不完整的解决方法

    2022-09-14 17:44:16
  • java多线程抓取铃声多多官网的铃声数据

    2023-12-18 23:20:05
  • Mockito mock Kotlin Object类方法报错解决方法

    2022-03-10 15:23:37
  • Java中synchronized关键字修饰方法同步的用法详解

    2022-03-05 07:11:22
  • Android调用相机并将照片存储到sd卡上实现方法

    2023-11-06 00:41:41
  • C# 批处理调用方法

    2021-06-18 17:14:19
  • 新手入门Jvm--jvm概览

    2023-11-09 15:42:31
  • Android之禁止ViewPager滑动实现实例

    2022-03-17 23:55:40
  • android点击无效验证的解决方法

    2022-02-28 03:55:08
  • 使用Flutter开发的抖音国际版实例代码详解

    2023-11-12 09:38:44
  • JAVA读取文件夹大小的几种方法实例

    2021-05-24 21:01:53
  • java 多态与抽象类详解总结

    2022-04-19 10:59:18
  • Java 滑动窗口最大值的实现

    2021-09-10 15:34:20
  • MybatisPlus中@TableField注解的使用详解

    2021-11-01 23:05:35
  • Android 情景模式的设置代码

    2023-09-23 07:26:37
  • Java两种方式实现动态代理

    2022-10-15 22:12:23
  • C#生成注册码的实例代码

    2022-05-16 23:35:58
  • Java多线程的临界资源问题解决方案

    2021-12-29 07:44:35
  • asp之家 软件编程 m.aspxhome.com