赞
踩
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw6xG80XOSDJzDynpG+GoKTA2wJK4PDT64VSm7chHJRStyRYJpUPS+VagLhPb3pu7Sc6yjmzdd2GGjlAiJ/yCbSlqqTrsKUC/hdomYBPP9BG7xFgjzJzCBygU/sUgzOEMGWpl8V3ePSO6cGyvU8wgcchS6T/0goHC8gZz/kaFp0msfM0xHB+NmlmZZLF3cZowjyPhW+SmU5O5AVWyMJ29Bm/Cglt6SJ+Ex7/WGPEz8q16tPXbusJCIhrjDs7cKmWXISFfPoxgvtyOE7gbyQeHFbClqjZroAke7pMGFCmUP9/+mLFFkpVjWr3yiS6UyZr0ASxdFYhcO7w1foms/Qzg8QIDAQAB
-----END PUBLIC KEY-----
然后是使用代码加载
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);
}
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);
}
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)
}
到这里,数据不是很长的情况下呢,已经可以完美的加密解密了,但是一但数据长一些,则需要做分段加解密了
对于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(); } }
最后还要感谢以下文章,真的帮了很多,希望后来的人们也可以更少踩坑
https://www.cnblogs.com/yulibostu/articles/9859033.html
https://www.jianshu.com/p/44b3f5f03c78
https://blog.csdn.net/leedaning/article/details/51780511(如果你的后台不明白,还有php的文章赠送)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。