blob: 69138340f6538b4a6bdb5967647ba6f90179d21a [file] [log] [blame]
/*
* 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(),
"XDH",
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;
}
}