wicket-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mgrigo...@apache.org
Subject wicket git commit: WICKET-5756 Allow to use custom ciphers when using SunJceCrypt class
Date Tue, 18 Nov 2014 14:17:17 GMT
Repository: wicket
Updated Branches:
  refs/heads/master 0374c0405 -> 1cb35a067


WICKET-5756 Allow to use custom ciphers when using SunJceCrypt class

(cherry picked from commit e7abf489a55372d72f5f439d213c3cc9f8e16708)


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/1cb35a06
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/1cb35a06
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/1cb35a06

Branch: refs/heads/master
Commit: 1cb35a0670c29536ff35a7f91aa9b2e88e85fb79
Parents: 0374c04
Author: Martin Tzvetanov Grigorov <mgrigorov@apache.org>
Authored: Tue Nov 11 11:47:56 2014 +0200
Committer: Martin Tzvetanov Grigorov <mgrigorov@apache.org>
Committed: Tue Nov 18 16:17:03 2014 +0200

----------------------------------------------------------------------
 .../core/request/mapper/CryptoMapper.java       |  36 +++++--
 .../crypt/KeyInSessionSunJceCryptFactory.java   |  33 +++++-
 .../core/request/mapper/CryptoMapperTest.java   |   2 +-
 .../markup/html/form/encryption/CryptTest.java  |   7 +-
 .../apache/wicket/util/crypt/AbstractCrypt.java |  11 +-
 .../wicket/util/crypt/ClassCryptFactory.java    |  15 ++-
 .../crypt/CryptFactoryCachingDecorator.java     |  10 +-
 .../wicket/util/crypt/NoCryptFactory.java       |  10 +-
 .../apache/wicket/util/crypt/SunJceCrypt.java   |  83 +++++++++++---
 .../apache/wicket/util/crypt/TrivialCrypt.java  |  11 --
 .../wicket/util/crypt/SunJceCryptTest.java      |  75 +++++++++++++
 ...UnlimitedStrengthJurisdictionPolicyTest.java | 107 +++++++++++++++++++
 12 files changed, 328 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java
