非对称加密之RSA算法


该系列文章列表

1.网络及数据安全概念及领域概述
网络安全之数据加密/解密/签名/验签/数字证书
2.对称加密/解密算法
对称加密算法之高级数据加密标准-AES
对称加密之三重DES—DESede
对称加密算法之DES

3.非对称加密/解密算法
非对称加密算法概述
非对称加密之密钥交换算法-DH
非对称加密之RSA算法
非对称加密之Curve25519加密算法
4.其他加密解密算法
异或加密算法
5. 消息摘要算法
SHA安全散列算法
6. 数字证书
7. 网络安全协议

1. RSA算法简述

在DH算法的基础上,RSA算法、ElGamal算法及ECC算法等被提出。
RSA算法基于大数因子分解难题, 而ElGamal算法和ECC算法则是基于离散对数难题。
目前,主流计算机语言都提供了对RSA算法的支持。Java中可以很方便地构建该算法。

RSA在1978年,由麻省理工学院(MIT)的Ron Rivest、Adi Shamir和Leonard Adleman三位学者提出,以三位学者姓氏开头字母命名,被成为RSA算法。

RSA算法是唯一被广泛接受并实现的通用公开加密算法,目前已经成为非对称加密算法国际标准。RSA算法也被用于数字签名。

RSA想对于对称加密算法而言,其算法速度要慢得多。

RSA算法是最流行的公钥密码算法,使用长度可以变化的密钥。

2. 模型分析

下面以Alice与Bob双方收发消息为例,说明是RSA进行数据加密/解密的交互流程。这里Alice作为消息发送方,Bob作为消息接收方。Alice与Bob双方在消息传递之前已将RSA算法作为消息传递的加密算法。具体交互流程如下:

在这里插入图片描述

  1. 密钥构建及发布

步骤1、2为密钥构建及发布流程。

  1. 构建加密消息传递

步骤3、4、5为构建加密消息传递流程, Alice(发送者)向Bob(接收者)发送RSA算法加密数据

步骤6、7、8, Bob(接收者)向Alice(发送者)回复RSA算法加密的数据

特别说明:非对称加密算法领域中,对于私钥加密的数据只能使用公钥解密。对于公钥加密的数据,只能使用私钥解密。
简言之,“私钥加密,公钥解密”或者“公钥加密,私钥解密”。

在传递过程中,公钥可能被截获,截获的加码数据也可能被破解。所以要建立更安全的加密消息传递模型,就需要甲乙方构建两套非对称加密算法密钥,仅遵循“私钥加密,公钥解密”的方式进行加密消息传递。

3.代码实现

RSA算法较DH算法在密钥管理及实现上较为简单,一方面,甲方保留了私钥,而将公钥公布于乙方,甲乙双方密钥一一对应; 另一方面,私钥用于解密,公钥则用于加密,反之亦然。RSA算法仅需要一套密钥即可完成加密/解密操作。Java与Bouncy Castle都对RSA提供了实现,具体实现细节如下:

算法密钥长度密钥默认长度工作模式填充模式备注
RSA512~65536位(密钥长度必须是64的倍数)1024ECBNoPadding、PKCS1Padding、OAEPWITHMD5AndMGF1Padding、 OAEPWITHSHA1AndMGF1Padding、OAEPWITHSHA256AndMGF1Padding、OAEPWITHSHA384AndMGF1Padding、OAEPWITHSHA512AndMGF1PaddingJava6
RSA512~65536位(密钥长度必须是64的倍数)2048NONENoPadding、PKCS1Padding、OAEPWITHMD5AndMGF1Padding、 OAEPWITHSHA1AndMGF1Padding、OAEPWITHSHA224AndMGF1Padding、OAEPWITHSHA256AndMGF1Padding、OAEPWITHSHA384AndMGF1Padding、OAEPWITHSHA512AndMGF1Padding、ISO9796-1PaddingBouncy Castle实现

3.1 算法实现

算法基于Java的实现

package com.calvin.android.secrity;

/**
 * Author:cl
 * Email:lhzheng@grandstream.cn
 * Date:20-10-20
 */

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
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;

/**
 * RSA安全编码组件
 */
public class RSACoder {
	//密钥生成算法
    public static final String KEY_ALGORITHM = "RSA";
    //数据加密算法
    public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";//加密填充方式
    //公钥 Map Key
    private static final String PUBLIC_KEY = "RSAPublicKey";
    //私钥Map key
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * RSA密钥长度,默认1024位,密钥长度必须是64的倍数,范围512~65536位之间
     */
    private static final int KEY_SIZE = 512;

