【问题标题】:Android Decryption Error安卓解密错误
【发布时间】:2016-03-19 20:51:57
【问题描述】:

我正在尝试在我的 Android 应用程序中加密和解密字符串,但我不断收到 InvalidKeyException 错误。

这是我的代码:

//生成密钥方法

public void generateKeys() {
    Calendar cal = Calendar.getInstance();
    Date now = cal.getTime();
    cal.add(Calendar.YEAR, 25);
    Date end = cal.getTime();

    KeyPairGenerator kpg = null;
    try {
        kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchProviderException e) {
        e.printStackTrace();
    }
    try {
        kpg.initialize(new KeyPairGeneratorSpec.Builder(context)
                .setAlias(KEY_ALIAS)
                .setStartDate(now)
                .setEndDate(end)
                .setSerialNumber(BigInteger.valueOf(1))
                .setSubject(new X500Principal("CN=" + KEY_ALIAS))
                .build());
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }

    KeyPair kp = kpg.generateKeyPair();

    KeyStore ks = null;
    try {
        ks = KeyStore.getInstance("AndroidKeyStore");
        ks.load(null);
        Enumeration<String> aliases = ks.aliases();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    KeyStore.Entry entry = null;
    try {
        entry = ks.getEntry(KEY_ALIAS, null);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnrecoverableEntryException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }
    if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
        Log.e(LOG_TAG, "Not an instance of PrivateKeyEntry.");
    }
    else{
        privKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
        pubKey = ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();
    }

}

//加密方法

private String encryptString(String value){
    byte[] encodedBytes = null;
    try {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        cipher.init(Cipher.ENCRYPT_MODE,  pubKey);
        encodedBytes = cipher.doFinal(value.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }

    return Base64.encodeToString(encodedBytes, Base64.DEFAULT);
}

//解密方法

private String decryptString(String value){
    byte[] decodedBytes = null;
    try {
        Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
        c.init(Cipher.DECRYPT_MODE,  privKey);
        decodedBytes = c.doFinal(Base64.decode(value, Base64.DEFAULT));
    } catch (Exception e) {
        e.printStackTrace();
        Log.e("Error", "Error = " + e);
        return "SECURE_FAILURE";
    }

    return new String(decodedBytes);
}

//测试代码

    generateKeys();
    String encrypted = encryptString("Hello World");
    Log.e("Encrypt", "encrypted = " + encrypted);
    String decrypted = decryptString(encrypted);
    Log.e("Decrypt", "decrypted = " + decrypted);

看起来加密工作正常,因为它会打印出如下内容:

加密= SbA2iWWKQbDL7NTA9xvtjD/viYDdpx9fLRYTSZ8UQzdBy3QLqzkswBY21ErH7FPza3vZys4E4PZw uxaGkRz0aC0FLqsYlbpcJernGm5+D5lRcBOaZmgkNY9pMf0YP75cBbcJdcmb1rDaH40nCRDnEoXv rGESJRqT6p0NMzlZqdd9KO3tqfExwgservAWxPNtRDBbMgE4I/09418jM5Ock5eayfOuv/STwEy6 Ecd56UjFH63h+gP6ed2aMDhBVeExMxvdloY+VnsAxS5Dkoc2GdaljtjRuPK48HQASoJK8EwAMNpz

但是当我尝试解密时出现以下错误:

java.security.InvalidKeyException:需要 RSA 私钥或公钥

我不明白为什么会出现这个异常?有人可以帮忙吗?

【问题讨论】:

  • 运气好吗?我在 Android Marshmallow 中遇到了同样的异常。
  • 我使用不同的提供商修复了它...请参阅下面的答案。
  • 除非出于某种原因需要非对称加密 (RSA) 公钥/私钥,否则请使用对称加密,例如 AES。对称加密是数据加密的一般选择。非对称加密数据长度受限于密钥大小,而且速度确实很慢,而且不安全。

标签: java android encryption public-key-encryption private-key


【解决方案1】:

这对我有用:

private Cipher getCipher() {
    try {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // below android m
            return Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); // error in android 6: InvalidKeyException: Need RSA private or public key
        }
        else { // android m and above
            return Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround"); // error in android 5: NoSuchProviderException: Provider not available: AndroidKeyStoreBCWorkaround
        }
    } catch(Exception exception) {
        throw new RuntimeException("getCipher: Failed to get an instance of Cipher", exception);
    }
}

【讨论】:

  • 嗯...如果我们在 Lollipop 上创建了一个公共和一个私有 RSA 密钥,然后用户将他的 Android 操作系统升级到 Marshmallow 会怎样。而且我们的方法将返回不同的提供者——它可以与之前生成的 RSA 密钥一起使用吗?
  • @KirillKarmazin 我认为如果你使用相同的算法、密码和填充,结果应该总是相同的,无论你使用什么提供商。
  • 我也觉得我们可以跳过第二个参数,让我们为我们选择提供者
【解决方案2】:

删除提供程序对我有用:

Cipher.getInstance("RSA/ECB/PKCS1Padding")

来自Java docs:“此方法遍历已注册的安全提供者列表,从最首选的提供者开始。返回一个封装来自第一个支持指定算法的提供者的 CipherSpi 实现的新 Cipher 对象。”

【讨论】:

    【解决方案3】:

    尝试使用不同的提供商,如下所示:

    Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
    

    【讨论】:

    • 对我有用,虽然一些解释会很棒。
    • 看'lanna blue'的答案,你必须根据Android版本更改RSA加密的提供者名称!否则会出错!
    猜你喜欢
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多