android - 当密钥是在 Android 密钥库中支持的保险箱时无法验证签名
问题描述
我的要求是使用 AndroidKeystore 中生成的密钥对 sha256 哈希进行签名。但是当我验证签名有效性时,它失败了,这是我使用不同场景的观察结果。
我们在以下场景中使用 Google PIXEL 3A 作为支持保险箱的设备对此进行了测试
IsStrongBoxEnabled Algorithm Verification
TRUE NONEWithRSA FALSE
TRUE SHA256WithRSA TRUE
FALSE NONEWithRSA TRUE
FALSE SHA256WithRSA TRUE
TRUE NONEWithECDSA TRUE
TRUE SHA256WithECDSA TRUE
FALSE NONEWithECDSA TRUE
FALSE SHA256WithECDSA TRUE
这是我的示例测试代码
package com.company.samplekeystoreapp;
import android.os.Build;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.StrongBoxUnavailableException;
import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import org.bouncycastle.util.encoders.Hex;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.Signature;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private KeyPair keyPair;
private KeyStore keyStore;
private String aliasName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
UUID uuid = UUID.randomUUID();
aliasName = "keyPrefix_" + uuid.toString();
keyPair = generateKeyPair(true);
KeyStore.Entry entry = keyStore.getEntry(aliasName, null);
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
Log.w("SampleApp", "Not an instance of a PrivateKeyEntry");
}
Signature s = Signature.getInstance("NONEwithRSA");
if (entry instanceof KeyStore.PrivateKeyEntry) {
s.initSign(((KeyStore.PrivateKeyEntry) entry).getPrivateKey());
}
byte[] data = Hex.decode("d56ca469cd129c015f682724560baaf653914ef21fff1817512186d67b18c7f5");
s.update(data);
byte[] signature = s.sign();
if (entry instanceof KeyStore.PrivateKeyEntry) {
s.initVerify(((KeyStore.PrivateKeyEntry) entry).getCertificate());
}
s.update(data);
boolean valid = s.verify(signature);
Toast.makeText(MainActivity.this, "Status : " + valid, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
private KeyPair generateKeyPair(boolean isStrongBoxEnabled) throws Exception {
try{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && isStrongBoxEnabled) {
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(
aliasName, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_SHA1)
.setIsStrongBoxBacked(true)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build());
} else {
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(
aliasName, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_SHA1)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build());
}
return keyPairGenerator.generateKeyPair();
}catch (Exception e) {
if (e instanceof StrongBoxUnavailableException) {
try {
return keyPair = generateKeyPair(false);
} catch (Exception ex) {
throw e;
}
}else {
throw e;
}
}
}
解决方案
推荐阅读
- javascript - 为什么最后一个容器闪烁?
- php - 排队消费者的健康检查
- typescript - 如何在类组件中使用 this.props.navigation.openDrawer() 而无需从父级传递道具给它?
- reactjs - 使用 React Hooks 设置加载器
- java - 在 java 中处理流时记录警告消息
- css - 如何在文本容器中将按钮向右对齐?
- docker - 如何在同一台服务器上托管不同的 nginx docker-compose 实例?
- reactjs - 反应ui闪烁状态更新settimeinterval
- java - 如何在 IText 7 的每个页面上使用相同的表单模板
- android - 高优先级通知不显示最新通知