1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.security.keystore2; 18 19 import android.annotation.NonNull; 20 import android.security.KeyStoreSecurityLevel; 21 import android.system.keystore2.KeyDescriptor; 22 import android.system.keystore2.KeyMetadata; 23 24 import java.math.BigInteger; 25 import java.security.interfaces.XECPublicKey; 26 import java.security.spec.AlgorithmParameterSpec; 27 import java.security.spec.NamedParameterSpec; 28 import java.util.Arrays; 29 30 /** 31 * {@link XECPublicKey} backed by keystore. 32 * This class re-implements Conscrypt's OpenSSLX25519PublicKey. The reason is that 33 * OpenSSLX25519PublicKey does not implement XECPublicKey and is not a part of Conscrypt's public 34 * interface so it cannot be referred to. 35 * 36 * So the functionality is duplicated here until (likely Android U) one of the things mentioned 37 * above is fixed. 38 * 39 * @hide 40 */ 41 public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implements XECPublicKey { 42 private static final byte[] X509_PREAMBLE = new byte[] { 43 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00, 44 }; 45 46 private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] { 47 0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00, 48 }; 49 50 private static final int X25519_KEY_SIZE_BYTES = 32; 51 52 private final byte[] mEncodedKey; 53 private final int mPreambleLength; 54 AndroidKeyStoreXDHPublicKey( @onNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, @NonNull String algorithm, @NonNull KeyStoreSecurityLevel iSecurityLevel, @NonNull byte[] encodedKey)55 public AndroidKeyStoreXDHPublicKey( 56 @NonNull KeyDescriptor descriptor, 57 @NonNull KeyMetadata metadata, 58 @NonNull String algorithm, 59 @NonNull KeyStoreSecurityLevel iSecurityLevel, 60 @NonNull byte[] encodedKey) { 61 super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel); 62 mEncodedKey = encodedKey; 63 if (mEncodedKey == null) { 64 throw new IllegalArgumentException("empty encoded key."); 65 } 66 67 mPreambleLength = matchesPreamble(X509_PREAMBLE, mEncodedKey) | matchesPreamble( 68 X509_PREAMBLE_WITH_NULL, mEncodedKey); 69 if (mPreambleLength == 0) { 70 throw new IllegalArgumentException("Key size is not correct size"); 71 } 72 } 73 matchesPreamble(byte[] preamble, byte[] encoded)74 private static int matchesPreamble(byte[] preamble, byte[] encoded) { 75 if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) { 76 return 0; 77 } 78 79 if (Arrays.compare(preamble, 0, preamble.length, encoded, 0, preamble.length) != 0) { 80 return 0; 81 } 82 return preamble.length; 83 } 84 85 @Override getPrivateKey()86 AndroidKeyStorePrivateKey getPrivateKey() { 87 return new AndroidKeyStoreXDHPrivateKey( 88 getUserKeyDescriptor(), 89 getKeyIdDescriptor().nspace, 90 getAuthorizations(), 91 "XDH", 92 getSecurityLevel()); 93 } 94 95 @Override getU()96 public BigInteger getU() { 97 return new BigInteger(Arrays.copyOfRange(mEncodedKey, mPreambleLength, mEncodedKey.length)); 98 } 99 100 @Override getEncoded()101 public byte[] getEncoded() { 102 return mEncodedKey.clone(); 103 } 104 105 @Override getAlgorithm()106 public String getAlgorithm() { 107 return "XDH"; 108 } 109 110 @Override getFormat()111 public String getFormat() { 112 return "x.509"; 113 } 114 115 @Override getParams()116 public AlgorithmParameterSpec getParams() { 117 return NamedParameterSpec.X25519; 118 } 119 } 120 121