简体   繁体   English

ECDH 密钥协议生成的密钥对在 Android 中始终无效 12

[英]ECDH key agreement generated Key Pair is always invalid in Android 12

I've written the below code following the official guide for ECDH Key Agreement on Android.我已经按照 Android 上的 ECDH 密钥协议官方指南编写了以下代码。

private static final String EC_SPEC = "p-256";
private static final String KEY_PAIR_NAME = "abcdefgh";
private static final String MAC_ALG = "HMACSHA256";
private static final String INFO_TAG = "ECDH p-256 AES-256-GCM-SIV\0";
private static final String KEY_AGREEMENT_ALG = "ECDH";
private static final String KEY_STORE_PROVIDER = "AndroidKeyStore";

public static KeyPair generateKeys() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, ParseException {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_EC, KEY_STORE_PROVIDER);
    keyPairGenerator.initialize(
            new KeyGenParameterSpec.Builder(
                    KEY_PAIR_NAME,
                    KeyProperties.PURPOSE_AGREE_KEY)
                    .setAlgorithmParameterSpec(new ECGenParameterSpec(EC_SPEC))
                    .setUserAuthenticationRequired(false)
                    .setKeyValidityEnd(DateFormat.getDateInstance().parse("Aug 1, 2199"))
                    .build());
    return keyPairGenerator.generateKeyPair();
}

public static byte[] sharedSecret(PrivateKey mine, PublicKey remote) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
    KeyAgreement keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALG, KEY_STORE_PROVIDER);
    //Line 55 here ↓ where error occurs
    keyAgreement.init(mine);
    keyAgreement.doPhase(remote, true);
    return keyAgreement.generateSecret();
}

But at the time of execution the code throws below error:但是在执行时,代码会抛出以下错误:

W/System.err: android.security.keystore.KeyPermanentlyInvalidatedException: Key permanently invalidated
W/System.err:     at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:123)
W/System.err:     at android.security.keystore2.AndroidKeyStoreKeyAgreementSpi.ensureKeystoreOperationInitialized(AndroidKeyStoreKeyAgreementSpi.java:228)
W/System.err:     at android.security.keystore2.AndroidKeyStoreKeyAgreementSpi.engineInit(AndroidKeyStoreKeyAgreementSpi.java:96)
W/System.err:     at javax.crypto.KeyAgreement.init(KeyAgreement.java:498)
W/System.err:     at javax.crypto.KeyAgreement.init(KeyAgreement.java:470)
W/System.err:     at app.exploitr.sec.rts.security.ECCUtil.sharedSecret(ECCUtil.java:55)

I've tried to test the code in the following manner,我尝试以以下方式测试代码,

try {
    KeyPair one = ECCUtil.generateKeys();
    KeyPair two = ECCUtil.generateKeys();

    byte[] sec_one = ECCUtil.sharedSecret(one.getPrivate(), two.getPublic());
    byte[] sec_two = ECCUtil.sharedSecret(two.getPrivate(), one.getPublic());

    Log.d("TAG 1st SHARED", new String(sec_one));
    Log.d("TAG 2nd SHARED", new String(sec_two));

} catch (IOException | GeneralSecurityException | ParseException e) {
    e.printStackTrace();
}

I can't understand why the keys are getting permanently invalidated instantly despite of setting user authentication disabled or large timeout.尽管设置了用户身份验证禁用或大超时,但我无法理解为什么密钥会立即永久失效。 As key generation has issues with emulators and I've only 1 Android 12 device ( KeyProperties.PURPOSE_AGREE_KEY was introduced in API 31) I tried to generate and test both the local and remote keys on the device.由于密钥生成存在模拟器问题,并且我只有 1 个 Android 12 设备(在KeyProperties.PURPOSE_AGREE_KEY 31 中引入了 KeyProperties.PURPOSE_AGREE_KEY),我尝试在设备上生成和测试本地和远程密钥。 What should be done here?这里应该做什么?

The generateKeys() method creates a new key pair with always the same alias ( KEY_PAIR_NAME , ie abcdefgh ). generateKeys()方法创建一个新的密钥对,它始终具有相同的别名( KEY_PAIR_NAME ,即abcdefgh )。 This makes the first key pair invalid as soon as the second key pair is generated.这使得一旦生成第二个密钥对,第一个密钥对就无效。
Using the invalid private key in init() then throws an exception whose error message actually describes the problem quite accurately: KeyPermanentlyInvalidatedException: key permanently invalidated .init()中使用无效的私钥会引发异常,其错误消息实际上非常准确地描述了问题: KeyPermanentlyInvalidatedException: key permanently invalidated
The fix is to create the second key pair with a different alias (for this, the alias can eg be passed to generateKeys() and forwarded to KeyGenParameterSpec.Builder() ):解决方法是使用不同的别名创建第二个密钥对(为此,可以将别名传递给generateKeys()并转发给KeyGenParameterSpec.Builder() ):

...
KeyPair one = generateKeys("alias_one");
KeyPair two = generateKeys("alias_two");
...

public static KeyPair generateKeys(String alias) throws ... {
    ...
    keyPairGenerator.initialize(
        new KeyGenParameterSpec.Builder(
            alias,
    ...
}

Also it is wrong to convert the shared secret to a string using new String() .使用new String()将共享密钥转换为字符串也是错误的。 This applies the default charset encoding, which generally corrupts the binary data.这将应用默认字符集编码,这通常会破坏二进制数据。 Instead a binary-to-text encoding like Base64 should be used for the conversion to a string.相反,应该使用像 Base64 这样的二进制到文本编码来转换为字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM