resolve cipher api dependency problems

This commit is contained in:
Sebastian Sdorra
2011-09-03 17:28:57 +02:00
parent 9d52d43061
commit 8c0324de73
7 changed files with 120 additions and 42 deletions

View File

@@ -58,7 +58,7 @@ import java.util.List;
import javax.servlet.ServletContextEvent;
import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherSingleton;
import sonia.scm.security.CipherUtil;
/**
*
@@ -145,10 +145,6 @@ public class ScmContextListener extends GuiceServletContextListener
injector = Guice.createInjector(moduleList);
SCMContextProvider context = SCMContext.getContext();
// init CipherSingleton
CipherHandler ch = injector.getInstance(CipherHandler.class);
CipherSingleton.init(ch);
// init StoreFactory
injector.getInstance(StoreFactory.class).init(context);

View File

@@ -65,12 +65,11 @@ import sonia.scm.repository.RepositoryBrowserUtil;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.xml.XmlRepositoryManager;
import sonia.scm.security.CipherHandler;
import sonia.scm.security.DefaultCipherHandler;
import sonia.scm.security.CipherUtil;
import sonia.scm.security.EncryptionHandler;
import sonia.scm.security.KeyGenerator;
import sonia.scm.security.MessageDigestEncryptionHandler;
import sonia.scm.security.SecurityContext;
import sonia.scm.security.UUIDKeyGenerator;
import sonia.scm.store.JAXBStoreFactory;
import sonia.scm.store.StoreFactory;
import sonia.scm.template.FreemarkerTemplateHandler;
@@ -196,14 +195,15 @@ public class ScmServletModule extends ServletModule
bind(SCMContextProvider.class).toInstance(context);
ScmConfiguration config = getScmConfiguration(context);
CipherUtil cu = CipherUtil.getInstance();
bind(StoreFactory.class).to(JAXBStoreFactory.class);
bind(ScmConfiguration.class).toInstance(config);
bind(PluginLoader.class).toInstance(pluginLoader);
bind(PluginManager.class).to(DefaultPluginManager.class);
bind(KeyGenerator.class).to(UUIDKeyGenerator.class);
bind(KeyGenerator.class).toInstance(cu.getKeyGenerator());
bind(CipherHandler.class).toInstance(cu.getCipherHandler());
bind(EncryptionHandler.class).to(MessageDigestEncryptionHandler.class);
bind(CipherHandler.class).to(DefaultCipherHandler.class);
bindExtProcessor.bindExtensions(binder());
Class<? extends FileSystem> fileSystem =

View File

@@ -1,339 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of SCM-Manager; 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.core.util.Base64;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class DefaultCipherHandler implements CipherHandler
{
/** Field description */
public static final String CIPHER_TYPE = "AES/CTR/PKCS5PADDING";
/** Field description */
public static final String DIGEST_TYPE = "SHA-512";
/** Field description */
public static final String ENCODING = "UTF-8";
/** Field description */
public static final int KEY_LENGTH = 16;
/** Field description */
public static final int SALT_LENGTH = 16;
/** Field description */
private static final String CIPHERKEY_FILENAME = ".cipherkey";
/** Field description */
private static final char[] KEY_BASE = new char[]
{
'1', '4', '7', '3', 'F', '2', '1', 'E', '-', 'C', '4', 'C', '4', '-', '4',
'6', 'C', 'C', '-', '8', '7', 'F', '6', '-', '7', 'B', '4', 'F', '0', '5',
'E', 'C', '7', '7', '2', 'E'
};
/** Field description */
private static final String KEY_TYPE = "AES";
/** the logger for DefaultCipherHandler */
private static final Logger logger =
LoggerFactory.getLogger(DefaultCipherHandler.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param context
* @param keyGenerator
*
*
* @throws IOException
*/
@Inject
public DefaultCipherHandler(SCMContextProvider context,
KeyGenerator keyGenerator)
throws IOException
{
File configDirectory = new File(context.getBaseDirectory(), "config");
IOUtil.mkdirs(configDirectory);
cipherKeyFile = new File(configDirectory, CIPHERKEY_FILENAME);
if (cipherKeyFile.exists())
{
loadKey();
}
else
{
key = keyGenerator.createKey().toCharArray();
storeKey();
}
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param value
*
* @return
*/
@Override
public String decode(String value)
{
return decode(key, value);
}
/**
* Method description
*
*
* @param plainKey
* @param value
*
* @return
*/
public String decode(char[] plainKey, String value)
{
String result = null;
try
{
byte[] encodedInput = Base64.decode(value);
byte[] salt = new byte[SALT_LENGTH];
byte[] encoded = new byte[encodedInput.length - SALT_LENGTH];
System.arraycopy(encodedInput, 0, salt, 0, SALT_LENGTH);
System.arraycopy(encodedInput, SALT_LENGTH, encoded, 0,
encodedInput.length - SALT_LENGTH);
IvParameterSpec iv = new IvParameterSpec(salt);
SecretKey secretKey = buildSecretKey(plainKey);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_TYPE);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decoded = cipher.doFinal(encoded);
result = new String(decoded, ENCODING);
}
catch (Exception ex)
{
logger.error("could not decode string", ex);
throw new CipherException(ex);
}
return result;
}
/**
* Method description
*
*
* @param value
*
* @return
*/
@Override
public String encode(String value)
{
return encode(key, value);
}
/**
* Method description
*
*
* @param plainKey
* @param value
*
* @return
*/
public String encode(char[] plainKey, String value)
{
String res = null;
try
{
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
IvParameterSpec iv = new IvParameterSpec(salt);
SecretKey secretKey = buildSecretKey(key);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_TYPE);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] inputBytes = value.getBytes(ENCODING);
byte[] encodedInput = cipher.doFinal(inputBytes);
byte[] result = new byte[salt.length + encodedInput.length];
System.arraycopy(salt, 0, result, 0, SALT_LENGTH);
System.arraycopy(encodedInput, 0, result, SALT_LENGTH,
result.length - SALT_LENGTH);
res = new String(Base64.encode(result), ENCODING);
}
catch (Exception ex)
{
logger.error("could not encode string", ex);
throw new CipherException(ex);
}
return res;
}
/**
* Method description
*
*
* @param plainKey
*
* @return
*
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
private SecretKey buildSecretKey(char[] plainKey)
throws UnsupportedEncodingException, NoSuchAlgorithmException
{
byte[] raw = new String(plainKey).getBytes(ENCODING);
MessageDigest digest = MessageDigest.getInstance(DIGEST_TYPE);
raw = digest.digest(raw);
raw = Arrays.copyOf(raw, KEY_LENGTH);
return new SecretKeySpec(raw, KEY_TYPE);
}
/**
* Method description
*
*
* @throws IOException
*/
private void loadKey() throws IOException
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(cipherKeyFile));
String line = reader.readLine();
key = decode(KEY_BASE, line).toCharArray();
}
finally
{
IOUtil.close(reader);
}
}
/**
* Method description
*
*
* @throws FileNotFoundException
*/
private void storeKey() throws FileNotFoundException
{
String storeKey = encode(KEY_BASE, new String(key));
PrintWriter output = null;
try
{
output = new PrintWriter(cipherKeyFile);
output.write(storeKey);
}
finally
{
IOUtil.close(output);
}
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private File cipherKeyFile;
/** Field description */
private char[] key = null;
/** Field description */
private SecureRandom random = new SecureRandom();
}