b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java
index 78f0288..c006bc1 100755
--- a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/CryptoMapper.java
@@ -40,9 +40,17 @@ import org.slf4j.LoggerFactory;
 /**
  * <p>
  * A request mapper that encrypts URLs generated by another mapper. This mapper encrypts
the segments
- * and query parameters of URLs starting with {@link IMapperContext#getNamespace()}, and
the just the
+ * and query parameters of URLs starting with {@link IMapperContext#getNamespace()}, and
just the
  * {@link PageComponentInfo} parameter for mounted URLs.
  * </p>
+ *
+ * <p>
+ * <strong>Important</strong>: for better security it is recommended to use
+ * {@link org.apache.wicket.core.request.mapper.CryptoMapper#CryptoMapper(org.apache.wicket.request.IRequestMapper,
org.apache.wicket.util.IProvider)}
+ * constructor with {@link org.apache.wicket.util.crypt.ICrypt} implementation that generates
a
+ * separate key for each user. {@link org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory}
provides such an
+ * implementation that stores the key in the HTTP session.
+ * </p>
  * 
  * <p>
  * This mapper can be mounted before or after mounting other pages, but will only encrypt
URLs for
@@ -60,7 +68,7 @@ import org.slf4j.LoggerFactory;
  * encrypted URL until the encrypted URL has the same number of segments as the original
URL had.
  * Each checksum segment has a precise 5 character value, calculated using a checksum. This
helps in calculating
  * the relative distance from the original URL. When a URL is returned by the browser, we
iterate through these
- * checksummed placeholder URL segments. If the segment matches the expected checksum, then
the segment it deemed
+ * checksummed placeholder URL segments. If the segment matches the expected checksum, then
the segment is deemed
  * to be the corresponding segment in the original URL. If the segment does not match the
expected checksum, then
  * the segment is deemed a plain text sibling of the corresponding segment in the original
URL, and all subsequent
  * segments are considered plain text children of the current segment.
@@ -72,13 +80,16 @@ import org.slf4j.LoggerFactory;
  * 
  * <p>
  * {@link CryptoMapper} can be configured to mark encrypted URLs as encrypted, and throw
a {@link PageExpiredException}
- * exception if a encrypted URL cannot be decrypted. This can occur when using {@code KeyInSessionSubJceCryptFactory},
and
+ * exception if a encrypted URL cannot be decrypted. This can occur when using {@code KeyInSessionSunJceCryptFactory},
and
  * the session has expired.
  * </p>
  * 
  * @author igor.vaynberg
  * @author Jesse Long
  * @author svenmeier
+ * @see org.apache.wicket.settings.SecuritySettings#setCryptFactory(org.apache.wicket.util.crypt.ICryptFactory)
+ * @see org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory
+ * @see org.apache.wicket.util.crypt.SunJceCrypt
  */
 public class CryptoMapper implements IRequestMapperDelegate
 {
@@ -102,14 +113,19 @@ public class CryptoMapper implements IRequestMapperDelegate
 	/**
 	 * Encrypt with {@link org.apache.wicket.settings.SecuritySettings#getCryptFactory()}.
 	 * <p>
-	 * Note: Encryption is done with {@link org.apache.wicket.settings.SecuritySettings#DEFAULT_ENCRYPTION_KEY}
-	 * if you haven't configured an alternative {@link ICryptFactory}. Alternatively use
-	 * {@link CryptoMapper#CryptoMapper(IRequestMapper, IProvider)} with a specific {@link ICrypt}.
-	 * 
+	 * <strong>Important</strong>: Encryption is done with {@link org.apache.wicket.settings.SecuritySettings#DEFAULT_ENCRYPTION_KEY}
if you haven't
+	 * configured an alternative {@link ICryptFactory}. For better security it is recommended
to use
+	 * {@link CryptoMapper#CryptoMapper(IRequestMapper, IProvider)} with a specific {@link ICrypt}
implementation
+	 * that generates a separate key for each user.
+	 * {@link org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory} provides such
an implementation that stores the
+	 * key in the HTTP session.
+	 * </p>
+	 *
 	 * @param wrappedMapper
 	 *            the non-crypted request mapper
 	 * @param application
 	 *            the current application
+	 * @see org.apache.wicket.util.crypt.SunJceCrypt
 	 */
 	public CryptoMapper(final IRequestMapper wrappedMapper, final Application application)
 	{
@@ -162,9 +178,9 @@ public class CryptoMapper implements IRequestMapperDelegate
 	 * This implementation decrypts the URL and passes the decrypted URL to the wrapped mapper.
 	 * </p>
 	 * @param request
-	 *		The request for which to get a compatability score.
+	 *		The request for which to get a compatibility score.
 	 * 
-	 * @return The compatability score.
+	 * @return The compatibility score.
 	 */
 	@Override
 	public int getCompatibilityScore(final Request request)
@@ -454,7 +470,7 @@ public class CryptoMapper implements IRequestMapperDelegate
 		{
 			/*
 			 * This should always be true. Home page URLs are the only ones without
-			 * segments, and we dont encrypt those with this method.
+			 * segments, and we don't encrypt those with this method.
 			 * 
 			 * We always add the first segment of the URL, because we encrypt a URL like:
 			 *	/path/to/something

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-core/src/main/java/org/apache/wicket/core/util/crypt/KeyInSessionSunJceCryptFactory.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/crypt/KeyInSessionSunJceCryptFactory.java
b/wicket-core/src/main/java/org/apache/wicket/core/util/crypt/KeyInSessionSunJceCryptFactory.java
index d3b137b..5b3bae6 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/crypt/KeyInSessionSunJceCryptFactory.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/crypt/KeyInSessionSunJceCryptFactory.java
@@ -23,6 +23,7 @@ import org.apache.wicket.Session;
 import org.apache.wicket.util.crypt.ICrypt;
 import org.apache.wicket.util.crypt.ICryptFactory;
 import org.apache.wicket.util.crypt.SunJceCrypt;
+import org.apache.wicket.util.lang.Args;
 
 /**
  * Crypt factory that produces {@link SunJceCrypt} instances based on http session-specific
@@ -36,11 +37,31 @@ import org.apache.wicket.util.crypt.SunJceCrypt;
 public class KeyInSessionSunJceCryptFactory implements ICryptFactory
 {
 	/** metadata-key used to store crypto-key in session metadata */
-	private static MetaDataKey<String> KEY = new MetaDataKey<String>()
+	private static final MetaDataKey<String> KEY = new MetaDataKey<String>()
 	{
 		private static final long serialVersionUID = 1L;
 	};
 
+	private final String cryptMethod;
+
+	/**
+	 * Constructor using {@link javax.crypto.Cipher} {@value org.apache.wicket.util.crypt.SunJceCrypt#DEFAULT_CRYPT_METHOD}
+	 */
+	public KeyInSessionSunJceCryptFactory()
+	{
+		this(SunJceCrypt.DEFAULT_CRYPT_METHOD);
+	}
+
+	/**
+	 * Constructor that uses a custom {@link javax.crypto.Cipher}
+	 *
+	 * @param cryptMethod
+	 *              the name of the crypt method (cipher)
+	 */
+	public KeyInSessionSunJceCryptFactory(String cryptMethod)
+	{
+		this.cryptMethod = Args.notNull(cryptMethod, "Crypt method");
+	}
 
 	@Override
 	public ICrypt newCrypt()
@@ -58,8 +79,16 @@ public class KeyInSessionSunJceCryptFactory implements ICryptFactory
 		}
 
 		// build the crypt based on session key
-		ICrypt crypt = new SunJceCrypt();
+		ICrypt crypt = createCrypt();
 		crypt.setKey(key);
 		return crypt;
 	}
+
+	/**
+	 * @return the {@link org.apache.wicket.util.crypt.ICrypt} to use
+	 */
+	protected ICrypt createCrypt()
+	{
+		return new SunJceCrypt(cryptMethod);
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java
b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java
index 7b2cd4d..ec2459b 100644
--- a/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/core/request/mapper/CryptoMapperTest.java
@@ -48,11 +48,11 @@ import org.apache.wicket.util.crypt.CachingSunJceCryptFactory;
 import org.apache.wicket.util.crypt.ICrypt;
 import org.apache.wicket.util.crypt.ICryptFactory;
 import org.apache.wicket.util.string.StringValue;
-import org.apache.wicket.util.string.Strings;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.apache.wicket.util.string.Strings;
 
 /**
  * Tests for {@link CryptoMapper}

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-core/src/test/java/org/apache/wicket/markup/html/form/encryption/CryptTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/encryption/CryptTest.java
b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/encryption/CryptTest.java
index 4d019d8..72024c6 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/encryption/CryptTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/encryption/CryptTest.java
@@ -28,21 +28,18 @@ import org.junit.Test;
  */
 public class CryptTest extends WicketTestCase
 {
-	/**
-	 * 
-	 * 
-	 */
 	@Test
 	public void crypt()
 	{
 		final ICrypt crypt = new SunJceCrypt();
+		crypt.setKey("someStableKey");
 
 		try
 		{
 			if (crypt.encryptUrlSafe("test") != null)
 			{
 				final String text = "abcdefghijkABC: A test which creates a '/' and/or a '+'";
-				final String expectedUrlSafeEncrypted = "g-N_AGk2b3qe70kJ0we4Rsa8getbnPLm6NyE0BCd-go0P-0kuIe6UvAYP7dlzx-9mfmPaMQ5lCk";
+				final String expectedUrlSafeEncrypted = "xXMS3UMELV--qVINGVFaYaiqUPOtryc_E4x0MyMFgYl-TgTGKxczTzPvwJrE-4YEVMpl-F3eDAg";
 
 				final String encrypted = crypt.encryptUrlSafe(text);
 				assertEquals(expectedUrlSafeEncrypted, encrypted);

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/AbstractCrypt.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/AbstractCrypt.java b/wicket-util/src/main/java/org/apache/wicket/util/crypt/AbstractCrypt.java
index 7e91aa2..9daa2dd 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/AbstractCrypt.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/AbstractCrypt.java
@@ -18,6 +18,7 @@ package org.apache.wicket.util.crypt;
 
 import java.io.UnsupportedEncodingException;
 import java.security.GeneralSecurityException;
+import java.util.UUID;
 
 import javax.crypto.Cipher;
 
@@ -32,9 +33,6 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class AbstractCrypt implements ICrypt
 {
-	/** Default encryption key */
-	private static final String DEFAULT_ENCRYPTION_KEY = "WiCkEt-CrYpT";
-
 	/** Encoding used to convert java String from and to byte[] */
 	private static final String CHARACTER_ENCODING = "UTF-8";
 
@@ -42,13 +40,14 @@ public abstract class AbstractCrypt implements ICrypt
 	private static final Logger log = LoggerFactory.getLogger(AbstractCrypt.class);
 
 	/** Key used to de-/encrypt the data */
-	private String encryptionKey = DEFAULT_ENCRYPTION_KEY;
+	private String encryptionKey;
 
 	/**
 	 * Constructor
 	 */
 	public AbstractCrypt()
 	{
+		this.encryptionKey = UUID.randomUUID().toString();
 	}
 
 	/**
@@ -86,7 +85,9 @@ public abstract class AbstractCrypt implements ICrypt
 		try
 		{
 			byte[] encrypted = encryptStringToByteArray(plainText);
-			return new String(new Base64(-1, null, true).encode(encrypted), CHARACTER_ENCODING);
+			Base64 base64 = new Base64(-1, null, true);
+			byte[] encoded = base64.encode(encrypted);
+			return new String(encoded, CHARACTER_ENCODING);
 		}
 		catch (GeneralSecurityException e)
 		{

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/ClassCryptFactory.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/ClassCryptFactory.java
b/wicket-util/src/main/java/org/apache/wicket/util/crypt/ClassCryptFactory.java
index a144ecc..b2e260c 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/ClassCryptFactory.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/ClassCryptFactory.java
@@ -57,30 +57,27 @@ public class ClassCryptFactory implements ICryptFactory
 		this.encryptionKey = encryptionKey;
 	}
 
-	/**
-	 * @see org.apache.wicket.util.crypt.ICryptFactory#newCrypt()
-	 */
 	@Override
 	public ICrypt newCrypt()
 	{
 		try
 		{
 			ICrypt crypt = (ICrypt)(cryptClass.get()).newInstance();
-			log.info("using encryption/decryption object " + crypt);
+			log.info("using encryption/decryption object {}", crypt);
 			crypt.setKey(encryptionKey);
 			return crypt;
 		}
 		catch (Exception e)
 		{
 			log.warn("************************** WARNING **************************");
-			log.warn("As the instantion of encryption/decryption class:");
+			log.warn("As the instantiation of encryption/decryption class:");
 			log.warn("\t" + cryptClass);
 			log.warn("failed, Wicket will fallback on a dummy implementation");
 			log.warn("\t(" + NoCrypt.class.getName() + ")");
-			log.warn("This is not recommended for production systems.");
+			log.warn("This is NOT recommended for production systems.");
 			log.warn("Please override method org.apache.wicket.Application.newCrypt()");
-			log.warn("to provide a custom encryption/decryption implementation");
-			log.warn("The cause of the instantion failure: ");
+			log.warn("to provide a custom encryption/decryption implementation.");
+			log.warn("The cause of the instantiation failure: ");
 			log.warn("\t" + e.getMessage());
 			if (log.isDebugEnabled())
 			{
@@ -88,7 +85,7 @@ public class ClassCryptFactory implements ICryptFactory
 			}
 			else
 			{
-				log.warn("set log level to DEBUG to display the stack trace.");
+				log.warn("Set log level to DEBUG to display the stack trace.");
 			}
 			log.warn("*************************************************************");
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/CryptFactoryCachingDecorator.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/CryptFactoryCachingDecorator.java
b/wicket-util/src/main/java/org/apache/wicket/util/crypt/CryptFactoryCachingDecorator.java
index 3a8be90..9fc7142 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/CryptFactoryCachingDecorator.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/CryptFactoryCachingDecorator.java
@@ -17,6 +17,8 @@
 package org.apache.wicket.util.crypt;
 
 
+import org.apache.wicket.util.lang.Args;
+
 /**
  * {@link ICryptFactory} decorator that caches the call to {@link ICryptFactory#newCrypt()}
  * 
@@ -35,16 +37,10 @@ public class CryptFactoryCachingDecorator implements ICryptFactory
 	 */
 	public CryptFactoryCachingDecorator(final ICryptFactory delegate)
 	{
-		if (delegate == null)
-		{
-			throw new IllegalArgumentException("delegate cannot be null");
-		}
+		Args.notNull(delegate, "delegate");
 		this.delegate = delegate;
 	}
 
-	/**
-	 * @see org.apache.wicket.util.crypt.ICryptFactory#newCrypt()
-	 */
 	@Override
 	public final ICrypt newCrypt()
 	{

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/NoCryptFactory.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/NoCryptFactory.java b/wicket-util/src/main/java/org/apache/wicket/util/crypt/NoCryptFactory.java
index a7baba5..f33efce 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/NoCryptFactory.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/NoCryptFactory.java
@@ -26,18 +26,10 @@ public class NoCryptFactory implements ICryptFactory
 {
 	private static final ICrypt crypt = new NoCrypt();
 
-	/**
-	 * Construct.
-	 */
-	public NoCryptFactory()
-	{
-
-	}
-
 	@Override
 	public ICrypt newCrypt()
 	{
 		return crypt;
 	}
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/SunJceCrypt.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/SunJceCrypt.java b/wicket-util/src/main/java/org/apache/wicket/util/crypt/SunJceCrypt.java
index 65036c1..934f586 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/SunJceCrypt.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/SunJceCrypt.java
@@ -20,7 +20,9 @@ import java.security.GeneralSecurityException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
 
 import javax.crypto.Cipher;
 import javax.crypto.SecretKey;
@@ -28,6 +30,8 @@ import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.PBEParameterSpec;
 
+import org.apache.wicket.util.lang.Args;
+
 
 /**
  * Provide some simple means to encrypt and decrypt strings such as passwords. The whole
@@ -44,19 +48,37 @@ public class SunJceCrypt extends AbstractCrypt
 	 */
 	private final static int COUNT = 17;
 
-	/** Name of encryption method */
-	private static final String CRYPT_METHOD = "PBEWithMD5AndDES";
+	/** Name of the default encryption method */
+	public static final String DEFAULT_CRYPT_METHOD = "PBEWithMD5AndDES";
 
 	/** Salt */
-	private final static byte[] salt = { (byte)0x15, (byte)0x8c, (byte)0xa3, (byte)0x4a,
+	public final static byte[] SALT = { (byte)0x15, (byte)0x8c, (byte)0xa3, (byte)0x4a,
 			(byte)0x66, (byte)0x51, (byte)0x2a, (byte)0xbc };
 
+	/** The name of encryption method (cipher) */
+	private final String cryptMethod;
+
 	/**
 	 * Constructor
 	 */
 	public SunJceCrypt()
 	{
-		if (Security.getProviders("Cipher." + CRYPT_METHOD).length > 0)
+		this(DEFAULT_CRYPT_METHOD);
+	}
+
+	/**
+	 * Constructor that uses a custom encryption method (cipher).
+	 * You may need to override {@link #createKeySpec()} and/or
+	 * {@link #createParameterSpec()} for the custom cipher.
+	 *
+	 * @param cryptMethod
+	 *              the name of encryption method (the cipher)
+	 */
+	public SunJceCrypt(String cryptMethod)
+	{
+		this.cryptMethod = Args.notNull(cryptMethod, "Crypt method");
+
+		if (Security.getProviders("Cipher." + cryptMethod).length > 0)
 		{
 			return; // we are good to go!
 		}
@@ -77,39 +99,74 @@ public class SunJceCrypt extends AbstractCrypt
 	 * Crypts the given byte array
 	 * 
 	 * @param input
-	 *            byte array to be crypted
+	 *            byte array to be encrypted
 	 * @param mode
 	 *            crypt mode
 	 * @return the input crypted. Null in case of an error
 	 * @throws GeneralSecurityException
 	 */
 	@Override
-	protected final byte[] crypt(final byte[] input, final int mode)
+	protected byte[] crypt(final byte[] input, final int mode)
 		throws GeneralSecurityException
 	{
 		SecretKey key = generateSecretKey();
-		PBEParameterSpec spec = new PBEParameterSpec(salt, COUNT);
-		Cipher ciph = Cipher.getInstance(CRYPT_METHOD);
-		ciph.init(mode, key, spec);
+		AlgorithmParameterSpec spec = createParameterSpec();
+		Cipher ciph = createCipher(key, spec, mode);
 		return ciph.doFinal(input);
 	}
 
 	/**
+	 * Creates the {@link javax.crypto.Cipher} that will do the de-/encryption.
+	 *
+	 * @param key
+	 *              the secret key to use
+	 * @param spec
+	 *              the parameters spec to use
+	 * @param mode
+	 *              the mode ({@link javax.crypto.Cipher#ENCRYPT_MODE} or {@link javax.crypto.Cipher#DECRYPT_MODE})
+	 * @return the cipher that will do the de-/encryption
+	 * @throws GeneralSecurityException
+	 */
+	protected Cipher createCipher(SecretKey key, AlgorithmParameterSpec spec, int mode) throws
GeneralSecurityException
+	{
+		Cipher cipher = Cipher.getInstance(cryptMethod);
+		cipher.init(mode, key, spec);
+		return cipher;
+	}
+
+	/**
 	 * Generate the de-/encryption key.
 	 * <p>
 	 * Note: if you don't provide your own encryption key, the implementation will use a default.
Be
 	 * aware that this is potential security risk. Thus make sure you always provide your own
one.
-	 * 
+	 *
 	 * @return secretKey the security key generated
 	 * @throws NoSuchAlgorithmException
 	 *             unable to find encryption algorithm specified
 	 * @throws InvalidKeySpecException
 	 *             invalid encryption key
 	 */
-	private SecretKey generateSecretKey() throws NoSuchAlgorithmException,
+	protected SecretKey generateSecretKey() throws NoSuchAlgorithmException,
 		InvalidKeySpecException
 	{
-		final PBEKeySpec spec = new PBEKeySpec(getKey().toCharArray());
-		return SecretKeyFactory.getInstance(CRYPT_METHOD).generateSecret(spec);
+		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(cryptMethod);
+		KeySpec spec = createKeySpec();
+		return keyFactory.generateSecret(spec);
+	}
+
+	/**
+	 * @return the parameter spec to be used for the configured crypt method
+	 */
+	protected AlgorithmParameterSpec createParameterSpec()
+	{
+		return new PBEParameterSpec(SALT, COUNT);
+	}
+
+	/**
+	 * @return the key spec to be used for the configured crypt method
+	 */
+	protected KeySpec createKeySpec()
+	{
+		return new PBEKeySpec(getKey().toCharArray());
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/main/java/org/apache/wicket/util/crypt/TrivialCrypt.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/crypt/TrivialCrypt.java b/wicket-util/src/main/java/org/apache/wicket/util/crypt/TrivialCrypt.java
index 300fb7c..5aab8e7 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/crypt/TrivialCrypt.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/crypt/TrivialCrypt.java
@@ -25,17 +25,6 @@ import java.security.GeneralSecurityException;
  */
 public class TrivialCrypt extends AbstractCrypt
 {
-	/**
-	 * Constructor
-	 */
-	public TrivialCrypt()
-	{
-		super();
-	}
-
-	/**
-	 * @see org.apache.wicket.util.crypt.AbstractCrypt#crypt(byte[], int)
-	 */
 	@Override
 	protected byte[] crypt(final byte[] input, final int mode) throws GeneralSecurityException
 	{

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/test/java/org/apache/wicket/util/crypt/SunJceCryptTest.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/test/java/org/apache/wicket/util/crypt/SunJceCryptTest.java b/wicket-util/src/test/java/org/apache/wicket/util/crypt/SunJceCryptTest.java
new file mode 100644
index 0000000..1d366bd
--- /dev/null
+++ b/wicket-util/src/test/java/org/apache/wicket/util/crypt/SunJceCryptTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.util.crypt;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class SunJceCryptTest extends Assert
+{
+	/**
+	 * Default encryption uses {@value org.apache.wicket.util.crypt.SunJceCrypt#DEFAULT_CRYPT_METHOD}
+	 */
+	@Test
+	public void defaultEncryption() throws GeneralSecurityException
+	{
+		SunJceCrypt crypt = new SunJceCrypt();
+		String input = "input";
+		byte[] encrypted = crypt.crypt(input.getBytes(), Cipher.ENCRYPT_MODE);
+
+		byte[] decrypted = crypt.crypt(encrypted, Cipher.DECRYPT_MODE);
+		assertThat(new String(decrypted), is(equalTo(input)));
+	}
+
+	/**
+	 * Uses <em>PBEWithMD5AndTripleDES</em> if unlimited cryptography is installed
+	 */
+	@Test
+	public void customPBEEncryption() throws GeneralSecurityException
+	{
+		boolean unlimitedStrengthJurisdictionPolicyInstalled = isUnlimitedStrengthJurisdictionPolicyInstalled();
+		Assume.assumeThat(unlimitedStrengthJurisdictionPolicyInstalled, is(true));
+
+		SunJceCrypt crypt = new SunJceCrypt("PBEWithMD5AndTripleDES");
+		String input = "input";
+		byte[] encrypted = crypt.crypt(input.getBytes(), Cipher.ENCRYPT_MODE);
+
+		byte[] decrypted = crypt.crypt(encrypted, Cipher.DECRYPT_MODE);
+		assertThat(new String(decrypted), is(equalTo(input)));
+	}
+
+	/**
+	 * Checks whether Oracle Unlimited Strenght Jurisdiction Policy is installed
+	 * Based on http://stackoverflow.com/a/8607735
+	 *
+	 * @return {@code true} if Unlimited Strenght Jurisdiction Policy is installed
+	 * @throws NoSuchAlgorithmException
+	 */
+	static boolean isUnlimitedStrengthJurisdictionPolicyInstalled() throws NoSuchAlgorithmException
+	{
+		return Cipher.getMaxAllowedKeyLength("AES") == Integer.MAX_VALUE;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/1cb35a06/wicket-util/src/test/java/org/apache/wicket/util/crypt/UnlimitedStrengthJurisdictionPolicyTest.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/test/java/org/apache/wicket/util/crypt/UnlimitedStrengthJurisdictionPolicyTest.java
b/wicket-util/src/test/java/org/apache/wicket/util/crypt/UnlimitedStrengthJurisdictionPolicyTest.java
new file mode 100644
index 0000000..19515e0
--- /dev/null
+++ b/wicket-util/src/test/java/org/apache/wicket/util/crypt/UnlimitedStrengthJurisdictionPolicyTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.util.crypt;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+/**
+ * A demo how to create {@link org.apache.wicket.util.crypt.ICrypt} implementation that
+ * uses <em>PBKDF2WithHmacSHA1</em> for encryption
+ */
+public class UnlimitedStrengthJurisdictionPolicyTest extends Assert
+{
+	@Test
+	public void unlimitedStrengthJurisdictionEncryption() throws GeneralSecurityException
+	{
+		boolean unlimitedStrengthJurisdictionPolicyInstalled = SunJceCryptTest.isUnlimitedStrengthJurisdictionPolicyInstalled();
+		Assume.assumeThat(unlimitedStrengthJurisdictionPolicyInstalled, is(true));
+
+		AbstractCrypt crypt = new UnlimitedStrenghtJurisdictionPolicyCrypt();
+
+		String input1 = "input1";
+		byte[] encrypted = crypt.crypt(input1.getBytes(), Cipher.ENCRYPT_MODE);
+
+		String input2 = "input2";
+		byte[] encrypted2 = crypt.crypt(input2.getBytes(), Cipher.ENCRYPT_MODE);
+
+		byte[] decrypted = crypt.crypt(encrypted, Cipher.DECRYPT_MODE);
+		assertThat(new String(decrypted), is(equalTo(input1)));
+
+		byte[] decrypted2 = crypt.crypt(encrypted2, Cipher.DECRYPT_MODE);
+		assertThat(new String(decrypted2), is(equalTo(input2)));
+	}
+
+	/**
+	 * Based on http://stackoverflow.com/a/992413
+	 */
+	private static class UnlimitedStrenghtJurisdictionPolicyCrypt extends AbstractCrypt
+	{
+		private final Cipher crypter;
+		private final Cipher decrypter;
+
+		private UnlimitedStrenghtJurisdictionPolicyCrypt() throws GeneralSecurityException
+		{
+			SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+			KeySpec spec = new PBEKeySpec(getKey().toCharArray(), SunJceCrypt.SALT, 65536, 256);
+			SecretKey tmp = factory.generateSecret(spec);
+			SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
+
+			String transformation = "AES/CBC/PKCS5Padding";
+			crypter = Cipher.getInstance(transformation);
+			crypter.init(Cipher.ENCRYPT_MODE, secret);
+			AlgorithmParameters params = crypter.getParameters();
+			byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
+
+			decrypter = Cipher.getInstance(transformation);
+			decrypter.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
+		}
+
+		@Override
+		protected byte[] crypt(byte[] input, int mode) throws GeneralSecurityException
+		{
+			byte[] result;
+			switch (mode)
+			{
+				case Cipher.ENCRYPT_MODE:
+					result = crypter.doFinal(input);
+					break;
+				case Cipher.DECRYPT_MODE:
+					result = decrypter.doFinal(input);
+					break;
+				default:
+					throw new RuntimeException("Wrong crypt mode: " + mode);
+			}
+			return result;
+		}
+	}
+}


Mime
View raw message