关于Android解密后端RSA加密的Base64字符串
后端
后端的操作步骤:
- 后端提供了私钥给前端,假设为final String PRIVATE_KEY = “EFAASOAmldEJWeqHnfaDjH1T”;
- 数据先使用公钥通过RSA加密,然后再使用base64转换为字符串;
- 通过openSSL传送给前端;
前端(Android App)
将加密的数据先进行base64解密(用到BASE64.jar点我下载)
数据解密后再通过上述私钥,使用Cipher cipher = Cipher.getInstance(“RSA”)解密得到的数据有乱码
( #牓 {"code":"200","desc":"ok","data":[{"ip":"192.168.6.133","port":1654,"username":"guest","password":"guest"},{"ip":"192s% EH j5 T l V DB$ ԑ= j 855 Z* ~ </ ˠ" + .168.0.115","port":1654,"username":"guest","password":"guest"}]}
查阅相关资料,发现原因是因为RSA加密填充方式问题导致 ,使用"RSA/ECB/PKCS1Padding", 即
Cipher cipher = Cipher.getInstance(“RSA/ECB/PKCS1Padding”)可解决。
具体代码如下:
public static String decrypt(String key, String input) {
try {
byte[] keyBytes = Base64.decode(key.getBytes(), Base64.DEFAULT);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
byte []encrypted = new BASE64Decoder().decodeBuffer(input);
byte []str = decryptByPrivateKey((PrivateKey)privateK, encrypted);
return new String(str, "utf-8");
}catch (Exception e){
e.printStackTrace();
return null;
}
}
private static byte[] decryptByPrivateKey(PrivateKey privateKey, byte[] encryptedData) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(2, privateKey);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
final int BLOCK_SIZE = 128;//注意这里密钥长度为128位
for(int i = 0; inputLen - offSet > 0; offSet = i * BLOCK_SIZE) {
byte[] cache;
if(inputLen - offSet > BLOCK_SIZE) {
cache = cipher.doFinal(encryptedData, offSet, BLOCK_SIZE);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
++i;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
关于RSA的补充
- RSA 加密或签名后的结果是不可读的二进制,使用时经常会转为 BASE64 码再传输。
- RSA 加密时,对要加密数据的大小有限制,最大不大于密钥长度。例如在使用 1024 bit 的密钥时(genrsa -out rsa_private_key.pem 1024),最大可以加密 1024/8=128 Bytes 的数据。数据大于 128 Bytes 时,需要对数据进行分组加密(如果数据超限,加解密时会失败,openssl 函数会返回 RSA 加密时,对要加密数据的大小有限制,最大不大于密钥长度。例如在使用 1024 bit 的密钥时(genrsa -out rsa_private_key.pem 1024),最大可以加密 1024/8=128 Bytes 的数据。数据大于 128 Bytes 时,需要对数据进行分组加密(如果数据超限,加解密时会失败,openssl 函数会返回 false),分组加密后的加密串拼接成一个字符串后发送给客户端。
- 为了保证每次加密的结果都不同,RSA 加密时会在待加密数据后拼接一个随机字符串,再进行加密。不同的填充方式 Padding 表示这个字符串的不同长度,在对超限数据进行分组后,会按照这个 Padding 指定的长度填入随机字符串。例如如果 Padding 填充方式使用默认的 OPENSSL_PKCS1_PADDING(需要占用 11 个字节用于填充),那么明文长度最多只能就是 128-11=117 Bytes。
- 一般默认使用 OPENSSL_PKCS1_PADDING。PHP 支持的 Padding 有 OPENSSL_PKCS1_PADDING、OPENSSL_SSLV23_PADDING、OPENSSL_PKCS1_OAEP_PADDING 和 OPENSSL_NO_PADDING。
- 接收方解密时也需要分组。将加密后的原始二进制数据(对于经过 BASE64 的数据,需要解码),每 128 Bytes 分为一组,然后再进行解密。解密后,根据 Padding 的长度丢弃随机字符串,把得到的原字符串拼接起来,就得到原始报文。
参考
https://blog.youkuaiyun.com/o279642707/article/details/78318636
https://blog.youkuaiyun.com/kikajack/article/details/80703894