/** * Copyright (c) 2011-2012 Optimax Software Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Optimax Software, ElasticInbox, nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.elasticinbox.config.crypto; import static com.google.common.base.Preconditions.checkArgument; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.Enumeration; import java.util.concurrent.ConcurrentHashMap; import javax.crypto.SecretKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.elasticinbox.config.ConfigurationException; public class SymmetricKeyStorage { private static final Logger logger = LoggerFactory.getLogger(SymmetricKeyStorage.class); private final static String KEYSTORE_TYPE = "JCEKS"; private static KeyStore ks; private static ConcurrentHashMap<String, SecretKey> keys = new ConcurrentHashMap<String, SecretKey>(5); public SymmetricKeyStorage() { // by default do not initialize keys } public SymmetricKeyStorage(final File keystore, final String password) throws ConfigurationException { this.loadAllKeys(keystore, password); } /** * Get symmetric key * * @param keyAlias Key alias * @return */ public SecretKey getKey(String alias) { checkArgument(!keys.isEmpty(), "No symmetric keys found in keystore."); checkArgument(keys.containsKey(alias), "Symmetric key alias \"%s\" not found in keystore.", alias); return keys.get(alias); } /** * Check if key exists * * @param keyAlias * @return */ public boolean containsKey(String alias) { return keys.containsKey(alias); } /** * Load all symmetric keys into memory * * @param keystore Keystore file * @param password Password * @throws ConfigurationException */ private void loadAllKeys(final File keystore, final String password) throws ConfigurationException { try { ks = KeyStore.getInstance(KEYSTORE_TYPE); FileInputStream fis = null; try { fis = new FileInputStream(keystore); ks.load(fis, password.toCharArray()); } finally { if (fis != null) { fis.close(); } } Enumeration<String> aliases = ks.aliases(); while(aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (ks.isKeyEntry(alias)) { SecretKey sk = (SecretKey) ks.getKey(alias, password.toCharArray()); keys.put(alias, sk); logger.debug("Loaded encyption key {} from keystore.", alias); } } } catch (IOException ioe) { throw new ConfigurationException("Unable to access key store: " + ioe.getMessage(), ioe); } catch (GeneralSecurityException gse) { throw new ConfigurationException("Unable to load encryption keys: " + gse.getMessage(), gse); } } }