AndroidKeyStoreKeyPairGeneratorSpi.java revision e21f0231765492718f1284442136c2ae45e6dd93
14f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber/*
24f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Copyright (C) 2012 The Android Open Source Project
34f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
44f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
54f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * you may not use this file except in compliance with the License.
64f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * You may obtain a copy of the License at
74f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
84f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
94f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Unless required by applicable law or agreed to in writing, software
114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * See the License for the specific language governing permissions and
144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * limitations under the License.
154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber */
164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberpackage android.security.keystore;
184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport android.annotation.NonNull;
204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport android.security.Credentials;
214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport android.security.KeyPairGeneratorSpec;
224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport android.security.KeyStore;
234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport com.android.org.conscrypt.NativeConstants;
264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport com.android.org.conscrypt.OpenSSLEngine;
274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.InvalidAlgorithmParameterException;
294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.InvalidKeyException;
304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.KeyFactory;
314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.KeyPair;
324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.KeyPairGenerator;
334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.KeyPairGeneratorSpi;
344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.NoSuchAlgorithmException;
354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.PrivateKey;
364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.PublicKey;
374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.SecureRandom;
384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.cert.CertificateEncodingException;
394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.cert.X509Certificate;
404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.spec.AlgorithmParameterSpec;
414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.spec.InvalidKeySpecException;
424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.spec.RSAKeyGenParameterSpec;
434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.security.spec.X509EncodedKeySpec;
444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberimport java.util.Locale;
454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber/**
474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Provides a way to create instances of a KeyPair which will be placed in the
484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Android keystore service usable only by the application that called it. This
494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * can be used in conjunction with
504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * {@link java.security.KeyStore#getInstance(String)} using the
514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * {@code "AndroidKeyStore"} type.
524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * <p>
534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * This class can not be directly instantiated and must instead be used via the
544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * {@link KeyPairGenerator#getInstance(String)
554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * @hide
584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber */
594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberpublic abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        public RSA() {
634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            super(KeyProperties.KEY_ALGORITHM_RSA);
644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        public EC() {
694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            super(KeyProperties.KEY_ALGORITHM_EC);
704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    /*
744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * These must be kept in sync with system/security/keystore/defaults.h
754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     */
764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    /* EC */
784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int EC_DEFAULT_KEY_SIZE = 256;
794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int EC_MIN_KEY_SIZE = 192;
804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int EC_MAX_KEY_SIZE = 521;
814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    /* RSA */
834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
844f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int RSA_MIN_KEY_SIZE = 512;
854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static final int RSA_MAX_KEY_SIZE = 8192;
864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private final String mAlgorithm;
884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private KeyStore mKeyStore;
904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private KeyGenParameterSpec mSpec;
924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private boolean mEncryptionAtRestRequired;
934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private @KeyProperties.KeyAlgorithmEnum String mKeyAlgorithm;
944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private int mKeyType;
954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private int mKeySize;
964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    protected AndroidKeyStoreKeyPairGeneratorSpi(@KeyProperties.KeyAlgorithmEnum String algorithm) {
984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mAlgorithm = algorithm;
994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1014f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    @KeyProperties.KeyAlgorithmEnum String getAlgorithm() {
1024f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return mAlgorithm;
1034f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1044f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1054f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    /**
1064f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * Generate a KeyPair which is backed by the Android keystore service. You
1074f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
1084f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * with an {@link KeyPairGeneratorSpec} as the {@code params}
1094f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * argument before calling this otherwise an {@code IllegalStateException}
1104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * will be thrown.
1114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * <p>
1124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * This will create an entry in the Android keystore service with a
1134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * self-signed certificate using the {@code params} specified in the
1144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * {@code initialize(params)} call.
1154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     *
1164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * @throws IllegalStateException when called before calling
1174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     *             {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
1184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     * @see java.security.KeyPairGeneratorSpi#generateKeyPair()
1194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber     */
1204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    @Override
1214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    public KeyPair generateKeyPair() {
1224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (mKeyStore == null || mSpec == null) {
1234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("Not initialized");
1244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
1284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
1294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
1304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException(
1314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Encryption at rest using secure lock screen credential requested for key pair"
1324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    + ", but the user has not yet entered the credential");
1334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final String alias = mSpec.getKeystoreAlias();
1364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
1384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        byte[][] args = getArgsForKeyType(mKeyType, mSpec.getAlgorithmParameterSpec());
1404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
1424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mKeyType, mKeySize,
1444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                flags, args)) {
1454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("could not generate key in keystore");
1464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
1494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final PrivateKey privKey;
1514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
1524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        try {
1534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            privKey = engine.getPrivateKeyById(privateKeyAlias);
1544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } catch (InvalidKeyException e) {
1554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new RuntimeException("Can't get key", e);
1564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias);
1594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final PublicKey pubKey;
1614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        try {
1624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            final KeyFactory keyFact = KeyFactory.getInstance(mKeyAlgorithm);
1634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
1644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } catch (NoSuchAlgorithmException e) {
1654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("Can't instantiate key generator", e);
1664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } catch (InvalidKeySpecException e) {
1674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("keystore returned invalid key encoding", e);
1684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final X509Certificate cert;
1714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        try {
1724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cert = generateCertificate(privKey, pubKey);
1734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } catch (Exception e) {
1744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
1754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("Can't generate certificate", e);
1764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        byte[] certBytes;
1794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        try {
1804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            certBytes = cert.getEncoded();
1814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } catch (CertificateEncodingException e) {
1824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
1834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("Can't get encoding of certificate", e);
1844f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes, KeyStore.UID_SELF,
1874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                flags)) {
1884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
1894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
1904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return new KeyPair(pubKey, privKey);
1934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    @SuppressWarnings("deprecation")
1964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private X509Certificate generateCertificate(PrivateKey privateKey, PublicKey publicKey)
1974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throws Exception {
1984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
1994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setPublicKey(publicKey);
2004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
2014f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setSubjectDN(mSpec.getCertificateSubject());
2024f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setIssuerDN(mSpec.getCertificateSubject());
2034f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setNotBefore(mSpec.getCertificateNotBefore());
2044f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setNotAfter(mSpec.getCertificateNotAfter());
2054f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyAlgorithm(mKeyAlgorithm));
2064f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return certGen.generate(privateKey);
2074f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2084f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2094f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    @NonNull
2104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private @KeyProperties.KeyAlgorithmEnum String getKeyAlgorithm(KeyPairGeneratorSpec spec) {
2114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        String result = spec.getKeyType();
2124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (result != null) {
2134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return result;
2144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return getAlgorithm();
2164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static int getDefaultKeySize(int keyType) {
2194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (keyType == NativeConstants.EVP_PKEY_EC) {
2204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return EC_DEFAULT_KEY_SIZE;
2214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else if (keyType == NativeConstants.EVP_PKEY_RSA) {
2224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return RSA_DEFAULT_KEY_SIZE;
2234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return -1;
2254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static void checkValidKeySize(String keyAlgorithm, int keyType, int keySize)
2284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throws InvalidAlgorithmParameterException {
2294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (keyType == NativeConstants.EVP_PKEY_EC) {
2304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
2314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                throw new InvalidAlgorithmParameterException("EC keys must be >= "
2324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                        + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE);
2334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
2344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else if (keyType == NativeConstants.EVP_PKEY_RSA) {
2354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
2364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                throw new InvalidAlgorithmParameterException("RSA keys must be >= "
2374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                        + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
2384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
2394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else {
2404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new InvalidAlgorithmParameterException(
2414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                "Unsupported key algorithm: " + keyAlgorithm);
2424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static void checkCorrectParametersSpec(int keyType, int keySize,
2464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException {
2474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (keyType == NativeConstants.EVP_PKEY_RSA && spec != null) {
2484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (spec instanceof RSAKeyGenParameterSpec) {
2494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
2504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
2514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    throw new InvalidAlgorithmParameterException("RSA key size must match: "
2524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            + keySize + " vs " + rsaSpec.getKeysize());
2534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                }
2544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            } else {
2554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                throw new InvalidAlgorithmParameterException(
2564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "RSA may only use RSAKeyGenParameterSpec");
2574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
2584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static String getDefaultSignatureAlgorithmForKeyAlgorithm(
2624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            @KeyProperties.KeyAlgorithmEnum String algorithm) {
2634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
2644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return "sha256WithRSA";
2654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
2664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return "sha256WithECDSA";
2674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else {
2684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new IllegalArgumentException("Unsupported key type " + algorithm);
2694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    private static byte[][] getArgsForKeyType(int keyType, AlgorithmParameterSpec spec) {
2734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        switch (keyType) {
2744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            case NativeConstants.EVP_PKEY_RSA:
2754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                if (spec instanceof RSAKeyGenParameterSpec) {
2764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
2774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    return new byte[][] { rsaSpec.getPublicExponent().toByteArray() };
2784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                }
2794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                break;
2804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return null;
2824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2842d0ac425564ff9882ebaac5267d1a04d4af67d00Bernhard Rosenkränzer    @Override
2854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    public void initialize(int keysize, SecureRandom random) {
2864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        throw new IllegalArgumentException(
2874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                "cannot specify keysize with AndroidKeyStore KeyPairGenerator");
2884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    @Override
2914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
2924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throws InvalidAlgorithmParameterException {
2934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (params == null) {
2944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new InvalidAlgorithmParameterException(
2954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Must supply params of type " + KeyGenParameterSpec.class.getName()
2964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    + " or " + KeyPairGeneratorSpec.class.getName());
2974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
2984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        String keyAlgorithm;
3004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        KeyGenParameterSpec spec;
3014f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        boolean encryptionAtRestRequired = false;
3024f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (params instanceof KeyPairGeneratorSpec) {
3034f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
3044f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            try {
3054f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                KeyGenParameterSpec.Builder specBuilder;
3064f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                keyAlgorithm = getKeyAlgorithm(legacySpec).toUpperCase(Locale.US);
3074f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
3084f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder = new KeyGenParameterSpec.Builder(
3094f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            legacySpec.getKeystoreAlias(),
3104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.PURPOSE_SIGN
3114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            | KeyProperties.PURPOSE_VERIFY);
3124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setDigests(
3134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_NONE,
3144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_MD5,
3154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA1,
3164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA224,
3174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA256,
3184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA384,
3194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA512);
3204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
3214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder = new KeyGenParameterSpec.Builder(
3224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            legacySpec.getKeystoreAlias(),
3234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.PURPOSE_ENCRYPT
3244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            | KeyProperties.PURPOSE_DECRYPT
3254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            | KeyProperties.PURPOSE_SIGN
3264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            | KeyProperties.PURPOSE_VERIFY);
3274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setDigests(
3284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_NONE,
3294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_MD5,
3304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA1,
3314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA224,
3324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA256,
3334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA384,
3344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.DIGEST_SHA512);
3354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setSignaturePaddings(
3364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
3374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setBlockModes(KeyProperties.BLOCK_MODE_ECB);
3384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setEncryptionPaddings(
3394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.ENCRYPTION_PADDING_NONE,
3404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
3414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    // Disable randomized encryption requirement to support encryption padding NONE
3424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    // above.
3434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setRandomizedEncryptionRequired(false);
3444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                } else {
3454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    throw new InvalidAlgorithmParameterException(
3464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                            "Unsupported key algorithm: " + keyAlgorithm);
3474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                }
3484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
3494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                if (legacySpec.getKeySize() != -1) {
3504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setKeySize(legacySpec.getKeySize());
3514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                }
3524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                if (legacySpec.getAlgorithmParameterSpec() != null) {
3534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    specBuilder.setAlgorithmParameterSpec(legacySpec.getAlgorithmParameterSpec());
3544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                }
3554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
3564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
3574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
3584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
3594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                encryptionAtRestRequired = legacySpec.isEncryptionRequired();
3604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                specBuilder.setUserAuthenticationRequired(false);
3614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
3624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                spec = specBuilder.build();
3634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            } catch (NullPointerException | IllegalArgumentException e) {
3644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                throw new InvalidAlgorithmParameterException(e);
3654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
3664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else if (params instanceof KeyGenParameterSpec) {
3674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            spec = (KeyGenParameterSpec) params;
3684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            keyAlgorithm = getAlgorithm();
3694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else {
3704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new InvalidAlgorithmParameterException(
3714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Unsupported params class: " + params.getClass().getName()
3724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    + ". Supported: " + KeyGenParameterSpec.class.getName()
3734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    + ", " + KeyPairGeneratorSpec.class);
3744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
3754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
3764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm);
3774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (keyType == -1) {
3784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            throw new InvalidAlgorithmParameterException(
3794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Unsupported key algorithm: " + keyAlgorithm);
3804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
3814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        int keySize = spec.getKeySize();
3824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (keySize == -1) {
3834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            keySize = getDefaultKeySize(keyType);
3844f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (keySize == -1) {
3854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                throw new InvalidAlgorithmParameterException(
3864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                        "Unsupported key algorithm: " + keyAlgorithm);
3874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
3884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
3894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        checkCorrectParametersSpec(keyType, keySize, spec.getAlgorithmParameterSpec());
3904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        checkValidKeySize(keyAlgorithm, keyType, keySize);
3914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
3924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mKeyAlgorithm = keyAlgorithm;
3934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mKeyType = keyType;
3944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mKeySize = keySize;
3954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mSpec = spec;
3964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mEncryptionAtRestRequired = encryptionAtRestRequired;
3974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        mKeyStore = KeyStore.getInstance();
3984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
3994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
4004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber