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