java.security.spec.InvalidKeySpecException : java. lang.NoSuchMethodException:

标签 java android encryption keystore

我正在开发一个Android应用程序,我试图使用secretkeyfactory来设置和获取 keystore 文件中的 secret 值。我可以设置该值,但是当我尝试获取该值时,它显示以下错误 - java.security.spec.InvalidKeySpecException:

创建 keystore 文件的函数

private static KeyStore createKeyStore(String fileName, String pw) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
    File file = new File(this.getFilesDir().getPath().toString() + filename);

    final KeyStore keyStore = KeyStore.getInstance("BKS");
    if (file.exists()) {
      keyStore.load(new FileInputStream(file), pw.toCharArray());
    } else {
      keyStore.load(null, null);
      keyStore.store(new FileOutputStream(this.getFilesDir().getPath().toString() + filename), pw.toCharArray());
    }

    return keyStore;
  }

获取值的函数

public static String getKey(String key, String keystoreLocation, String keyStorePassword) throws Exception{
    KeyStore ks = KeyStore.getInstance("BKS");
    ks.load(null, keyStorePassword.toCharArray());
    KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());
    FileInputStream fIn = new FileInputStream(keystoreLocation);
    ks.load(fIn, keyStorePassword.toCharArray());
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEwithHmacSHA1");
    KeyStore.SecretKeyEntry ske =
      (KeyStore.SecretKeyEntry)ks.getEntry(key, keyStorePP);

    PBEKeySpec keySpec = (PBEKeySpec)factory.getKeySpec(
        ske.getSecretKey(),
        PBEKeySpec.class);

    char[] password = keySpec.getPassword();

    return new String(password);

  }

设置值的函数

public static void setKey(String key, String value, String keyStoreLocation, String keyStorePassword) throws Exception {

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEwithHmacSHA1");
    SecretKey generatedSecret = factory.generateSecret(new PBEKeySpec(value.toCharArray()));

    KeyStore ks = KeyStore.getInstance("BKS");
    ks.load(null, keyStorePassword.toCharArray());
    KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());

    ks.setEntry(key, new KeyStore.SecretKeyEntry( generatedSecret), keyStorePP);

    FileOutputStream fos = new java.io.FileOutputStream(keyStoreLocation);
    ks.store(fos, keyStorePassword.toCharArray());
  }
}

错误:

java.security.spec.InvalidKeySpecException: java.lang.NoSuchMethodException:
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory.engineGetKeySpec(BaseSecretKeyFactory.java:73)

getKey函数中的这一行发生错误

PBEKeySpec keySpec = (PBEKeySpec)factory.getKeySpec(
            ske.getSecretKey(),
            PBEKeySpec.class);

最佳答案

(1)可以,但是不行:

SecretKey key = ske.getSecretKey();
SecretKeySpeckeySpec = (SecretKeySpec)factory.getKeySpec(ke.getSecretKey(),SecretKeySpec.class);

(2)代码没问题,但是会报错: java.lang.ClassCastException:javax.crypto.spec.SecretKeySpec无法转换为javax.crypto.interfaces.PBEKey

PBEKey key = (PBEKey)ske.getSecretKey();
PBEKeySpec keySpec = (PBEKeySpec)factory.getKeySpec((PBEKey)ke.getSecretKey(),PBEKeySpec.class);

造成的原因:

public class SecretKeySpec implements KeySpec, SecretKey
public class PBEKeySpec implements KeySpec

ske.getSecretKey() 只是 SecretKeySpec 的一个实例

解决方案:(别人的代码)

void implInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
    char[] passwdChars = null;
    salt = null;
    iCount = 0;
    if (key instanceof javax.crypto.interfaces.PBEKey) {
        javax.crypto.interfaces.PBEKey pbeKey = (javax.crypto.interfaces.PBEKey) key;
        passwdChars = pbeKey.getPassword();
        // maybe null if unspecified
        salt = pbeKey.getSalt();
        // maybe 0 if unspecified
        iCount = pbeKey.getIterationCount();
    } else if (key instanceof SecretKey) {
        byte[] passwdBytes = key.getEncoded();
        if ((passwdBytes == null) || !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
            throw new InvalidKeyException("Missing password");
        }
        passwdChars = new char[passwdBytes.length];
        for (int i = 0; i < passwdChars.length; i++) {
            passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
        }
    } else {
        throw new InvalidKeyException("SecretKey of PBE type required");
    }
    if (((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher.UNWRAP_MODE)) && ((params == null) && ((salt == null) || (iCount == 0)))) {
        throw new InvalidAlgorithmParameterException("Parameters missing");
    }
    if (params == null) {
        // generate default for salt and iteration count if necessary
        if (salt == null) {
            salt = new byte[DEFAULT_SALT_LENGTH];
            if (random != null) {
                random.nextBytes(salt);
            } else {
                SunJCE.RANDOM.nextBytes(salt);
            }
        }
        if (iCount == 0)
            iCount = DEFAULT_COUNT;
    } else if (!(params instanceof PBEParameterSpec)) {
        throw new InvalidAlgorithmParameterException("PBEParameterSpec type required");
    } else {
        PBEParameterSpec pbeParams = (PBEParameterSpec) params;
        // make sure the parameter values are consistent
        if (salt != null) {
            if (!Arrays.equals(salt, pbeParams.getSalt())) {
                throw new InvalidAlgorithmParameterException("Inconsistent value of salt between key and params");
            }
        } else {
            salt = pbeParams.getSalt();
        }
        if (iCount != 0) {
            if (iCount != pbeParams.getIterationCount()) {
                throw new InvalidAlgorithmParameterException("Different iteration count between key and params");
            }
        } else {
            iCount = pbeParams.getIterationCount();
        }
    }
    // and openssl does.
    if (salt.length < 8) {
        throw new InvalidAlgorithmParameterException("Salt must be at least 8 bytes long");
    }
    if (iCount <= 0) {
        throw new InvalidAlgorithmParameterException("IterationCount must be a positive number");
    }
    byte[] derivedKey = derive(passwdChars, salt, iCount, keySize, CIPHER_KEY);
    SecretKey cipherKey = new SecretKeySpec(derivedKey, algo);
    byte[] derivedIv = derive(passwdChars, salt, iCount, 8, CIPHER_IV);
    IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8);
    // initialize the underlying cipher
    cipher.init(opmode, cipherKey, ivSpec, random);
}

关于java.security.spec.InvalidKeySpecException : java. lang.NoSuchMethodException:,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57160541/

相关文章:

java - 输出中每个整数之间的连字符

java - Android onTouch 事件没有发生?

javascript - CSS:强制视频显示全高并以纵向手持设备为中心

java - 在 JSP 页面中使用 JSON 数组进行响应

java - 检查 Selenium Hub/Node 是否在给定端口上运行

android - C2DMBroadcastReceiver 的 onReceive 未执行(用于注册)

encryption - 如何生成与 JWT 一起使用的 HS512 key

c - 在C中解密密码

encryption - HTTPs 网址加密

java - 如何检查一个单词是否包含一个字母或一组字母?