Repository: wicket
Updated Branches:
  refs/heads/wicket-6.x 18667ac77 -> d24639522


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/d2463952
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/d2463952
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/d2463952

Branch: refs/heads/wicket-6.x
Commit: d246395221355b7dc941982b7f4e25be74e7050c
Parents: 18667ac
Author: Martin Tzvetanov Grigorov <[email protected]>
Authored: Tue Nov 11 11:47:56 2014 +0200
Committer: Martin Tzvetanov Grigorov <[email protected]>
Committed: Tue Nov 18 16:10:04 2014 +0200

----------------------------------------------------------------------
 .../core/request/mapper/CryptoMapper.java       |  34 ++++--
 .../crypt/KeyInSessionSunJceCryptFactory.java   |  33 +++++-
 .../wicket/settings/def/SecuritySettings.java   |  22 ++--
 .../core/request/mapper/CryptoMapperTest.java   |  13 ++-
 .../markup/html/form/encryption/CryptTest.java  |   7 +-
 .../apache/wicket/util/crypt/AbstractCrypt.java |  15 +--
 .../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 +++++++++++++++++++
 13 files changed, 348 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/d2463952/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 e1ab3fb..0cc2d68 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
@@ -41,9 +41,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
@@ -61,7 +69,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.
@@ -73,13 +81,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.ISecuritySettings#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
 {
@@ -103,14 +114,19 @@ public class CryptoMapper implements 
IRequestMapperDelegate
        /**
         * Encrypt with {@link ISecuritySettings#getCryptFactory()}.
         * <p>
-        * Note: Encryption is done with {@link 
ISecuritySettings#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 
ISecuritySettings#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)
        {
@@ -163,9 +179,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)
@@ -466,7 +482,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/d2463952/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/d2463952/wicket-core/src/main/java/org/apache/wicket/settings/def/SecuritySettings.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/settings/def/SecuritySettings.java
 
b/wicket-core/src/main/java/org/apache/wicket/settings/def/SecuritySettings.java
index 3b7f8ad..d866258 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/settings/def/SecuritySettings.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/settings/def/SecuritySettings.java
@@ -22,9 +22,10 @@ import 
org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
 import org.apache.wicket.authorization.IAuthorizationStrategy;
 import 
org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
 import org.apache.wicket.authorization.UnauthorizedInstantiationException;
+import org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory;
 import org.apache.wicket.settings.ISecuritySettings;
-import org.apache.wicket.util.crypt.CachingSunJceCryptFactory;
 import org.apache.wicket.util.crypt.ICryptFactory;
+import org.apache.wicket.util.lang.Args;
 
 /**
  * @author Jonathan Locke
@@ -81,14 +82,16 @@ public class SecuritySettings implements ISecuritySettings
        }
 
        /**
-        * @see org.apache.wicket.settings.ISecuritySettings#getCryptFactory()
+        * @return crypt factory used to generate crypt objects. By default it 
uses
+        * {@link 
org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory} that
+        * binds an HTTP session to store the user specific key
         */
        @Override
        public synchronized ICryptFactory getCryptFactory()
        {
                if (cryptFactory == null)
                {
-                       cryptFactory = new 
CachingSunJceCryptFactory(ISecuritySettings.DEFAULT_ENCRYPTION_KEY);
+                       cryptFactory = new KeyInSessionSunJceCryptFactory();
                }
                return cryptFactory;
        }
@@ -117,23 +120,14 @@ public class SecuritySettings implements ISecuritySettings
        @Override
        public void setAuthorizationStrategy(IAuthorizationStrategy strategy)
        {
-               if (strategy == null)
-               {
-                       throw new IllegalArgumentException("authorization 
strategy cannot be set to null");
-               }
+               Args.notNull(strategy, "authorization strategy");
                authorizationStrategy = strategy;
        }
 
-       /**
-        * @see 
org.apache.wicket.settings.ISecuritySettings#setCryptFactory(org.apache.wicket.util.crypt.ICryptFactory)
-        */
        @Override
        public void setCryptFactory(ICryptFactory cryptFactory)
        {
-               if (cryptFactory == null)
-               {
-                       throw new IllegalArgumentException("cryptFactory cannot 
be null");
-               }
+               Args.notNull(cryptFactory, "Crypt factory");
                this.cryptFactory = cryptFactory;
        }
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/d2463952/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 b8213e6..fce5e0a 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
@@ -40,6 +40,10 @@ import 
org.apache.wicket.request.mapper.info.PageComponentInfo;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.PackageResourceReference;
 import org.apache.wicket.request.resource.UrlResourceReference;
+import org.apache.wicket.settings.ISecuritySettings;
+import org.apache.wicket.util.IProvider;
+import org.apache.wicket.util.crypt.CachingSunJceCryptFactory;
+import org.apache.wicket.util.crypt.ICrypt;
 import org.apache.wicket.util.string.StringValue;
 import org.apache.wicket.util.string.Strings;
 import org.apache.wicket.util.tester.WicketTester;
@@ -74,7 +78,14 @@ public class CryptoMapperTest extends AbstractMapperTest
                tester = new WicketTester();
                WebApplication webApplication = tester.getApplication();
                webApplication.mountPage(MOUNTED_URL, Page1.class);
-               mapper = new 
CryptoMapper(webApplication.getRootRequestMapper(), webApplication);
+               mapper = new 
CryptoMapper(webApplication.getRootRequestMapper(), new IProvider<ICrypt>()
+               {
+                       @Override
+                       public ICrypt get()
+                       {
+                               return new 
CachingSunJceCryptFactory(ISecuritySettings.DEFAULT_ENCRYPTION_KEY).newCrypt();
+                       }
+               });
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/d2463952/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/d2463952/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 4d2c7e2..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)
                {
@@ -142,7 +143,7 @@ public abstract class AbstractCrypt implements ICrypt
         *            byte array to decrypt
         * @return the decrypted text
         */
-       private final byte[] decryptByteArray(final byte[] encrypted)
+       private byte[] decryptByteArray(final byte[] encrypted)
        {
                try
                {
@@ -163,7 +164,7 @@ public abstract class AbstractCrypt implements ICrypt
         * @return the string encrypted
         * @throws GeneralSecurityException
         */
-       private final byte[] encryptStringToByteArray(final String plainText)
+       private byte[] encryptStringToByteArray(final String plainText)
                throws GeneralSecurityException
        {
                try

http://git-wip-us.apache.org/repos/asf/wicket/blob/d2463952/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/d2463952/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/d2463952/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/d2463952/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 2af21f4..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 final 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/d2463952/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/d2463952/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/d2463952/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;
+               }
+       }
+}

Reply via email to