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"
。
填充问题
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"
。