    /**
     * 私钥解密
     * @param data 待解密数据
     * @param key 私钥
     * @return byte[] 解密数据
     * @throws Exception 异常
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //对数据解密
        //指定具体加密算法时 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥加密
     * @param data 待加密数据
     * @param key 私钥
     * @return byte[] 加密数据
     * @throws Exception 异常
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //对数据加密 
        //指定具体加密算法时 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 公钥
     * @return byte[] 解密数据
     * @throws Exception 异常
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //对数据解密
        //指定具体加密算法时 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key 公钥
     * @return byte[] 加密数据
     * @throws Exception 异常
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //对数据解密
        //指定具体加密算法时 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    public static Map<String, Object> initKey() throws Exception {
        //实例化密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥对生辰其
        keyPairGen.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        //公钥
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        //私钥
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        //封装密钥
        Map<String, Object> keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    public static byte[] getPublicKey(Map<String, Object> keyMap){

        return  ((RSAPublicKey)keyMap.get(PUBLIC_KEY)).getEncoded();
    }

    public static byte[] getPrivateKey(Map<String, Object> keyMap){
        return  ((RSAPrivateKey)keyMap.get(PRIVATE_KEY)).getEncoded();

    }
}

3.2 测试代码

android 单元测试代码

@Test
    public void RSATest() throws Exception {
        //初始化密钥
        Map<String, Object> keyMap = RSACoder.initKey();
        byte[] publicKey = RSACoder.getPublicKey(keyMap);
        byte[] privateKey = RSACoder.getPrivateKey(keyMap);
        System.out.println("公钥:\n"+Base64.encodeToString(publicKey, Base64.DEFAULT));
        System.out.println("私钥:\n"+Base64.encodeToString(privateKey, Base64.DEFAULT));
        System.out.println("\n ----私钥加密--公钥解密----");
        String inputStr1 = "RSA加密算法";
        byte[] data1 = inputStr1.getBytes();
        System.out.println("原文:\n "+inputStr1);
        //加密
        byte[] encodedData1 = RSACoder.encryptByPrivateKey(data1, privateKey);
        System.out.println("加密后:\n "+Base64.encodeToString(encodedData1, Base64.DEFAULT));

        //解密
        byte[] decodedData1 = RSACoder.decryptByPublicKey(encodedData1, publicKey);
        String outputStr1 = new String(decodedData1);
        System.out.println("解密后:\n "+outputStr1);
        assertEquals(inputStr1, outputStr1);
        System.out.println("\n ----公钥加密--私钥解密----");
        String inputStr2 = "RSA Encrypt Algorithm";
        byte[] data2 = inputStr2.getBytes();
        System.out.println("原文:\n "+inputStr2);
        //加密
        byte[] encodedData2 = RSACoder.encryptByPublicKey(data2, publicKey);
        System.out.println("加密后:\n "+Base64.encodeToString(encodedData2, Base64.DEFAULT));
        //解密
        byte[] decodedData2 = RSACoder.decryptByPrivateKey(encodedData2, privateKey);
        String outputStr2 = new String(decodedData2);
        System.out.println("解密后:\n "+outputStr2);
        //校验证
        assertEquals(inputStr2, outputStr2);
    }

3.3 测试结果

android7.0下的运行结果

2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: 公钥:
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL5gzKOXMyj7+YAxYzxtjfmsWIviUATR/zTms4YoHGNu
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: gyia00naRS0QDm2Q0iMMWdwgEHrLQT6IoW+nnWWlqwcCAwEAAQ==
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: 私钥:
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAvmDMo5czKPv5gDFjPG2N+axYi+JQ
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: BNH/NOazhigcY26DKJrTSdpFLRAObZDSIwxZ3CAQestBPoihb6edZaWrBwIDAQABAkAjy0tujqUd
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: 1ZJpmd+QowCIqvDTDDADWABlz+J9HNmJkBA5w/Npg3eu5rYIZo9mkOtEp8A74ghQIJrN1BeoiNHx
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: AiEA9Wr/At1DURtbHio3c9JKwBoI8EbU4clUqHTPGiWzDZ0CIQDGlkFqLTR+GKNCeIXf2amWUXbN
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: Biq5VLDGRx20+WIL8wIhAL0Y6U8Kr/DRtD6k5r9OfJxSMyr4WNV0bM+z2VPbUoCdAiEArnqj3NL8
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: 9PFWt/dGwIfwXZcTx01sykrjykH/ktstzwsCIQDETuncItM2NW3ol+G0woBElkaPrdANYhmWjOG9
2020-10-20 09:57:42.066 4810-4827/com.calvin.android.sample I/System.out: FOG4Lw==
2020-10-20 09:57:42.067 4810-4827/com.calvin.android.sample I/System.out:  ----私钥加密--公钥解密----
2020-10-20 09:57:42.067 4810-4827/com.calvin.android.sample I/System.out: 原文:
2020-10-20 09:57:42.067 4810-4827/com.calvin.android.sample I/System.out:  RSA加密算法
2020-10-20 09:57:42.071 4810-4827/com.calvin.android.sample I/System.out: 加密后:
2020-10-20 09:57:42.071 4810-4827/com.calvin.android.sample I/System.out:  pOqsIefLKzH55AytuUzbxoTj9xpYdDfIqCHAF7f+/9KCEti/qMI4gc3Xbz7NWy7Y9qQxLKCBv9QU
2020-10-20 09:57:42.071 4810-4827/com.calvin.android.sample I/System.out: rmYcnyJ61A==
2020-10-20 09:57:42.072 4810-4827/com.calvin.android.sample I/System.out: 解密后:
2020-10-20 09:57:42.072 4810-4827/com.calvin.android.sample I/System.out:  RSA加密算法
2020-10-20 09:57:42.072 4810-4827/com.calvin.android.sample I/System.out:  ----公钥加密--私钥解密----
2020-10-20 09:57:42.072 4810-4827/com.calvin.android.sample I/System.out: 原文:
2020-10-20 09:57:42.072 4810-4827/com.calvin.android.sample I/System.out:  RSA Encrypt Algorithm
2020-10-20 09:57:42.073 4810-4827/com.calvin.android.sample I/System.out: 加密后:
2020-10-20 09:57:42.073 4810-4827/com.calvin.android.sample I/System.out:  IQovrNhy9tcV8BzT7kxeuACfh+wFkhUWjVHbJBsduGDZUmIygzJVNFQMeMj0pKNUIJilNOyvWjGs
2020-10-20 09:57:42.074 4810-4827/com.calvin.android.sample I/System.out: Q9sOAdEiWw==
2020-10-20 09:57:42.075 4810-4827/com.calvin.android.sample I/System.out: 解密后:
2020-10-20 09:57:42.075 4810-4827/com.calvin.android.sample I/System.out:  RSA Encrypt Algorithm

4. 算法实现分析

RSA算法原理如下:

1.随机选择两个大质数p和q,p不等于q,计算N=pq;
2.选择一个大于1小于N的自然数e,e必须与(p-1)(q-1)互素。
3.用公式计算出d:d×e = 1 (mod (p-1)(q-1)) 。
4.销毁p和q。

最终得到的N和e就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。

RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,这是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥,但RSA仍然不失为一种高强度的算法。

5. 数据分段处理

关于加密填充方式:之前以为上面这些操作就能实现rsa加解密,以为万事大吉了,呵呵,这事还没完,悲剧还是发生了,Android这边加密过的数据,服务器端死活解密不了,原来android系统的RSA实现是"RSA/None/NoPadding",而标准JDK实现是"RSA/None/PKCS1Padding" ,这造成了在android机上加密后无法在服务器上解密的原因,所以在实现的时候这个一定要注意。

public static final String RSA = "RSA";// 非对称加密密钥算法
public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式

实现分段加密:搞定了填充方式之后又自信的认为万事大吉了,可是意外还是发生了,RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes) , RSA 是常用的非对称加密算法。最近使用时却出现了“不正确的长度”的异常,研究发现是由于待加密的数据超长所致。RSA 算法规定:待加密的字节数不能超过密钥的长度值除以 8 再减去 11(即:KeySize / 8 - 11),而加密后得到密文的字节数,正好是密钥的长度值除以 8(即:KeySize / 8)。

public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
    public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes();    // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
    public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数

公钥分段加密

/**
     * 用公钥对字符串进行分段加密
     *
     */
    public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception {
        int dataLen = data.length;
        if (dataLen <= DEFAULT_BUFFERSIZE) {
            return encryptByPublicKey(data, publicKey);
        }
        List<Byte> allBytes = new ArrayList<Byte>(2048);
        int bufIndex = 0;
        int subDataLoop = 0;
        byte[] buf = new byte[DEFAULT_BUFFERSIZE];
        for (int i = 0; i < dataLen; i++) {
            buf[bufIndex] = data[i];
            if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
                subDataLoop++;
                if (subDataLoop != 1) {
                    for (byte b : DEFAULT_SPLIT) {
                        allBytes.add(b);
                    }
                }
                byte[] encryptBytes = encryptByPublicKey(buf, publicKey);
                for (byte b : encryptBytes) {
                    allBytes.add(b);
                }
                bufIndex = 0;
                if (i == dataLen - 1) {
                    buf = null;
                } else {
                    buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
                }
            }
        }
        byte[] bytes = new byte[allBytes.size()];
        {
            int i = 0;
            for (Byte b : allBytes) {
                bytes[i++] = b.byteValue();
            }
        }
        return bytes;
    }

