我们可以从 Android 密钥库中提取 public/private 密钥吗?

Can we extract public/private keys from the Android Keystore?

关于 Android Keystore system 篇文章,

Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations. If the app's process is compromised, the attacker may be able to use the app's keys but cannot extract their key material (for example, to be used outside of the Android device)

那么,我的问题是为什么在 BasicAndroidKeyStore, developer able to get the KeyPair object and then print its public/private keys 中?

如果开发者可以访问密钥,这个系统如何被认为是安全的?不是。如果攻击者破坏了应用程序进程,他可以轻松地检索密钥并在设备外部使用。

KeyPair class 中的 example code that you pointed to from BasicAndroidKeyStore does not log the public key as getPublic() 仅 return 是 public 密钥对象的引用,而不是 public 密钥本身。

Log.d(TAG, "Public Key reference is: " + kp.getPublic().toString());

日志:

D/KeyStoreFragment: Public Key reference is: android.security.keystore.AndroidKeyStoreRSAPublicKey@b8004e8f

getPrivate()也是如此。

Log.d(TAG, "Private Key reference is: " + kp.getPrivate().toString());

日志:

D/KeyStoreFragment: Private Key reference is android.security.keystore.AndroidKeyStoreRSAPrivateKey@5da42c27


现在,正如您在评论中指出的那样,kp.getPublic().getEncoded() 将 return 实际的 public 键,但 public 键的原始用途并不意味着秘密。

私钥是秘密的,当使用硬件支持的密钥库和设备安全硬件支持的密钥时,密钥安全地存储在 TEE/SE 中并且不能被应用程序提取本身或另一个具有 root 权限的不良行为者。你可以在这个例子中看到它:

Log.d(TAG, "Private Key is " + Arrays.toString(kp.getPrivate().getEncoded()));

日志:

D/KeyStoreFragment: Private Key is null


要验证您设备的安全硬件是否支持您的密钥,您可以使用此代码的一些变体来满足您的需要。您可以在上面示例应用的 createKeys() 方法中提到的相同 Log.d 之后粘贴此代码段。

    KeyFactory factory = KeyFactory.getInstance(kp.getPrivate().getAlgorithm(), "AndroidKeyStore");
    KeyInfo keyInfo = null;
    try {
        keyInfo = factory.getKeySpec(kp.getPrivate(), KeyInfo.class);
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    }
    if (keyInfo.isInsideSecureHardware())
        Log.d(TAG, "Key is supported in secure hardware");
    else
        Log.d(TAG, "Key is not supported in secure hardware");