Android 和 Java 中的 RSA 加密
RSA encryption in Android and Java
我想用 RSA 加密来加密一个字符串。我的 public/private 密钥已生成并存储在数据库中。在 android 中,我使用此代码:
public static String encryptRSAToString(String text, String strPublicKey) {
byte[] cipherText = null;
String strEncryInfoData="";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strPublicKey.trim().getBytes(), Base64.DEFAULT));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encode(cipherText,Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
return strEncryInfoData.replaceAll("(\r|\n)", "");
}
出于调试目的,我尝试使用相同的参数调用此方法 2 次,字符串结果相似(如预期)。
我想在 java 中生成相同的加密字符串。但是,"android.util.Base64" class 在 Java 中不可用,所以我尝试使用默认的 Base64 class:
public static String encryptRSAToString(String text, String strPublicKey) {
byte[] cipherText = null;
String strEncryInfoData="";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(strPublicKey.trim().getBytes()));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encodeBase64(cipherText));
} catch (Exception e) {
e.printStackTrace();
}
return strEncryInfoData.replaceAll("(\r|\n)", "");
}
但是Android生成的String和java生成的String不一样
在 Android 侧生成:
Ky2T4j1JdI081ZESVJgxZXEf/xmtpehfv/EwpVvKQxUu1JI8lwXP2Rc66jHZRc0P846ZYuF3C9YEmWoKbXGXk2MBuT5KVxa2yoTbwZlMmhVOX3X3Efq0VyaO5zZ4qavIq036cA3MzvQbUAb678UdbALW/CjRCsOdeH+hSCzNQ+0=
在 JAVA 侧生成:
XhSLxfiJUUdZW5kWh0MEPSrqoROBBhNC/krfTx+sdnXML3WegYbMzSvNnPgB8+8Z9joEUBMmoeBI1OhTF6qPFL1EEixkFYAkGaryEFxvN/aFI75kEUj71OHNzAHAuvS+h+9Nssx9psSZ5gc2OoLQH0QtbGDyXB4p+qUGFCde4tY=
有人知道如何解决我的问题吗?
谢谢你
不同的密码和哈希实现存在偏差。我建议使用 OpenSSL 作为通用实现。
我还不能评论所以我回答。
可能使用了不同的默认配置。检查这个问题:Is there any difference between Apache's Base64.encodeBase64 and Android's Base64.encode with Base64.Default flag?
看起来你已经因为依赖默认设置而失败了。如果您希望互操作性,请不要这样做。
这是我在您的代码中发现的两个错误依赖默认值的示例。
final Cipher cipher = Cipher.getInstance("RSA");
转换字符串应该是 "algorithm/mode/padding" 的形式,但是你没有使用 mode 和 padding规格。结果,您获得了这些的默认值。 Android 和 Oracle Java 上的默认值明显不同。您应该始终 fully specify the transformation,例如:
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
另一个不好的例子是
cipherText = cipher.doFinal(text.getBytes());
在 text.getBytes()
中,您依赖于使用平台默认字符集的无参数 getBytes() 方法。但是这个默认的字符集在不同的平台上是不同的,因此这是不可移植的。在几乎所有情况下,我都运行 认为您应该指定 UTF-8 字符集。所以正确的行是
cipherText = cipher.doFinal(text.getBytes("UTF-8"));
用于在解密方法中重新创建原始字符串的正确字符串构造函数是 String(byte [] data, String charsetName)
。
我想用 RSA 加密来加密一个字符串。我的 public/private 密钥已生成并存储在数据库中。在 android 中,我使用此代码:
public static String encryptRSAToString(String text, String strPublicKey) {
byte[] cipherText = null;
String strEncryInfoData="";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strPublicKey.trim().getBytes(), Base64.DEFAULT));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encode(cipherText,Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
return strEncryInfoData.replaceAll("(\r|\n)", "");
}
出于调试目的,我尝试使用相同的参数调用此方法 2 次,字符串结果相似(如预期)。
我想在 java 中生成相同的加密字符串。但是,"android.util.Base64" class 在 Java 中不可用,所以我尝试使用默认的 Base64 class:
public static String encryptRSAToString(String text, String strPublicKey) {
byte[] cipherText = null;
String strEncryInfoData="";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(strPublicKey.trim().getBytes()));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encodeBase64(cipherText));
} catch (Exception e) {
e.printStackTrace();
}
return strEncryInfoData.replaceAll("(\r|\n)", "");
}
但是Android生成的String和java生成的String不一样
在 Android 侧生成:
Ky2T4j1JdI081ZESVJgxZXEf/xmtpehfv/EwpVvKQxUu1JI8lwXP2Rc66jHZRc0P846ZYuF3C9YEmWoKbXGXk2MBuT5KVxa2yoTbwZlMmhVOX3X3Efq0VyaO5zZ4qavIq036cA3MzvQbUAb678UdbALW/CjRCsOdeH+hSCzNQ+0=
在 JAVA 侧生成:
XhSLxfiJUUdZW5kWh0MEPSrqoROBBhNC/krfTx+sdnXML3WegYbMzSvNnPgB8+8Z9joEUBMmoeBI1OhTF6qPFL1EEixkFYAkGaryEFxvN/aFI75kEUj71OHNzAHAuvS+h+9Nssx9psSZ5gc2OoLQH0QtbGDyXB4p+qUGFCde4tY=
有人知道如何解决我的问题吗?
谢谢你
不同的密码和哈希实现存在偏差。我建议使用 OpenSSL 作为通用实现。
我还不能评论所以我回答。
可能使用了不同的默认配置。检查这个问题:Is there any difference between Apache's Base64.encodeBase64 and Android's Base64.encode with Base64.Default flag?
看起来你已经因为依赖默认设置而失败了。如果您希望互操作性,请不要这样做。
这是我在您的代码中发现的两个错误依赖默认值的示例。
final Cipher cipher = Cipher.getInstance("RSA");
转换字符串应该是 "algorithm/mode/padding" 的形式,但是你没有使用 mode 和 padding规格。结果,您获得了这些的默认值。 Android 和 Oracle Java 上的默认值明显不同。您应该始终 fully specify the transformation,例如:
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
另一个不好的例子是
cipherText = cipher.doFinal(text.getBytes());
在 text.getBytes()
中,您依赖于使用平台默认字符集的无参数 getBytes() 方法。但是这个默认的字符集在不同的平台上是不同的,因此这是不可移植的。在几乎所有情况下,我都运行 认为您应该指定 UTF-8 字符集。所以正确的行是
cipherText = cipher.doFinal(text.getBytes("UTF-8"));
用于在解密方法中重新创建原始字符串的正确字符串构造函数是 String(byte [] data, String charsetName)
。