素材巴巴 > 程序开发 >

#Android笔记#通过RSA加密请求参数,防止数据被抓包

程序开发 2023-09-09 07:43:32

最近在做南京某高校的电子班牌项目,其中涉及到一些敏感数据,需要做一定的加密处理。正好之前实习的时候,做过一个课程电子书的项目,也是高校相关的,领导希望将其中的课程讲义进行加密处理,防止app被反编译或抓包后泄漏信息,那段时间研究对比了不少加密算法,比如AES、DES、MD5和RSA等(有说说为证~),综合考虑下来,RSA是目前比较靠谱的选择,当时就使用了RSA加密算法,只可惜当时没有记录,现在想用的时候,又得去查阅资料,这次就把它记录下来吧!

RSA加密算法,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,由于无法计算出大数n的欧拉函数phi(N),所以不能根据PK计算出SK。

通过RSA加密请求参数的大致思路就是:客户端通过公钥将请求参数进行加密,服务端拿到加密字符串后通过私钥对请求参数进行解密,并进行对应的业务处理。在实际操作中发现,直接通过RSA加密的字符串是一串类似乱码的字符串,在本地是可以解密的,但是传到服务端后就无法解密了,因此使用了BASE64对数据串进行了编码,服务端再进行一次解码,即可继续进行解密。

下面是一个在Android中实现的例子:

MainActivity.java:

import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;import com.yuyan.rsatest.utils.Base64;
 import com.yuyan.rsatest.utils.RSAUtils;import static com.yuyan.rsatest.utils.Constant.DEFAULT_PRIVATE_KEY;
 import static com.yuyan.rsatest.utils.Constant.DEFAULT_PUBLIC_KEY;public class MainActivity extends AppCompatActivity {private EditText ed_input;private TextView tv_encrypt,tv_decrypt;private Button btn_start;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ed_input = findViewById(R.id.ed_input);tv_encrypt = findViewById(R.id.tv_encrypt);tv_decrypt = findViewById(R.id.tv_decrypt);btn_start = findViewById(R.id.btn_start);btn_start.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String input = ed_input.getText().toString();try {if (!TextUtils.isEmpty(input)) {byte[] data = input.getBytes();//模拟客户端数据通过公钥加密byte[] encryptedByte = RSAUtils.encryptByPublicKey(data, DEFAULT_PUBLIC_KEY);//通过base64编码String encrypted = Base64.encode(encryptedByte);tv_encrypt.setText("加密后的文字:" + encrypted);//解码base64串byte[] decrypted = Base64.decode(encrypted);//模拟服务端数据通过私钥进行解码byte[] decodedData = RSAUtils.decryptByPrivateKey(decrypted,DEFAULT_PRIVATE_KEY);String target = new String(decodedData);tv_decrypt.setText("解密后的文字:" + target);}} catch (Exception e) {e.printStackTrace();}}});}
 }
RSAUtils.java:
import java.io.ByteArrayOutputStream;
 import java.security.Key;
 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.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.HashMap;
 import java.util.Map;import javax.crypto.Cipher;public class RSAUtils {/** *//*** 加密算法RSA*/public static final String KEY_ALGORITHM = "RSA";/** *//*** 签名算法*/public static final String SIGNATURE_ALGORITHM = "MD5withRSA";/** *//*** 获取公钥的key*/private static final String PUBLIC_KEY = "RSAPublicKey";/** *//*** 获取私钥的key*/private static final String PRIVATE_KEY = "RSAPrivateKey";/** *//*** RSA最大加密明文大小*/private static final int MAX_ENCRYPT_BLOCK = 117;/** *//*** RSA最大解密密文大小*/private static final int MAX_DECRYPT_BLOCK = 128;/** *//*** 

* 生成密钥对(公钥和私钥)*

** @return* @throws Exception*/public static Map genKeyPair() throws Exception {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPair keyPair = keyPairGen.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();Map keyMap = new HashMap(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}/** *//***

* 用私钥对信息生成数字签名*

** @param data 已加密数据* @param privateKey 私钥(BASE64编码)** @return* @throws Exception*/public static String sign(byte[] data, String privateKey) throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(privateK);signature.update(data);return Base64Utils.encode(signature.sign());}/** *//***

* 校验数字签名*

** @param data 已加密数据* @param publicKey 公钥(BASE64编码)* @param sign 数字签名** @return* @throws Exception**/public static boolean verify(byte[] data, String publicKey, String sign)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PublicKey publicK = keyFactory.generatePublic(keySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initVerify(publicK);signature.update(data);return signature.verify(Base64Utils.decode(sign));}/** *//***

* 私钥解密*

** @param encryptedData 已加密数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM,"BC");Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE, privateK);int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/** *//***

* 公钥解密*

** @param encryptedData 已加密数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec); // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE, publicK);int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/** *//***

* 公钥加密*

** @param data 源数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, String publicKey)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);// 对数据加密 // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");cipher.init(Cipher.ENCRYPT_MODE, publicK);int inputLen = data.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, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/** *//***

* 私钥加密*

** @param data 源数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, String privateKey)throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");cipher.init(Cipher.ENCRYPT_MODE, privateK);int inputLen = data.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, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/** *//***

* 获取私钥*

** @param keyMap 密钥对* @return* @throws Exception*/public static String getPrivateKey(Map keyMap)throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return Base64Utils.encode(key.getEncoded());}/** *//***

* 获取公钥*

** @param keyMap 密钥对* @return* @throws Exception*/public static String getPublicKey(Map keyMap)throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return Base64Utils.encode(key.getEncoded());}

核心的加密解密代码就是以上这些了,如果想查看整个demo的话,可点击这里下载。

通过这种方式,请求的参数就被加密成了密文了,这样即使别人抓到了你的请求,也不知道该如何去动态抓包你的数据;当然了,他可以直接拿着你的加密串去拿固定的结果,所以最好在数据串中加入时间戳等验证字段或者数字签名等,服务端在验证后再返回结果,虽说在一定程度上牺牲了速度,但是却最大程度的保证了安全。以上。

 

 


标签:

素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。