Decryption error: caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android
Decryption error: caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android
你好,我正在尝试从 Android 上的 public 密钥解密内容:
public String decrypt(String basetext) {
try {
FileInputStream iR = new FileInputStream("/sdcard/publickkey");
ObjectInputStream inputStream = new ObjectInputStream(iR);
final PublicKey key = (PublicKey) inputStream.readObject();
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
iR.close();
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
它在我的棉花糖上运行良好,尝试在模拟器 4.2.2 上 运行 并抛出以下错误:
caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android
如果我看到我的导入,则没有像上面那样的导入错误
import javax.crypto.Cipher;
import java.security.PublicKey;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
这在真实设备上工作正常android棉花糖,4.2.2 在模拟器上崩溃
完整 class :-
import android.util.Base64;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
public class EncryptionUtils {
public static final String ALGORITHM = "RSA";
public static final String PRIVATE_KEY_FILE = "/sdcard/private.key";
public static final String PUBLIC_KEY_FILE = "/sdcard/public.key";
public static void generateKey() {
try {
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(2048);
final KeyPair key = keyGen.generateKeyPair();
File privateKeyFile = new File(PRIVATE_KEY_FILE);
File publicKeyFile = new File(PUBLIC_KEY_FILE);
// Create files to store public and private key
if (privateKeyFile.getParentFile() != null) {
privateKeyFile.getParentFile().mkdirs();
}
privateKeyFile.createNewFile();
if (publicKeyFile.getParentFile() != null) {
publicKeyFile.getParentFile().mkdirs();
}
publicKeyFile.createNewFile();
// Saving the Public key in a file
ObjectOutputStream publicKeyOS = new ObjectOutputStream(
new FileOutputStream(publicKeyFile));
publicKeyOS.writeObject(key.getPublic());
publicKeyOS.close();
// Saving the Private key in a file
ObjectOutputStream privateKeyOS = new ObjectOutputStream(
new FileOutputStream(privateKeyFile));
privateKeyOS.writeObject(key.getPrivate());
privateKeyOS.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String text, PrivateKey key) {
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// encrypt the plain text using the private key
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(text.getBytes("UTF-8"));
String base64 = Base64.encodeToString(cipherText, Base64.DEFAULT);
return base64;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String decrypt(String basetext, PublicKey key) {
try {
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
在定义您打算使用的密码时,特定 是值得的。而不是使用:
final Cipher cipher = Cipher.getInstance("RSA");
你应该试试:
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
我认为普通 Java 和 Android 之间存在一些不一致,我不记得是什么版本,但在大多数情况下,上述调整可以解决问题。
您不应使用 ObjectOutputStream
/ ObjectInputStream
来存储密钥。 PublicKey
的底层实现 class 因版本而异,如果 class 在较高版本中不存在,则使用内部 class 的对象序列化将失败。
我建议直接存储public关键数据
byte publicKeyData[] = publicKey.getEncoded();
并使用
加载它
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyData);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(spec);
另请注意,在 4.3
之前的 android 中,加密提供程序未完全实现,可以使用非常规操作,如使用 RSA public 密钥解密和使用私钥加密有保证。
更新 - 海绵城堡
或者,您可以使用 spongycastle 加密提供程序来生成和加载密钥
Gradle 依赖关系
compile 'com.madgag.spongycastle:core:1.51.0.0'
compile 'com.madgag.spongycastle:prov:1.51.0.0'
compile 'com.madgag.spongycastle:pkix:1.51.0.0'
添加提供商
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
用法
将 SC
添加到提供程序参数。例如
KeyPairGenerator keyGen= KeyPairGenerator.getInstance("RSA", "SC");
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SC");
查看更多信息here
好吧,唯一的问题是 android 4.3 及更高版本中添加了真正的密码学,因此在 android 4.2 及更低版本中它会导致问题,因为 openssl class 在api 18,所以使用这个 rsa encrypting/decryption 在 4.3+ 上没问题,否则为了支持下面使用一些其他技术。
这就是我的解决方案,如果其他人遇到此问题,您可以在此处查看解决方案,
或者如果有人设法在不使用第三方库的情况下使它工作,那么非常欢迎他在这里写它
你好,我正在尝试从 Android 上的 public 密钥解密内容:
public String decrypt(String basetext) {
try {
FileInputStream iR = new FileInputStream("/sdcard/publickkey");
ObjectInputStream inputStream = new ObjectInputStream(iR);
final PublicKey key = (PublicKey) inputStream.readObject();
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
iR.close();
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
它在我的棉花糖上运行良好,尝试在模拟器 4.2.2 上 运行 并抛出以下错误:
caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android
如果我看到我的导入,则没有像上面那样的导入错误
import javax.crypto.Cipher;
import java.security.PublicKey;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
这在真实设备上工作正常android棉花糖,4.2.2 在模拟器上崩溃
完整 class :-
import android.util.Base64;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
public class EncryptionUtils {
public static final String ALGORITHM = "RSA";
public static final String PRIVATE_KEY_FILE = "/sdcard/private.key";
public static final String PUBLIC_KEY_FILE = "/sdcard/public.key";
public static void generateKey() {
try {
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(2048);
final KeyPair key = keyGen.generateKeyPair();
File privateKeyFile = new File(PRIVATE_KEY_FILE);
File publicKeyFile = new File(PUBLIC_KEY_FILE);
// Create files to store public and private key
if (privateKeyFile.getParentFile() != null) {
privateKeyFile.getParentFile().mkdirs();
}
privateKeyFile.createNewFile();
if (publicKeyFile.getParentFile() != null) {
publicKeyFile.getParentFile().mkdirs();
}
publicKeyFile.createNewFile();
// Saving the Public key in a file
ObjectOutputStream publicKeyOS = new ObjectOutputStream(
new FileOutputStream(publicKeyFile));
publicKeyOS.writeObject(key.getPublic());
publicKeyOS.close();
// Saving the Private key in a file
ObjectOutputStream privateKeyOS = new ObjectOutputStream(
new FileOutputStream(privateKeyFile));
privateKeyOS.writeObject(key.getPrivate());
privateKeyOS.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String text, PrivateKey key) {
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// encrypt the plain text using the private key
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(text.getBytes("UTF-8"));
String base64 = Base64.encodeToString(cipherText, Base64.DEFAULT);
return base64;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String decrypt(String basetext, PublicKey key) {
try {
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
在定义您打算使用的密码时,特定 是值得的。而不是使用:
final Cipher cipher = Cipher.getInstance("RSA");
你应该试试:
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
我认为普通 Java 和 Android 之间存在一些不一致,我不记得是什么版本,但在大多数情况下,上述调整可以解决问题。
您不应使用 ObjectOutputStream
/ ObjectInputStream
来存储密钥。 PublicKey
的底层实现 class 因版本而异,如果 class 在较高版本中不存在,则使用内部 class 的对象序列化将失败。
我建议直接存储public关键数据
byte publicKeyData[] = publicKey.getEncoded();
并使用
加载它X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyData);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(spec);
另请注意,在 4.3
之前的 android 中,加密提供程序未完全实现,可以使用非常规操作,如使用 RSA public 密钥解密和使用私钥加密有保证。
更新 - 海绵城堡
或者,您可以使用 spongycastle 加密提供程序来生成和加载密钥
Gradle 依赖关系
compile 'com.madgag.spongycastle:core:1.51.0.0'
compile 'com.madgag.spongycastle:prov:1.51.0.0'
compile 'com.madgag.spongycastle:pkix:1.51.0.0'
添加提供商
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
用法
将 SC
添加到提供程序参数。例如
KeyPairGenerator keyGen= KeyPairGenerator.getInstance("RSA", "SC");
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SC");
查看更多信息here
好吧,唯一的问题是 android 4.3 及更高版本中添加了真正的密码学,因此在 android 4.2 及更低版本中它会导致问题,因为 openssl class 在api 18,所以使用这个 rsa encrypting/decryption 在 4.3+ 上没问题,否则为了支持下面使用一些其他技术。
这就是我的解决方案,如果其他人遇到此问题,您可以在此处查看解决方案,
或者如果有人设法在不使用第三方库的情况下使它工作,那么非常欢迎他在这里写它