Android+Java中使用RSA加密实现接口调用时的校验功能
場景
RSA加密
RSA算法是一種非對稱加密算法,那么何為非對稱加密算法呢?
一般我們理解上的加密是這樣子進(jìn)行的:原文經(jīng)過了一把鑰匙(密鑰)加密后變成了密文,然后將密文傳遞給接收方,接收方再用這把鑰匙(密鑰)解開密文。在這個(gè)過程中,其實(shí)加密和解密使用的是同一把鑰匙,這種加密方式稱為對稱加密。
而非對稱加密就是和對稱加密相對,加密用的鑰匙和解密所用的鑰匙,并不是同一把鑰匙。非對稱加密首先會(huì)創(chuàng)建兩把鑰匙,而這兩把鑰匙是成對的分別稱為公鑰和私鑰。在進(jìn)行加密時(shí)我們使用公鑰進(jìn)行加密,而在解密的時(shí)候就必須要使用私鑰才能進(jìn)行解密,這就是非對稱加密算法。
假如使用非對稱加密,甲發(fā)送消息給乙,這時(shí)候乙會(huì)預(yù)先創(chuàng)建好兩把鑰匙,私鑰乙自己保存好,然后把公鑰發(fā)送給甲,甲使用公鑰對信息進(jìn)行加密,然后傳給乙。最后乙使用自己的私鑰對數(shù)據(jù)進(jìn)行解密。這個(gè)過程中,公鑰還是有可能被第三者所截獲,但是不同的是,這個(gè)第三者縱然得到了公鑰,也無法解開密文,因?yàn)榻饷苊芪乃枰乃借€從始至終一直在乙的手里。因此這個(gè)過程是安全的。
在一個(gè)Android應(yīng)用中錄音完成后將錄音文件上傳到SpringBoot搭建的后臺(tái)接口中。
由于Android應(yīng)用中沒有登錄功能,所以需要對一串自定義字符串進(jìn)行加密并傳輸,然后在SpringBoot后臺(tái)進(jìn)行解密驗(yàn)證。防止上傳接口暴露。
注:
博客主頁:
https://blog.csdn.net/badao_liumang_qizhi
關(guān)注公眾號
霸道的程序猿
獲取編程相關(guān)電子書、教程推送與免費(fèi)下載。
實(shí)現(xiàn)
首先在SpringBoot端新建一個(gè)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 待加密數(shù)據(jù)* @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;// 對數(shù)據(jù)分段加密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();// 獲取加密內(nèi)容使用base64進(jìn)行編碼,并以UTF-8為標(biāo)準(zhǔn)轉(zhuǎn)化成字符串// 加密后的字符串return new String(Base64.encode((encryptedData)));}/*** RSA解密** @param data 待解密數(shù)據(jù)* @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;// 對數(shù)據(jù)分段解密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();// 解密后的內(nèi)容return new String(decryptedData, "UTF-8");}/*** 簽名** @param data 待簽名數(shù)據(jù)* @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());}/*** 驗(yàn)簽** @param srcData 原始字符串* @param publicKey 公鑰* @param sign 簽名* @return 是否驗(yàn)簽通過*/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 = "待加密的文字內(nèi)容";String encryptData = encrypt(data, getPublicKey(publicKey));System.out.println("加密后內(nèi)容:" + encryptData);// RSA解密String decryptData = decrypt("encryptData ", getPrivateKey(privateKey));System.out.println("解密后內(nèi)容:" + decryptData);// RSA簽名String sign = sign(data, getPrivateKey(privateKey));// RSA驗(yàn)簽boolean result = verify(data, getPublicKey(publicKey), sign);System.out.print("驗(yàn)簽結(jié)果:" + result);*//*} catch (Exception e) {e.printStackTrace();System.out.print("加解密異常");}}*/}然后運(yùn)行此工具類的main方法中的生成密鑰對的方法,獲取到生成的公鑰和密鑰對。
然后將它們賦值到最上面的privateKey和publicKey。
然后在Android端中也新建一個(gè)工具類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 待加密數(shù)據(jù)* @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;// 對數(shù)據(jù)分段加密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();// 獲取加密內(nèi)容使用base64進(jìn)行編碼,并以UTF-8為標(biāo)準(zhǔn)轉(zhuǎn)化成字符串// 加密后的字符串return new String(Base64.encode(encryptedData, Base64.DEFAULT));}}這里的公鑰與上面生成的公鑰一致。
注意著兩個(gè)工具類的區(qū)別
在Android工具類中的Base64引入的是
import android.util.Base64;而在Java中引入的Base64是
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;注意這里為什么不是引用java.util.Base64,因?yàn)闀?huì)有換行導(dǎo)致的轉(zhuǎn)移字符的問題。
然后在Android中對字符串進(jìn)行加密
//獲取加密字符串 String escode = ""; try {escode = RsaUtils.encrypt(key,RsaUtils.getPublicKey(RsaUtils.publicKey));} catch (Exception e) {e.printStackTrace(); }將其作為接口調(diào)用的參數(shù)傳遞到Java中進(jìn)行解密
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("非法訪問");}這樣就限制了只能通過指定的移動(dòng)端對文件上傳接口進(jìn)行訪問。
在移動(dòng)端調(diào)用接口進(jìn)行測試
可見調(diào)用接口前加密成功
并且能用過后臺(tái)接口的解密校驗(yàn)
這樣別的第三方請求接口就沒法請求
總結(jié)
以上是生活随笔為你收集整理的Android+Java中使用RSA加密实现接口调用时的校验功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android中使用retrofit2进
- 下一篇: Android+Java中使用Aes对称