私钥分段加密

 /**
     * 分段加密
     *
     * @param data       要加密的原始数据
     * @param privateKey 秘钥
     */
    public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
        int dataLen = data.length;
        if (dataLen <= DEFAULT_BUFFERSIZE) {
            return encryptByPrivateKey(data, privateKey);
        }
        List<Byte> allBytes = new ArrayList<Byte>(2048);
        int bufIndex = 0;
        int subDataLoop = 0;
        byte[] buf = new byte[DEFAULT_BUFFERSIZE];
        for (int i = 0; i < dataLen; i++) {
            buf[bufIndex] = data[i];
            if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
                subDataLoop++;
                if (subDataLoop != 1) {
                    for (byte b : DEFAULT_SPLIT) {
                        allBytes.add(b);
                    }
                }
                byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
                for (byte b : encryptBytes) {
                    allBytes.add(b);
                }
                bufIndex = 0;
                if (i == dataLen - 1) {
                    buf = null;
                } else {
                    buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
                }
            }
        }
        byte[] bytes = new byte[allBytes.size()];
        {
            int i = 0;
            for (Byte b : allBytes) {
                bytes[i++] = b.byteValue();
            }
        }
        return bytes;
    }

公钥分段解密

/**
     * 公钥分段解密
     *
     * @param encrypted 待解密数据
     * @param publicKey 密钥
     */
    public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
        int splitLen = DEFAULT_SPLIT.length;
        if (splitLen <= 0) {
            return decryptByPublicKey(encrypted, publicKey);
        }
        int dataLen = encrypted.length;
        List<Byte> allBytes = new ArrayList<Byte>(1024);
        int latestStartIndex = 0;
        for (int i = 0; i < dataLen; i++) {
            byte bt = encrypted[i];
            boolean isMatchSplit = false;
            if (i == dataLen - 1) {
                // 到data的最后了
                byte[] part = new byte[dataLen - latestStartIndex];
                System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
                byte[] decryptPart = decryptByPublicKey(part, publicKey);
                for (byte b : decryptPart) {
                    allBytes.add(b);
                }
                latestStartIndex = i + splitLen;
                i = latestStartIndex - 1;
            } else if (bt == DEFAULT_SPLIT[0]) {
                // 这个是以split[0]开头
                if (splitLen > 1) {
                    if (i + splitLen < dataLen) {
                        // 没有超出data的范围
                        for (int j = 1; j < splitLen; j++) {
                            if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
                                break;
                            }
                            if (j == splitLen - 1) {
                                // 验证到split的最后一位,都没有break,则表明已经确认是split段
                                isMatchSplit = true;
                            }
                        }
                    }
                } else {
                    // split只有一位,则已经匹配了
                    isMatchSplit = true;
                }
            }
            if (isMatchSplit) {
                byte[] part = new byte[i - latestStartIndex];
                System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
                byte[] decryptPart = decryptByPublicKey(part, publicKey);
                for (byte b : decryptPart) {
                    allBytes.add(b);
                }
                latestStartIndex = i + splitLen;
                i = latestStartIndex - 1;
            }
        }
        byte[] bytes = new byte[allBytes.size()];
        {
            int i = 0;
            for (Byte b : allBytes) {
                bytes[i++] = b.byteValue();
            }
        }
        return bytes;
    }

