当前位置:   article > 正文

android之Rsa加密,分段公钥加密解密_input must be under 256 bytes

input must be under 256 bytes

使用RSA算法加密

老规矩先说流程:
公钥私钥,一般由服务器生成,有512位的,1024位,2048位的,前面两个已经有破解的方法,建议使用2048位的,记住这个位数。在下面分段加解密有用。公钥可以解密和加密,公钥加密私钥解密,私钥加密公钥解密,有点绕,哈哈哈,客服端放置公钥,私钥放在服务端。我们 第一步也是先加载公钥。如下是服务端的人员给的公钥, 很重要,去掉头和尾(-----BEGIN PUBLIC KEY-----)(-----END PUBLIC KEY-----),只要中间部分,并且去掉/r/n
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw6xG80XOSDJzDynpG+GoKTA2wJK4PDT64VSm7chHJRStyRYJpUPS+VagLhPb3pu7Sc6yjmzdd2GGjlAiJ/yCbSlqqTrsKUC/hdomYBPP9BG7xFgjzJzCBygU/sUgzOEMGWpl8V3ePSO6cGyvU8wgcchS6T/0goHC8gZz/kaFp0msfM0xHB+NmlmZZLF3cZowjyPhW+SmU5O5AVWyMJ29Bm/Cglt6SJ+Ex7/WGPEz8q16tPXbusJCIhrjDs7cKmWXISFfPoxgvtyOE7gbyQeHFbClqjZroAke7pMGFCmUP9/+mLFFkpVjWr3yiS6UyZr0ASxdFYhcO7w1foms/Qzg8QIDAQAB
-----END PUBLIC KEY-----
  • 1
  • 2
  • 3

然后是使用代码加载

private static PublicKey getPublicKey(String publicKeyString) throws Exception{
    String a = publicKeyString.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
    byte[] keyBytes = Base64.decode(a .getBytes(), Base64.DEFAULT);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(keySpec);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.加载完钥匙后,则要开始解密了,然后用base64将数据转成byte数组,再解密即可。注意,这里的填充方式是"RSA/ECB/PKCS1Padding",android里边默认的填充方式是"RSA/None/NoPadding",而服务器默认是前者,这也是导致为什么服务端加密后,客户端无法解出来的一个容易出现的问题

 private static byte[] decrypt(byte[] content, PublicKey privateKey) throws Exception{
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    return cipher.doFinal(content);
  }
  • 1
  • 2
  • 3
  • 4
  • 5

ok,至此就已经完成服务端用私钥加密的数据,客户端用公钥将其解开的流程,接下来看,客户端用公钥加密数据,给服务的代码。加密完后用base64将其转为string,注意编码NO_WRAP,不然又会出现服务器无法解析的情况

private static String encrypted(byte[] content, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    btye[] enContent=cipher.doFinal(content);
    return Base64.encodeToString(enContent, Base64.NO_WRAP)
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

到这里,数据不是很长的情况下呢,已经可以完美的加密解密了,但是一但数据长一些,则需要做分段加解密了

RSA 分段加解密

对于RSA的分段加解密,网上很多误解,说最多RSA最多可以加密多少,解密多少,这都是错误的说法。
还记得刚开始说的2048位的钥匙吗,RSA可以加解密的多大长度取决于密钥的位数

最大解密:钥匙位数 / 8 如果是2048位,则是256
最大加密:钥匙位数 / 8 - 11 如果是2048位,则是245

比如2048位的,解密的内容超过了256字节就会报下面的错误
javax.crypto.IllegalBlockSizeException: input must be under 256 bytes

下面给上完整的代码(还可以优化)

public class RSAUtils {

    /**
     * RSA最大解密密文大小,2048位的公钥,2048/8=256
     */
    private static final int MAX_DECRYPT_BLOCK = 256;

    /**
     * RSA最大加密明文大小,2048位的公钥,2048/8-11=245
     */
    private static final int MAX_ENCRYPT_BLOCK = 245;

    //公钥自行替换掉
    private static String PublicKey= "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw6xG80XOSDJzDynpG+GoKTA2wJK4PDT64VSm7chHJRStyRYJpUPS+VagLhPb3pu7Sc6yjmzdd2GGjlAiJ/yCbSlqqTrsKUC/hdomYBPP9BG7xFgjzJzCBygU/sUgzOEMGWpl8V3ePSO6cGyvU8wgcchS6T/0goHC8gZz/kaFp0msfM0xHB+NmlmZZLF3cZowjyPhW+SmU5O5AVWyMJ29Bm/Cglt6SJ+Ex7/WGPEz8q16tPXbusJCIhrjDs7cKmWXISFfPoxgvtyOE7gbyQeHFbClqjZroAke7pMGFCmUP9/+mLFFkpVjWr3yiS6UyZr0ASxdFYhcO7w1foms/Qzg8QIDAQAB" ;

    /**
     * 加载公钥
     */
    private static PublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
        String key = PublicKey.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
        byte[] keyBytes = Base64.decode(key.getBytes(), Base64.DEFAULT);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 用RSA公钥解密
     *
     * @param data 要解密的数据
     * @return 解密数据
     */
    public static byte[] decryptByRSA1(byte[] data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
        PublicKey pubKey = getPublicKey();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, pubKey);


        int blockCount = (data.length / MAX_DECRYPT_BLOCK);
        if ((data.length % MAX_DECRYPT_BLOCK) != 0) {
            blockCount += 1;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * MAX_DECRYPT_BLOCK);
        for (int offset = 0; offset < data.length; offset += MAX_DECRYPT_BLOCK) {
            int inputLen = (data.length - offset);
            if (inputLen > MAX_DECRYPT_BLOCK) {
                inputLen = MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedBlock = cipher.doFinal(data, offset, inputLen);
            bos.write(decryptedBlock);
        }

        bos.close();
        return bos.toByteArray();

    }

    /**
     * 此方法为解密入口
     * @param data  要解密的json字符串
     * @return   解密后的字符串
     */
    public static String base64Decrypt(String data) {
        byte[] encryptedBytes = {};
        try {
            encryptedBytes = decryptByRSA1(Base64.decode(data.getBytes(), Base64.DEFAULT));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(encryptedBytes);
    }


    /**
     * 此方法为加密入口
     * @param data  要加密的json字符串
     * @return   加密后的字符串
     */
    public static String base64Encrypted(String data) {
        byte[] encryptedBytes = {};
        try {
            encryptedBytes = encrypted(data.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP);
    }


    private static byte[] encrypted(byte[] data) throws Exception {
        PublicKey publicKey = getPublicKey();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        //分段加密
        int blockCount = (data.length / MAX_ENCRYPT_BLOCK);
        if ((data.length % MAX_ENCRYPT_BLOCK) != 0) {
            blockCount += 1;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * MAX_ENCRYPT_BLOCK);
        for (int offset = 0; offset < data.length; offset += MAX_ENCRYPT_BLOCK) {
            int inputLen = (data.length - offset);
            if (inputLen > MAX_ENCRYPT_BLOCK) {
                inputLen = MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen);
            bos.write(encryptedBlock);
        }

        bos.close();
        return bos.toByteArray();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

最后还要感谢以下文章,真的帮了很多,希望后来的人们也可以更少踩坑
https://www.cnblogs.com/yulibostu/articles/9859033.html
https://www.jianshu.com/p/44b3f5f03c78
https://blog.csdn.net/leedaning/article/details/51780511(如果你的后台不明白,还有php的文章赠送)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/308289
推荐阅读
相关标签
  

闽ICP备14008679号