RSA PKCS1的爱恨情仇

背景

应业务要求,对接腾讯接口签名参数需要使用RSA加密算法。

 

介绍

RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

简单来说,我们可以用公钥加密私钥解密,或者私钥加密公钥解密,一般私钥是给自己保管,公钥提供出去。

 

生成秘钥

地址:https://uutool.cn/rsa-generate/

 

 

我们可以看到生成秘钥有长度和格式的选择,秘钥长度越长,加密报文的长度就越长(后面有坑),格式有PKCS8和PKCS1还有其他模式,我们要用PKCS1。

 

踩坑实录

 在网上找到一篇RSA加密解密的demo,地址:https://www.lilinchao.com/archives/659.html。

 

 

因为java默认是用pkcs8的,所以我又在网上搜java pkcs1加密字符串,然后就看到有说把PKCS1转换成PKCS8的秘钥(但是业务要求PKCS1),后面又找了几个demo,终于加密成功了(其实是错误的一串东西)。然后我拿着错误的字符串去解密,搞来搞去都搞不定,各种格式不对,解密错误等等异常。。。。。。

后面我在网上直接加密,和我加密出来的根本不一样呀!最后知道真相的我眼泪掉下来。往错误的方向越走越远。

其实那一片博客写得挺清楚了,pkcs1格式只需要加一句代码

static{

java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider() );

}

https://mvnrepository.com/搜索org.bouncycastle,导入两个依赖

 

 

后面还有一个小坑,就是我选择了512长度的秘钥,报文的长度只有53和64,53=512/8-11,64=512/8,如果过长就会报错。如果选择2048的秘钥,就是2048/8的长度。

这样我们需要分段处理。

部分代码

//加密
public static String private_encrypt(String str, String privateKey) throws Exception {
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, priKey);
        byte[] bytes = str.getBytes();
        int inputLen = bytes.length;
        int offLen = 0;//偏移量
        int i = 0;
        ByteArrayOutputStream bops = new ByteArrayOutputStream();
        while (inputLen - offLen > 0) {
            byte[] cache;
            if (inputLen - offLen > 53) {
                cache = cipher.doFinal(bytes, offLen, 53);
            } else {
                cache = cipher.doFinal(bytes, offLen, inputLen - offLen);
            }
            bops.write(cache);
            i++;
            offLen = 53 * i;
        }
        bops.close();
        //String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        byte[] encryptedData = bops.toByteArray();
        String encodeToString = java.util.Base64.getEncoder().encodeToString(encryptedData);
        return encodeToString;
    }

//解密
public static String public_decrypt(String str, String publicKey) throws Exception {

        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        ByteArrayOutputStream bops = new ByteArrayOutputStream();
        byte[] bytes = java.util.Base64.getDecoder().decode(str);;
        int inputLen = bytes.length;
        int offLen = 0;//偏移量
        int i = 0;
        while (inputLen - offLen > 0) {
            byte[] cache;
            if (inputLen - offLen > 64) {
                cache = cipher.doFinal(bytes, offLen, 64);
            } else {
                cache = cipher.doFinal(bytes, offLen, inputLen - offLen);
            }
            bops.write(cache);
            i++;
            offLen = 64 * i;
        }
        bops.close();
        byte[] byteArray = bops.toByteArray();
        System.out.println(new String(byteArray));
        return new String(byteArray);
        //String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
    }

 

会者不难,难者不会,还是要多验证、多思考 

 

posted @ 2022-10-14 11:05  BBI丨BBI  阅读(499)  评论(0编辑  收藏  举报