RSA Ruby& Android填充问题

时间:2017-09-10 03:35:50

标签: java android ruby encryption rsa

填充问题

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

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

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

示例:

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

实际字符串:V')f rBA ; \ : D .a 〜 A@ .P ( l - ך \ 0} nj。 ˚F@ƧWr[kEzo偣的 rK1D涮ú!t.UI?GA | XO @vKƏ'nF的 P܆09M9 * U S1和S2;→1; 3_〜 - )$ U *“ %/Oѡ k@ hello你好吗?

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 CODE:

 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*")

1 个答案:

答案 0 :(得分:1)

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

此字符串实际上已在Java Standard Algorithm Names中根据任何Java实现的要求进行了定义。当然Android还没有正式的Java,但是你可以肯定Google会尝试确保Java尽可能接近Java。所以这应该与任何Java(-ish)实现兼容。

Sun要求的原因是上述字符串中的操作模式("ECB")和填充方案("PKCS1Padding")是{{1}的默认值}。这就是你必须明确指定的原因。永远不要依赖提供者特定的默认值 - 除非指定随机数生成器。

您目前获得的是"RSA"方案,它使所有填充完好无损。因此,当您查看以字节为单位的明文大小时,它将与模数的字节大小相同。并且内容将是PKCS#1-padding,其(大部分)随机化用于每个加密。随机字节不能轻易转换为文本,所以你得到的主要看起来像垃圾。

注意:

  • "RSA/ECB/NoPadding"对Sun来说有点用词不当,应该是"ECB",因为只有一个明文块可以加密(一般情况下);
  • 你应该在将字节转换为字符串时明确字符集,即使Android默认使用UTF-8(Windows上的Java使用Windows-1252编码!);
  • 最佳随机数生成通常是特定于平台的,因此使用特定算法实际上可能会降低实施的安全性,对于定义不明确的"None"则更是如此。