All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.encryptionsdk.jce.KeyStoreProvider Maven / Gradle / Ivy

/*
 * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
 * in compliance with the License. A copy of the License is located at
 * 
 * http://aws.amazon.com/apache2.0
 * 
 * or in the "license" file accompanying this file. This file 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 com.amazonaws.encryptionsdk.jce;

import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStore.SecretKeyEntry;
import java.security.KeyStore.TrustedCertificateEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.DataKey;
import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.MasterKeyProvider;
import com.amazonaws.encryptionsdk.MasterKeyRequest;
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.exception.NoSuchMasterKeyException;
import com.amazonaws.encryptionsdk.exception.UnsupportedProviderException;

/**
 * This {@link MasterKeyProvider} provides keys backed by a JCE {@link KeyStore}. Please see
 * {@link #decryptDataKey(CryptoAlgorithm, Collection, Map)} for an of how decryption is managed and
 * see {@link #getMasterKeysForEncryption(MasterKeyRequest)} for an explanation of how encryption is
 * managed.
 */
public class KeyStoreProvider extends MasterKeyProvider {
    private final String providerName_;
    private final KeyStore keystore_;
    private final ProtectionParameter protection_;
    private final String wrappingAlgorithm_;
    private final String keyAlgorithm_;
    private final List aliasNames_;

    /**
     * Creates an instance of this class using {@code wrappingAlgorithm} which will work
     * for decrypt only.
     */
    public KeyStoreProvider(final KeyStore keystore, final ProtectionParameter protection,
            final String providerName, final String wrappingAlgorithm) {
        this(keystore, protection, providerName, wrappingAlgorithm, new String[0]);
    }

    /**
     * Creates an instance of this class using {@code wrappingAlgorithm} which will encrypt data to
     * the keys specified by {@code aliasNames}.
     */
    public KeyStoreProvider(final KeyStore keystore, final ProtectionParameter protection,
            final String providerName, final String wrappingAlgorithm, final String... aliasNames) {
        keystore_ = keystore;
        protection_ = protection;
        wrappingAlgorithm_ = wrappingAlgorithm;
        aliasNames_ = Arrays.asList(aliasNames);
        providerName_ = providerName;
        keyAlgorithm_ = wrappingAlgorithm.split("/", 2)[0].toUpperCase();
    }

    /**
     * Returns a {@link JceMasterKey} corresponding to the entry in the {@link KeyStore} with the
     * specified alias and compatible algorithm.
     */
    @Override
    public JceMasterKey getMasterKey(final String provider, final String keyId) throws UnsupportedProviderException,
            NoSuchMasterKeyException {
        if (!canProvide(provider)) {
            throw new UnsupportedProviderException();
        }
        final JceMasterKey result = internalGetMasterKey(provider, keyId);
        if (result == null) {
            throw new NoSuchMasterKeyException();
        } else {
            return result;
        }
    }

    private JceMasterKey internalGetMasterKey(final String provider, final String keyId) {
        final Entry entry;
        try {
            entry = keystore_.getEntry(keyId, keystore_.isKeyEntry(keyId) ? protection_ : null);
        } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
            throw new UnsupportedProviderException(e);
        }
        if (entry == null) {
            throw new NoSuchMasterKeyException();
        }
        if (entry instanceof SecretKeyEntry) {
            final SecretKeyEntry skEntry = (SecretKeyEntry) entry;
            if (!skEntry.getSecretKey().getAlgorithm().equals(keyAlgorithm_)) {
                return null;
            }
            return JceMasterKey.getInstance(skEntry.getSecretKey(), provider, keyId, wrappingAlgorithm_);
        } else if (entry instanceof PrivateKeyEntry) {
            final PrivateKeyEntry pkEntry = (PrivateKeyEntry) entry;
            if (!pkEntry.getPrivateKey().getAlgorithm().equals(keyAlgorithm_)) {
                return null;
            }
            return JceMasterKey.getInstance(pkEntry.getCertificate().getPublicKey(), pkEntry.getPrivateKey(), provider,
                    keyId, wrappingAlgorithm_);
        } else if (entry instanceof TrustedCertificateEntry) {
            final TrustedCertificateEntry certEntry = (TrustedCertificateEntry) entry;
            if (!certEntry.getTrustedCertificate().getPublicKey().getAlgorithm().equals(keyAlgorithm_)) {
                return null;
            }
            return JceMasterKey.getInstance(certEntry.getTrustedCertificate().getPublicKey(), null, provider, keyId,
                    wrappingAlgorithm_);
        } else {
            throw new NoSuchMasterKeyException();
        }
    }

    /**
     * Returns "JavaKeyStore".
     */
    @Override
    public String getDefaultProviderId() {
        return providerName_;
    }

    /**
     * Returns {@link JceMasterKey}s corresponding to the {@code aliasNames} passed into the
     * constructor.
     */
    @Override
    public List getMasterKeysForEncryption(final MasterKeyRequest request) {
        if (aliasNames_ != null) {
            final List result = new ArrayList<>();
            for (final String alias : aliasNames_) {
                result.add(getMasterKey(alias));
            }
            return result;
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * Attempts to decrypts the {@code encryptedDataKeys} by first iterating through all
     * {@code aliasNames} specified in the constructor and then over
     * all other compatible keys in the {@link KeyStore}. This includes
     * {@code TrustedCertificates} as well as standard key entries.
     */
    @Override
    public DataKey decryptDataKey(final CryptoAlgorithm algorithm,
            final Collection encryptedDataKeys,
            final Map encryptionContext)
            throws UnsupportedProviderException, AwsCryptoException {
        final List exceptions = new ArrayList<>();
        for (final EncryptedDataKey edk : encryptedDataKeys) {
            try {
                if (canProvide(edk.getProviderId())) {
                    final String alias = new String(edk.getProviderInformation(), StandardCharsets.UTF_8);
                    if (keystore_.isKeyEntry(alias)) {
                        final DataKey result = getMasterKey(alias).decryptDataKey(algorithm,
                                Collections.singletonList(edk),
                                encryptionContext);
                        if (result != null) {
                            return result;
                        }
                    }
                }
            } catch (final Exception ex) {
                exceptions.add(ex);
            }
        }

        throw buildCannotDecryptDksException(exceptions);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy