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

最近在做南京某高校的电子班牌项目,其中涉及到一些敏感数据,需要做一定的加密处理。正好之前实习的时候,做过一个课程电子书的项目,也是高校相关的,领导希望将其中的课程讲义进行加密处理,防止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;

    @Override
    protected 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() {
            @Override
            public 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的话,可点击这里下载。

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

 

 

你可能感兴趣的:(Android笔记)