Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52886ca7 authored by Alex Klyubin's avatar Alex Klyubin
Browse files

A way to obtain KeyStore operation handle from crypto primitives.

This adds AndroidKeyStore.getKeyStoreOperationHandle method which can
be used to obtain the KeyStore operation handle corresponding to the
provided JCA cryto primitive (provided it's backed by
AndroidKeyStore).

Bug: 18088752
Change-Id: Iaa3b6f9b2281b2ec2de8fd5946d353dc7fdb3d2d
parent b7a34e49
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -16,8 +16,12 @@

package android.security;

import java.lang.reflect.Method;
import java.security.Provider;

import javax.crypto.Cipher;
import javax.crypto.Mac;

/**
 * A provider focused on providing JCA interfaces for the Android KeyStore.
 *
@@ -71,4 +75,42 @@ public class AndroidKeyStoreProvider extends Provider {
        put("Cipher." + transformation, implClass);
        put("Cipher." + transformation + " SupportedKeyClasses", KeyStoreSecretKey.class.getName());
    }

    /**
     * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
     * primitive.
     *
     * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
     *
     * @return KeyStore operation handle or {@code null} if the provided primitive's KeyStore
     *         operation is not in progress.
     *
     * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
     *         by AndroidKeyStore provider.
     */
    public static Long getKeyStoreOperationHandle(Object cryptoPrimitive) {
        if (cryptoPrimitive == null) {
            throw new NullPointerException();
        }
        if ((!(cryptoPrimitive instanceof Mac)) && (!(cryptoPrimitive instanceof Cipher))) {
            throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive);
        }
        Object spi;
        // TODO: Replace this Reflection based codewith direct invocations once the libcore changes
        // are in.
        try {
            Method getSpiMethod = cryptoPrimitive.getClass().getDeclaredMethod("getSpi");
            getSpiMethod.setAccessible(true);
            spi = getSpiMethod.invoke(cryptoPrimitive);
        } catch (ReflectiveOperationException e) {
            throw new IllegalArgumentException(
                    "Unsupported crypto primitive: " + cryptoPrimitive, e);
        }
        if (!(spi instanceof KeyStoreCryptoOperation)) {
            throw new IllegalArgumentException(
                    "Crypto primitive not backed by Android KeyStore: " + cryptoPrimitive
                    + ", spi: " + spi);
        }
        return ((KeyStoreCryptoOperation) spi).getOperationHandle();
    }
}
+21 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ import javax.crypto.spec.IvParameterSpec;
 *
 * @hide
 */
public abstract class KeyStoreCipherSpi extends CipherSpi {
public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {

    public abstract static class AES extends KeyStoreCipherSpi {
        protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
@@ -129,6 +129,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi {
     * error conditions in between.
     */
    private IBinder mOperationToken;
    private Long mOperationHandle;
    private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;

    protected KeyStoreCipherSpi(
@@ -192,6 +193,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi {
            mOperationToken = null;
            mKeyStore.abort(operationToken);
        }
        mOperationHandle = null;
        mMainDataStreamer = null;
        mAdditionalEntropyForBegin = null;
    }
@@ -230,6 +232,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi {
            throw new CryptoOperationException("Keystore returned null operation token");
        }
        mOperationToken = opResult.token;
        mOperationHandle = opResult.operationHandle;
        loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
        mFirstOperationInitiated = true;
        mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
@@ -348,6 +351,23 @@ public abstract class KeyStoreCipherSpi extends CipherSpi {
        throw new UnsupportedOperationException();
    }

    @Override
    public void finalize() throws Throwable {
        try {
            IBinder operationToken = mOperationToken;
            if (operationToken != null) {
                mKeyStore.abort(operationToken);
            }
        } finally {
            super.finalize();
        }
    }

    @Override
    public Long getOperationHandle() {
        return mOperationHandle;
    }

    // The methods below may need to be overridden by subclasses that use algorithm-specific
    // parameters.

+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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;

/**
 * Cryptographic operation backed by {@link KeyStore}.
 *
 * @hide
 */
public interface KeyStoreCryptoOperation {
    /**
     * Gets the KeyStore operation handle of this crypto operation.
     *
     * @return handle or {@code null} if the KeyStore operation is not in progress.
     */
    Long getOperationHandle();
}
+9 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import javax.crypto.MacSpi;
 *
 * @hide
 */
public abstract class KeyStoreHmacSpi extends MacSpi {
public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {

    public static class HmacSHA256 extends KeyStoreHmacSpi {
        public HmacSHA256() {
@@ -50,6 +50,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi {
    // The fields below are reset by the engineReset operation.
    private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
    private IBinder mOperationToken;
    private Long mOperationHandle;

    protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest, int macSizeBytes) {
        mDigest = digest;
@@ -87,6 +88,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi {
            mOperationToken = null;
            mKeyStore.abort(operationToken);
        }
        mOperationHandle = null;
        mChunkedStreamer = null;

        KeymasterArguments keymasterArgs = new KeymasterArguments();
@@ -108,6 +110,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi {
        if (mOperationToken == null) {
            throw new CryptoOperationException("Keystore returned null operation token");
        }
        mOperationHandle = opResult.operationHandle;
        mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
                        mKeyStore, mOperationToken));
@@ -157,11 +160,15 @@ public abstract class KeyStoreHmacSpi extends MacSpi {
        try {
            IBinder operationToken = mOperationToken;
            if (operationToken != null) {
                mOperationToken = null;
                mKeyStore.abort(operationToken);
            }
        } finally {
            super.finalize();
        }
    }

    @Override
    public Long getOperationHandle() {
        return mOperationHandle;
    }
}