热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

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

这篇文章主要介绍了Android+Java使用RSA加密实现接口调用时的校验功能,帮助大家更好的利用Android进行开发,感兴趣的朋友可以了解下

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("非法访问");
  }

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

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

可见调用接口前加密成功

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

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

以上就是Android使用RSA加密实现接口调用时的校验功能的详细内容,更多关于Android rsa加密接口调用的资料请关注其它相关文章!


推荐阅读
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
author-avatar
手机用户2502894761
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有