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(),inputLen - offset); } out.write(cache,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,MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(dataBytes,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,並以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加密介面呼叫的資料請關注我們其它相關文章!