首页 > 解决方案 > 当密钥是在 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;
        }
    }
}

标签: androidcryptographyandroid-keystorepki

解决方案


推荐阅读