私钥分段解密

/**
     * 使用私钥分段解密
     *
     */
    public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
        int splitLen = DEFAULT_SPLIT.length;
        if (splitLen <= 0) {
            return decryptByPrivateKey(encrypted, privateKey);
        }
        int dataLen = encrypted.length;
        List<Byte> allBytes = new ArrayList<Byte>(1024);
        int latestStartIndex = 0;
        for (int i = 0; i < dataLen; i++) {
            byte bt = encrypted[i];
            boolean isMatchSplit = false;
            if (i == dataLen - 1) {
                // 到data的最后了
                byte[] part = new byte[dataLen - latestStartIndex];
                System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
                byte[] decryptPart = decryptByPrivateKey(part, privateKey);
                for (byte b : decryptPart) {
                    allBytes.add(b);
                }
                latestStartIndex = i + splitLen;
                i = latestStartIndex - 1;
            } else if (bt == DEFAULT_SPLIT[0]) {
                // 这个是以split[0]开头
                if (splitLen > 1) {
                    if (i + splitLen < dataLen) {
                        // 没有超出data的范围
                        for (int j = 1; j < splitLen; j++) {
                            if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
                                break;
                            }
                            if (j == splitLen - 1) {
                                // 验证到split的最后一位,都没有break,则表明已经确认是split段
                                isMatchSplit = true;
                            }
                        }
                    }
                } else {
                    // split只有一位,则已经匹配了
                    isMatchSplit = true;
                }
            }
            if (isMatchSplit) {
                byte[] part = new byte[i - latestStartIndex];
                System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
                byte[] decryptPart = decryptByPrivateKey(part, privateKey);
                for (byte b : decryptPart) {
                    allBytes.add(b);
                }
                latestStartIndex = i + splitLen;
                i = latestStartIndex - 1;
            }
        }
        byte[] bytes = new byte[allBytes.size()];
        {
            int i = 0;
            for (Byte b : allBytes) {
                bytes[i++] = b.byteValue();
            }
        }
        return bytes;
    }

