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"))); }
会者不难,难者不会,还是要多验证、多思考