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 <[email protected]> Authored: Tue Nov 11 11:47:56 2014 +0200 Committer: Martin Tzvetanov Grigorov <[email protected]> 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; + } + } +}
