Android RSA 加密

RSA是最流行的公开密钥算法,既能用于加密,也能用于数字签名,属于非对称加密鼻祖。

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。

由于进行的都是大数计算,使得RSA最快的情况也比DES和其它对称算法慢上好几倍。速度一般是RSA的缺陷,所以一般来说只用于少量数据加密。

生成RSA秘钥对

/**
 * 随机生成RSA密钥对
 *
 * @param keyLength 密钥长度,范围:512~2048
 *                  一般1024
 * @return
 */
public static KeyPair generateRSAKeyPair(int keyLength) {
    try {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
        kpg.initialize(keyLength);
        return kpg.genKeyPair();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

 

公钥进行加密:

public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    // 得到公钥
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PublicKey keyPublic = kf.generatePublic(keySpec);
    // 加密数据
    Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
    cp.init(Cipher.ENCRYPT_MODE, keyPublic);
    return cp.doFinal(data);
}

私钥进行解密:

public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
    // 得到私钥
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
    KeyFactory kf = KeyFactory.getInstance(RSA);
    PrivateKey keyPrivate = kf.generatePrivate(keySpec);

    // 解密数据
    Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
    cp.init(Cipher.DECRYPT_MODE, keyPrivate);
    byte[] arr = cp.doFinal(encrypted);
    return arr;

RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes)。RSA 算法规定: 待加密的字节数不能超过密钥的长度除以8再减去11 , 而加密后得到的密文的字节数,正好是密钥长度值除以8.  对于加密数据比较大的情况,可以采用以下分段加密的方式。

公钥进行分段加密:

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;
}

私钥进行分段解密:

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;
}

注意点:

Android 端RSA实现是"RSA/None/NoPadding", java后台端JDK实现是"RSA/None/PKCS1Padding",怎样会造成Android端加密数据在Java后台端无法解密,所以在设置补码方式时统一设置为"RSA/ECB/PKCS1Padding"。

 

项目地址:https://github.com/xiongliang120/EncryptionProject

参考:https://www.cnblogs.com/whoislcj/p/5470095.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值