【问题标题】:Decryption error: caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android解密错误:由java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android引起
【发布时间】:2017-01-07 23:26:57
【问题描述】:

您好,我正在尝试从我在 Android 上的公钥中解密内容:

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 marshmallow,4.2.2 在模拟器上崩溃

全班:-

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;
        }
    }
}

【问题讨论】:

    标签: java android encryption cryptography android-6.0-marshmallow


    【解决方案1】:

    在定义您打算使用的密码时,具体是值得的。而不是使用:

    final Cipher cipher = Cipher.getInstance("RSA");
    

    你应该试试:

    final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    

    我认为纯 Java 和 Android 之间存在一些不一致,我不记得是什么版本,但在大多数情况下,上述调整可以解决问题。

    【讨论】:

    • 还是强制关闭
    【解决方案2】:

    唯一的问题是在 android 4.3 及更高版本中添加了真正的密码学,因此在 android 4.2 及以下版本中会导致问题,因为 openssl 类在 api 18 中被设为默认值,因此在 4.3 上使用此 rsa 加密/解密很好+ else 以支持下面使用其他一些技术。

    这就是我这边的解决方案,如果其他人遇到这个问题,你可以在这里看到解决方案,

    或者如果有人设法在不使用第三方库的情况下使其工作,那么欢迎他在这里编写

    【讨论】:

      【解决方案3】:

      您不应该使用ObjectOutputStream / ObjectInputStream 来存储密钥。 PublicKey 的底层实现类因版本而异,如果更高版本中不存在该类,则使用内部类对对象进行序列化将失败。

      我建议直接存储公钥数据

      byte publicKeyData[] = publicKey.getEncoded();
      

      并使用加载它

      X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyData);
      KeyFactory kf = KeyFactory.getInstance("RSA");
      PublicKey publicKey = kf.generatePublic(spec);
      

      另请注意,在4.3 之前的 android 中,密码提供程序没有完全实现,并且可以使用非传统操作,如使用 RSA 公钥解密和使用私钥加密。

      更新 - 海绵城堡

      您也可以使用 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

      【讨论】:

      • 好吧,它也不会有任何问题,主要问题是 RSA 在 android 4.3 下无法完美运行,这就是它强制关闭的原因。所以需要为 android 4.3 以下解决一些问题跨度>
      • 我用
      • 是的,在 4.3 及更高版本上它工作正常,但在它下面会导致崩溃,你可以阅读大部分内容是在 api 18 中添加的密码学developer.android.com/training/articles/keystore.html,,well 你能给我android的链接吗实施?
      • 是的,我知道自 android 18 以来的优势以及安全密钥库的本机实现。我已经发布了一些使用 Spongycastle 提供程序的示例。
      • spongycastle 可以解决这个问题,但会增加 MB 的大小,这是降级的,所以我想在 4.3 上使用 rsa,否则使用其他东西
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 2016-12-11
      • 2016-08-11
      • 2016-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多