RSA Ruby & Android 填充问题

RSA Ruby & Android padding issue

填充问题

1) 我正在 ruby 中使用带有 PKCS1_PADDING 的 public 密钥加密消息。

2) 然后将输出(ASCII-8BIT 编码)转换为十六进制并将其发送到 android 设备。

3) 在 android 将十六进制转换为字节数组并使用私钥解密时,我得到了很多额外的字符。 (在 android 一侧默认为 RSA/NONE/PKCS1Padding)。

示例:

预期字符串:你好,你好吗?

实际字符串:V')f�rBA�;\�:�D�.a�~�A@�.P�(�l�-�ך�\�0}� nj.F��@Ƨ��Wr[��k��Ez��o����r������K����1D������U!��t ��.UI?��gA��|X��o@v��K��Ə������'��n��F������ P��0��9m9*u��٘S��1������<>��L��?��;3����~��-)$������ *"����%/Oѡ��k@��你好吗?

JAVA 代码:

public String Decrypt (String result,String privKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
    PrivateKey privateKey = getPrivateKeyFromString(privKey);
    Cipher cipher1 = Cipher.getInstance("RSA");
    cipher1.init(Cipher.DECRYPT_MODE, privateKey);
    String decrypted="";
    try {
        byte[] bytes = hexStringToByteArray(result);
        byte[] decryptedBytes = cipher1.doFinal(bytes);
         decrypted = new String(decryptedBytes);
    }catch (Exception e)
    {
        e.printStackTrace();
    }
    return decrypted;

}

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len/2];

    for(int i = 0; i < len; i+=2){
        data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
    }

    return data;
}

RUBY 代码:

 require 'openssl'
 require 'base64'

 public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn6fT8ScFrW2FR5bxTeFzsD77nN1W+gL5XUB1yQVNL699y6WISopbQ6lls76XvKfyhJHn7ca8i5rDRXrNnaY1BVvX9n/jKWLw13AQcVG4SjMewMQbW1KXOWFe2cltGxB7dX+4xlnxRtXz26xtOpEoBdMN2LBB39WdMghaLIrzcNu9uj363KK8szs9x9rO9E5BNfaqePFwajJoOXjkc5PUwRHeW2DodQnKfxJhaBwotoBbD6zrx+XPqpEzXD7XLjq2i/MGEuw6XGLCGQ+/zaytiYCDe8gboQ5WkWQtfa0FALve9zguqjpoNouWaK4SBq1kyeFKsdsbmZLC8NdJlSruUQIDAQAB"

 rsa_public_key = OpenSSL::PKey::RSA.new(Base64.decode64(public_key))

 encrypted_string = rsa_public_key.public_encrypt('hello how are you doing ?', OpenSSL::PKey::RSA::PKCS1_PADDING)

 encrypted_string.unpack("H*")

为了获得最大的可移植性,您应该使用 "RSA/ECB/PKCS1Padding" 作为密码的初始化字符串。

这个字符串实际上已经在 Java Standard Algorithm Names 中定义为任何 Java 实现所需要的。当然 Android 还不是正式的 Java,但是你可以肯定 Google 会尝试并确保它会尽可能接近 Java。所以这应该与任何 Java(-ish) 实现兼容。

Sun要求的不是的是操作模式(上面字符串中的"ECB")和填充方案("PKCS1Padding")是默认的"RSA"。这就是为什么你必须明确指定那些。永远不要依赖提供者特定的默认值 - 指定随机数生成器时除外。

您目前得到的是 "RSA/ECB/NoPadding" 方案,它保留所有填充。因此,当您查看以字节为单位的明文大小时,它将与模数的以字节为单位的大小相同。内容将是 PKCS#1-padding,它(大部分)对于每次加密都是随机的。随机字节不能轻易转换为文本,所以你得到的主要是垃圾。


备注:

  • "ECB" Sun 有点用词不当,应该是 "None" 因为只能加密一块明文(一般情况下);
  • 即使 Android 默认使用 UTF-8(Windows 上的 Java 使用 Windows -1252编码!);
  • 最好的随机数生成通常是特定于平台的,因此使用特定算法实际上可能会降低实现的安全性,对于定义不明确的 "SHA1PRNG"