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

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

后端

后端的操作步骤:

  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* ~ </ ˠ" +   .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的补充

  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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RSA封装类 ,完整的RSA加密解密 public class RSAUtilEncrypt { public static final String KEY_ALGORTHM = "RSA";// public static final String KEY_ALGORTHM_RSA_ECB_PKCS1PADDING = "RSA/ECB/PKCS1Padding"; public static String RSA_PUBLIC_KEY = "rsa_public_key"; public static String RSA_PRIVATE_KEY = "rsa_private_key"; private int KeySize = 1024; private Map keyMap; private static String RSA = "RSA"; private static PublicKey publickey; public RSAUtilEncrypt(int KeySize,String publickey) { this.KeySize = KeySize; try { this.publickey=generatePublicKeyByString(publickey); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private RSAPublicKey generatePublicKeyByString(String publicKeyStr) throws Exception { try { BASE64Decoder base64Decoder = new BASE64Decoder(); byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return (RSAPublicKey) keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("No Algorthm,Checked by cemung!"); } catch (InvalidKeySpecException e) { throw new Exception("InvalidKeySpec!"); } catch (IOException e) { throw new Exception("Io exception!"); } catch (NullPointerException e) { throw new Exception("Illegle pointer reference!"); } } // Encypt public byte[] RSAEncrypt(byte[] data, RSAPublicKey publickey) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORTHM_RSA_ECB_PKCS1PADDING); cipher.init(Cipher.ENCRYPT_MODE, this.publickey); byte[] cipherbytes = cipher.doFinal(data); return cipherbytes; } // Encypt public byte[] RSAEncrypt(byte[] data) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORTHM_RSA_ECB_PKCS1PADDING); cipher.init(Cipher.ENCRYPT_MODE, this.publickey); byte[] cipherbytes = cipher.doFinal(data); return cipherbytes; } // Get Public key with format byte[] public byte[] getPublicKeyByte() { RSAPublicKey pubkey = (RSAPublicKey) keyMap.get(RSA_PUBLIC_KEY); return pubkey.getEncoded(); } public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { byte[] keyBytes = decryptBASE64(key); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception { byte[] keyBytes = decryptBASE64(key); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { byte[] keyBytes = decryptBASE64(key); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } 使用方法 private RSAUtilEncrypt rsa = new RSAUtilEncrypt(1024, publikey); /* * 给信息加密,获取密文 */ public String getCiphertext(String str_encrode) { try { byte[] estr = rsa.RSAEncrypt(str_encrode.getBytes()); // 密文 String ciphertext = Base64.encodeToString(estr, Base64.DEFAULT); return ciphertext; } catch (Exception e) { e.printStackTrace(); } return null; } 有疑问的留言
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值