我正在开发一个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/