这样总算把遇见的问题解决了,项目中使用的方案是客户端公钥加密,服务器私钥解密,服务器开发人员说是出于效率考虑,所以还是自己写了个程序测试一下真正的效率

第一步:准备100条对象数据

List<Person> personList=new ArrayList<>();
        int testMaxCount=100;//测试的最大数据条数
        //添加测试数据
        for(int i=0;i<testMaxCount;i++){
            Person person =new Person();
            person.setAge(i);
            person.setName(String.valueOf(i));
            personList.add(person);
        }
        //FastJson生成json数据

        String jsonData=JsonUtils.objectToJsonForFastJson(personList);

        Log.e("MainActivity","加密前json数据 ---->"+jsonData);
        Log.e("MainActivity","加密前json数据长度 ---->"+jsonData.length());

第二步生成秘钥对

KeyPair keyPair=RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE);
    // 公钥
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    // 私钥
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

接下来分别使用公钥加密 私钥解密 私钥加密 公钥解密

//公钥加密
        long start=System.currentTimeMillis();
        byte[] encryptBytes=    RSAUtils.encryptByPublicKeyForSpilt(jsonData.getBytes(),publicKey.getEncoded());
        long end=System.currentTimeMillis();
        Log.e("MainActivity","公钥加密耗时 cost time---->"+(end-start));
        String encryStr=Base64Encoder.encode(encryptBytes);
        Log.e("MainActivity","加密后json数据 --1-->"+encryStr);
        Log.e("MainActivity","加密后json数据长度 --1-->"+encryStr.length());
        //私钥解密
        start=System.currentTimeMillis();
        byte[] decryptBytes=  RSAUtils.decryptByPrivateKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),privateKey.getEncoded());
        String decryStr=new String(decryptBytes);
        end=System.currentTimeMillis();
        Log.e("MainActivity","私钥解密耗时 cost time---->"+(end-start));
        Log.e("MainActivity","解密后json数据 --1-->"+decryStr);

        //私钥加密
        start=System.currentTimeMillis();
        encryptBytes=    RSAUtils.encryptByPrivateKeyForSpilt(jsonData.getBytes(),privateKey.getEncoded());
        end=System.currentTimeMillis();
        Log.e("MainActivity","私钥加密密耗时 cost time---->"+(end-start));
        encryStr=Base64Encoder.encode(encryptBytes);
        Log.e("MainActivity","加密后json数据 --2-->"+encryStr);
        Log.e("MainActivity","加密后json数据长度 --2-->"+encryStr.length());
        //公钥解密
        start=System.currentTimeMillis();
        decryptBytes=  RSAUtils.decryptByPublicKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),publicKey.getEncoded());
        decryStr=new String(decryptBytes);
        end=System.currentTimeMillis();
        Log.e("MainActivity","公钥解密耗时 cost time---->"+(end-start));
        Log.e("MainActivity","解密后json数据 --2-->"+decryStr);

运行结果:

在这里插入图片描述

对比发现:私钥的加解密都很耗时,所以可以根据不同的需求采用不能方案来进行加解密。个人觉得服务器要求解密效率高,客户端私钥加密,服务器公钥解密比较好一点
在这里插入图片描述

加密后数据大小的变化:数据量差不多是加密前的1.5倍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值