尝试使用 RSA 私钥加密时 Android 应用程序出现 InvalidKeyException
InvalidKeyException in Android app when trying to encrypt with RSA private key
我正尝试在我的 Android 应用程序中使用硬件支持的密钥库中生成的密钥对来执行 encryption/decryption。这是我的密钥生成代码:
public void createKeys() {
Context ctx = getApplicationContext();
Calendar start = new GregorianCalendar();
Calendar end = new GregorianCalendar();
end.add(Calendar.YEAR, 1);
try {
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
AlgorithmParameterSpec spec = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
spec = new KeyPairGeneratorSpec.Builder(ctx)
.setAlias(mAlias)
.setSubject(new X500Principal("CN=" + mAlias))
.setSerialNumber(BigInteger.valueOf(1337))
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
spec = new KeyGenParameterSpec.Builder(mAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build();
}
kpGenerator.initialize(spec);
KeyPair kp = kpGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "RSA not supported", e);
} catch (NoSuchProviderException e) {
Log.w(TAG, "No such provider: AndroidKeyStore");
} catch (InvalidAlgorithmParameterException e) {
Log.w(TAG, "No such provider: AndroidKeyStore");
}
}
这是我的加密代码:
public String encrypt(String challenge) {
try {
KeyStore mKeyStore = KeyStore.getInstance("AndroidKeyStore");
mKeyStore.load(null);
KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) mKeyStore.getEntry(mAlias, null);
Cipher cip = null;
cip = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cip.init(Cipher.ENCRYPT_MODE, entry.getPrivateKey());
byte[] encryptBytes = cip.doFinal(challenge.getBytes());
String encryptedStr64 = Base64.encodeToString(encryptBytes, Base64.NO_WRAP);
return encryptedStr64;
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "No Such Algorithm Exception");
e.printStackTrace();
} catch (UnrecoverableEntryException e) {
Log.w(TAG, "Unrecoverable Entry Exception");
e.printStackTrace();
} catch (KeyStoreException e) {
Log.w(TAG, "KeyStore Exception");
e.printStackTrace();
} catch (InvalidKeyException e) {
Log.w(TAG, "Invalid Key Exception");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
Log.w(TAG, "No Such Padding Exception");
e.printStackTrace();
} catch (BadPaddingException e) {
Log.w(TAG, "Bad Padding Exception");
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
Log.w(TAG, "Illegal Block Size Exception");
e.printStackTrace();
} catch (CertificateException e) {
Log.w(TAG, "Certificate Exception");
} catch (IOException e) {
Log.w(TAG, "IO Exception", e);
}
return null;
}
密钥生成成功完成。我还使用 KeyInfo.isInsideSecureHardware() 验证它是否由硬件支持。但是,我在 encrypt() 中的 cip.init(Cipher.ENCRYPT_MODE, entry.getPrivateKey()) 行中不断收到 InvalidKeyException。确切的例外是
java.security.InvalidKeyException: Keystore operation failed
有人知道为什么吗?
加密只有在使用 public 密钥时才有意义。如果您 "encrypt" 使用私钥,那么您实际上是在创建签名。 Java/Android 有一个单独的 class。
我正尝试在我的 Android 应用程序中使用硬件支持的密钥库中生成的密钥对来执行 encryption/decryption。这是我的密钥生成代码:
public void createKeys() {
Context ctx = getApplicationContext();
Calendar start = new GregorianCalendar();
Calendar end = new GregorianCalendar();
end.add(Calendar.YEAR, 1);
try {
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
AlgorithmParameterSpec spec = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
spec = new KeyPairGeneratorSpec.Builder(ctx)
.setAlias(mAlias)
.setSubject(new X500Principal("CN=" + mAlias))
.setSerialNumber(BigInteger.valueOf(1337))
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
spec = new KeyGenParameterSpec.Builder(mAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build();
}
kpGenerator.initialize(spec);
KeyPair kp = kpGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "RSA not supported", e);
} catch (NoSuchProviderException e) {
Log.w(TAG, "No such provider: AndroidKeyStore");
} catch (InvalidAlgorithmParameterException e) {
Log.w(TAG, "No such provider: AndroidKeyStore");
}
}
这是我的加密代码:
public String encrypt(String challenge) {
try {
KeyStore mKeyStore = KeyStore.getInstance("AndroidKeyStore");
mKeyStore.load(null);
KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) mKeyStore.getEntry(mAlias, null);
Cipher cip = null;
cip = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cip.init(Cipher.ENCRYPT_MODE, entry.getPrivateKey());
byte[] encryptBytes = cip.doFinal(challenge.getBytes());
String encryptedStr64 = Base64.encodeToString(encryptBytes, Base64.NO_WRAP);
return encryptedStr64;
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "No Such Algorithm Exception");
e.printStackTrace();
} catch (UnrecoverableEntryException e) {
Log.w(TAG, "Unrecoverable Entry Exception");
e.printStackTrace();
} catch (KeyStoreException e) {
Log.w(TAG, "KeyStore Exception");
e.printStackTrace();
} catch (InvalidKeyException e) {
Log.w(TAG, "Invalid Key Exception");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
Log.w(TAG, "No Such Padding Exception");
e.printStackTrace();
} catch (BadPaddingException e) {
Log.w(TAG, "Bad Padding Exception");
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
Log.w(TAG, "Illegal Block Size Exception");
e.printStackTrace();
} catch (CertificateException e) {
Log.w(TAG, "Certificate Exception");
} catch (IOException e) {
Log.w(TAG, "IO Exception", e);
}
return null;
}
密钥生成成功完成。我还使用 KeyInfo.isInsideSecureHardware() 验证它是否由硬件支持。但是,我在 encrypt() 中的 cip.init(Cipher.ENCRYPT_MODE, entry.getPrivateKey()) 行中不断收到 InvalidKeyException。确切的例外是
java.security.InvalidKeyException: Keystore operation failed
有人知道为什么吗?
加密只有在使用 public 密钥时才有意义。如果您 "encrypt" 使用私钥,那么您实际上是在创建签名。 Java/Android 有一个单独的 class。