View File

@@ -1,58 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of SCM-Manager; 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 REGENTS 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.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- JDK imports ------------------------------------------------------------
import java.util.UUID;
/**
*
* @author Sebastian Sdorra
*/
public class UUIDKeyGenerator implements KeyGenerator
{
/**
* Method description
*
*
* @return
*/
@Override
public String createKey()
{
return UUID.randomUUID().toString();
}
}

View File

@@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory;
import sonia.scm.ConfigurationException;
import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.security.CipherUtil;
//~--- JDK imports ------------------------------------------------------------
@@ -131,6 +132,13 @@ public class ScmConfigurationUtil
Unmarshaller unmarshaller = context.createUnmarshaller();
ScmConfiguration loadedConfig =
(ScmConfiguration) unmarshaller.unmarshal(file);
String password = loadedConfig.getProxyPassword();
if (Util.isNotEmpty(password))
{
password = CipherUtil.getInstance().decode(password);
loadedConfig.setProxyPassword(password);
}
if (loadedConfig != null)
{
@@ -168,10 +176,22 @@ public class ScmConfigurationUtil
IOUtil.mkdirs(file.getParentFile());
}
ScmConfiguration config = new ScmConfiguration();
config.load(configuration);
String password = config.getProxyPassword();
if (Util.isNotEmpty(password))
{
password = CipherUtil.getInstance().encode(password);
config.setProxyPassword(password);
}
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(configuration, file);
marshaller.marshal(config, file);
configuration.fireChangeEvent();
}
catch (Exception ex)