关于Android解密后端RSA加密的Base64字符串

关于Android解密后端RSA加密的Base64字符串

    • 后端
    • 前端(Android App)
    • 关于RSA的补充
    • 参考

后端

后端的操作步骤:

  1. 后端提供了私钥给前端,假设为final String PRIVATE_KEY = “EFAASOAmldEJWeqHnfaDjH1T”;
  2. 数据先使用公钥通过RSA加密,然后再使用base64转换为字符串;
  3. 通过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* ~ 

查阅相关资料,发现原因是因为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的补充

  1. RSA 加密或签名后的结果是不可读的二进制,使用时经常会转为 BASE64 码再传输。
  2. 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),分组加密后的加密串拼接成一个字符串后发送给客户端。
  3. 为了保证每次加密的结果都不同,RSA 加密时会在待加密数据后拼接一个随机字符串,再进行加密。不同的填充方式 Padding 表示这个字符串的不同长度,在对超限数据进行分组后,会按照这个 Padding 指定的长度填入随机字符串。例如如果 Padding 填充方式使用默认的 OPENSSL_PKCS1_PADDING(需要占用 11 个字节用于填充),那么明文长度最多只能就是 128-11=117 Bytes。
  4. 一般默认使用 OPENSSL_PKCS1_PADDING。PHP 支持的 Padding 有 OPENSSL_PKCS1_PADDING、OPENSSL_SSLV23_PADDING、OPENSSL_PKCS1_OAEP_PADDING 和 OPENSSL_NO_PADDING。
  5. 接收方解密时也需要分组。将加密后的原始二进制数据(对于经过 BASE64 的数据,需要解码),每 128 Bytes 分为一组,然后再进行解密。解密后,根据 Padding 的长度丢弃随机字符串,把得到的原字符串拼接起来,就得到原始报文。

参考

https://blog.csdn.net/o279642707/article/details/78318636
https://blog.csdn.net/kikajack/article/details/80703894

你可能感兴趣的:(Android,RSA,Android,BASE64)