Merge "Keystore: Wire X25519 key agreement"
This commit is contained in:
@@ -61,6 +61,17 @@ public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X25519 key agreement support.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static class XDH extends AndroidKeyStoreKeyAgreementSpi {
|
||||||
|
public XDH() {
|
||||||
|
super(Algorithm.EC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final int mKeymintAlgorithm;
|
private final int mKeymintAlgorithm;
|
||||||
|
|
||||||
// Fields below are populated by engineInit and should be preserved after engineDoFinal.
|
// Fields below are populated by engineInit and should be preserved after engineDoFinal.
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ public class AndroidKeyStoreProvider extends Provider {
|
|||||||
|
|
||||||
// javax.crypto.KeyAgreement
|
// javax.crypto.KeyAgreement
|
||||||
put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
|
put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
|
||||||
|
put("KeyAgreement.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$XDH");
|
||||||
|
|
||||||
// java.security.SecretKeyFactory
|
// java.security.SecretKeyFactory
|
||||||
putSecretKeyFactoryImpl("AES");
|
putSecretKeyFactoryImpl("AES");
|
||||||
@@ -235,8 +236,8 @@ public class AndroidKeyStoreProvider extends Provider {
|
|||||||
return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
|
return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
|
||||||
iSecurityLevel, publicKeyEncoded);
|
iSecurityLevel, publicKeyEncoded);
|
||||||
} else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
|
} else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
|
||||||
//TODO(b/214203951) missing classes in conscrypt
|
return new AndroidKeyStoreXDHPublicKey(descriptor, metadata, X25519_ALIAS,
|
||||||
throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
|
iSecurityLevel, publicKey.getEncoded());
|
||||||
} else {
|
} else {
|
||||||
throw new ProviderException("Unsupported Android Keystore public key algorithm: "
|
throw new ProviderException("Unsupported Android Keystore public key algorithm: "
|
||||||
+ jcaKeyAlgorithm);
|
+ jcaKeyAlgorithm);
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.security.keystore2;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.security.KeyStoreSecurityLevel;
|
||||||
|
import android.system.keystore2.Authorization;
|
||||||
|
import android.system.keystore2.KeyDescriptor;
|
||||||
|
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.interfaces.EdECKey;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* X25519 Private Key backed by Keystore.
|
||||||
|
* instance of {@link PrivateKey} and {@link EdECKey}
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
|
||||||
|
public AndroidKeyStoreXDHPrivateKey(
|
||||||
|
@NonNull KeyDescriptor descriptor, long keyId,
|
||||||
|
@NonNull Authorization[] authorizations,
|
||||||
|
@NonNull String algorithm,
|
||||||
|
@NonNull KeyStoreSecurityLevel securityLevel) {
|
||||||
|
super(descriptor, keyId, authorizations, algorithm, securityLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NamedParameterSpec getParams() {
|
||||||
|
return NamedParameterSpec.X25519;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.security.keystore2;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.security.KeyStoreSecurityLevel;
|
||||||
|
import android.system.keystore2.KeyDescriptor;
|
||||||
|
import android.system.keystore2.KeyMetadata;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.interfaces.XECPublicKey;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.NamedParameterSpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link XECPublicKey} backed by keystore.
|
||||||
|
* This class re-implements Conscrypt's OpenSSLX25519PublicKey. The reason is that
|
||||||
|
* OpenSSLX25519PublicKey does not implement XECPublicKey and is not a part of Conscrypt's public
|
||||||
|
* interface so it cannot be referred to.
|
||||||
|
*
|
||||||
|
* So the functionality is duplicated here until (likely Android U) one of the things mentioned
|
||||||
|
* above is fixed.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implements XECPublicKey {
|
||||||
|
private static final byte[] X509_PREAMBLE = new byte[] {
|
||||||
|
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] {
|
||||||
|
0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int X25519_KEY_SIZE_BYTES = 32;
|
||||||
|
|
||||||
|
private final byte[] mEncodedKey;
|
||||||
|
private final int mPreambleLength;
|
||||||
|
|
||||||
|
public AndroidKeyStoreXDHPublicKey(
|
||||||
|
@NonNull KeyDescriptor descriptor,
|
||||||
|
@NonNull KeyMetadata metadata,
|
||||||
|
@NonNull String algorithm,
|
||||||
|
@NonNull KeyStoreSecurityLevel iSecurityLevel,
|
||||||
|
@NonNull byte[] encodedKey) {
|
||||||
|
super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
|
||||||
|
mEncodedKey = encodedKey;
|
||||||
|
if (mEncodedKey == null) {
|
||||||
|
throw new IllegalArgumentException("empty encoded key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreambleLength = matchesPreamble(X509_PREAMBLE, mEncodedKey) | matchesPreamble(
|
||||||
|
X509_PREAMBLE_WITH_NULL, mEncodedKey);
|
||||||
|
if (mPreambleLength == 0) {
|
||||||
|
throw new IllegalArgumentException("Key size is not correct size");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int matchesPreamble(byte[] preamble, byte[] encoded) {
|
||||||
|
if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Arrays.compare(preamble, 0, preamble.length, encoded, 0, preamble.length) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return preamble.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AndroidKeyStorePrivateKey getPrivateKey() {
|
||||||
|
return new AndroidKeyStoreXDHPrivateKey(
|
||||||
|
getUserKeyDescriptor(),
|
||||||
|
getKeyIdDescriptor().nspace,
|
||||||
|
getAuthorizations(),
|
||||||
|
"x25519",
|
||||||
|
getSecurityLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getU() {
|
||||||
|
return new BigInteger(Arrays.copyOfRange(mEncodedKey, mPreambleLength, mEncodedKey.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
return mEncodedKey.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return "XDH";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormat() {
|
||||||
|
return "x.509";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AlgorithmParameterSpec getParams() {
|
||||||
|
return NamedParameterSpec.X25519;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user