Android使用RSA加密实现接口调用时的校验功能
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子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
- java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
- TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
android.os.BinderProxy cannot be cast to com解决办法
本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20- 这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
- 下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
- 首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
- 下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
用Intel HAXM给Android模拟器Emulator加速
Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20- 在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
Android开发中布局中的onClick简单完成多控件时的监听的利与弊
本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤
Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20- 这篇文章主要为大家详细介绍了Android实现简单用户注册案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-26