소스 검색

SEC-1689: Moved core codec code into crypto package and removed existing duplication (Hex encoding etc). Refactoring of crypto code to use CharSequence for where possible instead of String.

Luke Taylor 14 년 전
부모
커밋
e470eaa41d
34개의 변경된 파일162개의 추가작업 그리고 159개의 파일을 삭제
  1. 1 1
      core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java
  2. 2 2
      core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java
  3. 2 2
      core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java
  4. 2 2
      core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java
  5. 1 1
      core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java
  6. 7 7
      core/src/main/java/org/springframework/security/crypto/codec/Base64.java
  7. 22 4
      core/src/main/java/org/springframework/security/crypto/codec/Hex.java
  8. 39 0
      core/src/main/java/org/springframework/security/crypto/codec/Utf8.java
  9. 1 1
      core/src/main/java/org/springframework/security/crypto/codec/package-info.java
  10. 9 8
      core/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java
  11. 2 2
      core/src/main/java/org/springframework/security/crypto/encrypt/CipherUtils.java
  12. 12 8
      core/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
  13. 4 6
      core/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java
  14. 1 0
      core/src/main/java/org/springframework/security/crypto/encrypt/TextEncryptor.java
  15. 3 3
      core/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java
  16. 3 3
      core/src/main/java/org/springframework/security/crypto/password/Digester.java
  17. 5 5
      core/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
  18. 5 3
      core/src/main/java/org/springframework/security/crypto/password/PasswordEncoder.java
  19. 19 20
      core/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java
  20. 3 65
      core/src/main/java/org/springframework/security/crypto/util/EncodingUtils.java
  21. 1 1
      core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java
  22. 2 2
      core/src/test/java/org/springframework/security/crypto/encrypt/EncryptorsTests.java
  23. 2 2
      core/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java
  24. 2 1
      core/src/test/java/org/springframework/security/crypto/password/DigesterTests.java
  25. 1 1
      core/src/test/java/org/springframework/security/crypto/password/StandardPasswordEncoderTests.java
  26. 3 2
      core/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java
  27. 1 1
      web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java
  28. 1 1
      web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java
  29. 1 1
      web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java
  30. 1 1
      web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java
  31. 1 1
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java
  32. 1 1
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java
  33. 1 1
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java
  34. 1 0
      web/template.mf

+ 1 - 1
core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java

@@ -19,7 +19,7 @@ package org.springframework.security.authentication.encoding;
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.util.Assert;
 
 

+ 2 - 2
core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java

@@ -16,8 +16,8 @@ package org.springframework.security.authentication.encoding;
 
 import java.io.UnsupportedEncodingException;
 
-import org.springframework.security.core.codec.Base64;
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.crypto.codec.Hex;
 
 /**
  * MD4 implementation of PasswordEncoder.

+ 2 - 2
core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java

@@ -4,8 +4,8 @@ import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
-import org.springframework.security.core.codec.Base64;
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.crypto.codec.Hex;
 import org.springframework.util.Assert;
 
 /**

+ 2 - 2
core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java

@@ -5,8 +5,8 @@ import java.security.SecureRandom;
 import java.util.Date;
 
 import org.springframework.beans.factory.InitializingBean;
-import org.springframework.security.core.codec.Base64;
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.crypto.codec.Hex;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 

+ 1 - 1
core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java

@@ -3,7 +3,7 @@ package org.springframework.security.core.token;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Hex;
 
 /**
  * Provides SHA512 digest methods.

+ 7 - 7
core/src/main/java/org/springframework/security/core/codec/Base64.java → core/src/main/java/org/springframework/security/crypto/codec/Base64.java

@@ -1,4 +1,4 @@
-package org.springframework.security.core.codec;
+package org.springframework.security.crypto.codec;
 
 
 /**
@@ -33,14 +33,14 @@ public final class Base64 {
      * or at the very least should not be called Base64 without also specifying that is
      * was encoded using the URL- and Filename-safe dialect.
      */
-     public final static int URL_SAFE = 16;
+    public final static int URL_SAFE = 16;
 
 
-     /**
-      * Encode using the special "ordered" dialect of Base64 described here:
-      * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
-      */
-     public final static int ORDERED = 32;
+    /**
+     * Encode using the special "ordered" dialect of Base64 described here:
+     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+     */
+    public final static int ORDERED = 32;
 
 
     /** Maximum line length (76) of Base64 output. */

+ 22 - 4
core/src/main/java/org/springframework/security/core/codec/Hex.java → core/src/main/java/org/springframework/security/crypto/codec/Hex.java

@@ -1,4 +1,4 @@
-package org.springframework.security.core.codec;
+package org.springframework.security.crypto.codec;
 
 /**
  * Hex data encoder. Converts byte arrays (such as those obtained from message digests)
@@ -30,7 +30,25 @@ public final class Hex {
         return result;
     }
 
-//    public static byte[] decode(char[] hex) {
-//
-//    }
+    public static byte[] decode(CharSequence s) {
+        int nChars = s.length();
+
+        if (nChars % 2 != 0) {
+            throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");
+        }
+
+        byte[] result = new byte[nChars / 2];
+
+        for (int i = 0; i < nChars; i += 2) {
+            int msb = Character.digit(s.charAt(i), 16);
+            int lsb = Character.digit(s.charAt(i+1), 16);
+
+            if (msb < 0 || lsb < 0) {
+                throw new IllegalArgumentException("Non-hex character in input: " + s);
+            }
+            result[i / 2] = (byte) ((msb << 4) | lsb);
+        }
+        return result;
+    }
+
 }

+ 39 - 0
core/src/main/java/org/springframework/security/crypto/codec/Utf8.java

@@ -0,0 +1,39 @@
+package org.springframework.security.crypto.codec;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+
+/**
+ * UTF-8 Charset encoder/decoder.
+ * <p>
+ * For internal use only.
+ *
+ * @author Luke Taylor
+ */
+public final class Utf8 {
+    private static final Charset CHARSET = Charset.forName("UTF-8");
+
+    /**
+     * Get the bytes of the String in UTF-8 encoded form.
+     */
+    public static byte[] encode(CharSequence string) {
+        try {
+            return CHARSET.newEncoder().encode(CharBuffer.wrap(string)).array();
+        } catch (CharacterCodingException e) {
+            throw new IllegalArgumentException("Encoding failed", e);
+        }
+    }
+
+    /**
+     * Decode the bytes in UTF-8 form into a String.
+     */
+    public static String decode(byte[] bytes) {
+        try {
+            return new String(CHARSET.newDecoder().decode(ByteBuffer.wrap(bytes)).array());
+        } catch (CharacterCodingException e) {
+            throw new IllegalArgumentException("Encoding failed", e);
+        }
+    }
+}

+ 1 - 1
core/src/main/java/org/springframework/security/core/codec/package-info.java → core/src/main/java/org/springframework/security/crypto/codec/package-info.java

@@ -1,4 +1,4 @@
 /**
  * Internal codec classes. Only intended for use within the framework.
  */
-package org.springframework.security.core.codec;
+package org.springframework.security.crypto.codec;

+ 9 - 8
core/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java

@@ -15,10 +15,10 @@
  */
 package org.springframework.security.crypto.encrypt;
 
-import static org.springframework.security.crypto.util.CipherUtils.doFinal;
-import static org.springframework.security.crypto.util.CipherUtils.initCipher;
-import static org.springframework.security.crypto.util.CipherUtils.newCipher;
-import static org.springframework.security.crypto.util.CipherUtils.newSecretKey;
+import static org.springframework.security.crypto.encrypt.CipherUtils.doFinal;
+import static org.springframework.security.crypto.encrypt.CipherUtils.initCipher;
+import static org.springframework.security.crypto.encrypt.CipherUtils.newCipher;
+import static org.springframework.security.crypto.encrypt.CipherUtils.newSecretKey;
 import static org.springframework.security.crypto.util.EncodingUtils.concatenate;
 import static org.springframework.security.crypto.util.EncodingUtils.subArray;
 
@@ -28,11 +28,12 @@ import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
+import org.springframework.security.crypto.codec.Hex;
 import org.springframework.security.crypto.keygen.BytesKeyGenerator;
-import org.springframework.security.crypto.util.EncodingUtils;
 
 /**
  * Encryptor that uses 256-bit AES encryption.
+ *
  * @author Keith Donald
  */
 final class AesBytesEncryptor implements BytesEncryptor {
@@ -45,8 +46,8 @@ final class AesBytesEncryptor implements BytesEncryptor {
 
     private final BytesKeyGenerator ivGenerator;
 
-    public AesBytesEncryptor(String password, String salt, BytesKeyGenerator ivGenerator) {
-        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), EncodingUtils.hexDecode(salt), 1024, 256);
+    public AesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
+        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);
         SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
         this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
         encryptor = newCipher(AES_ALGORITHM);
@@ -82,4 +83,4 @@ final class AesBytesEncryptor implements BytesEncryptor {
     }
 
     private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
-}
+}

+ 2 - 2
core/src/main/java/org/springframework/security/crypto/util/CipherUtils.java → core/src/main/java/org/springframework/security/crypto/encrypt/CipherUtils.java

@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.security.crypto.util;
+package org.springframework.security.crypto.encrypt;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -35,7 +35,7 @@ import javax.crypto.spec.PBEParameterSpec;
  * Static helper for working with the Cipher API.
  * @author Keith Donald
  */
-public class CipherUtils {
+class CipherUtils {
 
     /**
      * Generates a SecretKey.

+ 12 - 8
core/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java

@@ -20,6 +20,7 @@ import org.springframework.security.crypto.keygen.KeyGenerators;
 /**
  * Factory for commonly used encryptors.
  * Defines the public API for constructing {@link BytesEncryptor} and {@link TextEncryptor} implementations.
+ *
  * @author Keith Donald
  */
 public class Encryptors {
@@ -31,19 +32,21 @@ public class Encryptors {
      * The provided salt is expected to be hex-encoded; it should be random and at least 8 bytes in length.
      * Also applies a random 16 byte initialization vector to ensure each encrypted message will be unique.
      * Requires Java 6.
+     *
      * @param password the password used to generate the encryptor's secret key; should not be shared
-     * @param salt an hex-encoded, random, site-global salt value to use to generate the key
+     * @param salt a hex-encoded, random, site-global salt value to use to generate the key
      */
-    public static BytesEncryptor standard(String password, String salt) {
-        return new AesBytesEncryptor(password, password, KeyGenerators.secureRandom(16));
+    public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
+        return new AesBytesEncryptor(password.toString(), salt, KeyGenerators.secureRandom(16));
     }
 
     /**
      * Creates a text encryptor that uses standard password-based encryption.
      * Encrypted text is hex-encoded.
+     *
      * @param password the password used to generate the encryptor's secret key; should not be shared
      */
-    public static TextEncryptor text(String password, String salt) {
+    public static TextEncryptor text(CharSequence password, CharSequence salt) {
         return new HexEncodingTextEncryptor(standard(password, salt));
     }
 
@@ -52,11 +55,12 @@ public class Encryptors {
      * Uses a shared, or constant 16 byte initialization vector so encrypting the same data results in the same encryption result.
      * This is done to allow encrypted data to be queried against.
      * Encrypted text is hex-encoded.
+     *
      * @param password the password used to generate the encryptor's secret key; should not be shared
-     * @param salt an hex-encoded, random, site-global salt value to use to generate the secret key
+     * @param salt a hex-encoded, random, site-global salt value to use to generate the secret key
      */
-    public static TextEncryptor queryableText(String password, String salt) {
-        return new HexEncodingTextEncryptor(new AesBytesEncryptor(password, salt, KeyGenerators.shared(16)));
+    public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
+        return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(), salt, KeyGenerators.shared(16)));
     }
 
     /**
@@ -84,4 +88,4 @@ public class Encryptors {
 
     }
 
-}
+}

+ 4 - 6
core/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java

@@ -15,10 +15,8 @@
  */
 package org.springframework.security.crypto.encrypt;
 
-import static org.springframework.security.crypto.util.EncodingUtils.hexDecode;
-import static org.springframework.security.crypto.util.EncodingUtils.hexEncode;
-import static org.springframework.security.crypto.util.EncodingUtils.utf8Decode;
-import static org.springframework.security.crypto.util.EncodingUtils.utf8Encode;
+import org.springframework.security.crypto.codec.Hex;
+import org.springframework.security.crypto.codec.Utf8;
 
 /**
  * Delegates to an {@link BytesEncryptor} to encrypt text strings.
@@ -35,11 +33,11 @@ final class HexEncodingTextEncryptor implements TextEncryptor {
     }
 
     public String encrypt(String text) {
-        return hexEncode(encryptor.encrypt(utf8Encode(text)));
+        return new String(Hex.encode(encryptor.encrypt(Utf8.encode(text))));
     }
 
     public String decrypt(String encryptedText) {
-        return utf8Decode(encryptor.decrypt(hexDecode(encryptedText)));
+        return Utf8.decode(encryptor.decrypt(Hex.decode(encryptedText)));
     }
 
 }

+ 1 - 0
core/src/main/java/org/springframework/security/crypto/encrypt/TextEncryptor.java

@@ -17,6 +17,7 @@ package org.springframework.security.crypto.encrypt;
 
 /**
  * Service interface for symmetric encryption of text strings.
+ *
  * @author Keith Donald
  */
 public interface TextEncryptor {

+ 3 - 3
core/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java

@@ -15,7 +15,7 @@
  */
 package org.springframework.security.crypto.keygen;
 
-import static org.springframework.security.crypto.util.EncodingUtils.hexEncode;
+import org.springframework.security.crypto.codec.Hex;
 
 /**
  * A StringKeyGenerator that generates hex-encoded String keys.
@@ -31,7 +31,7 @@ final class HexEncodingStringKeyGenerator implements StringKeyGenerator {
     }
 
     public String generateKey() {
-        return hexEncode(keyGenerator.generateKey());
+        return new String(Hex.encode(keyGenerator.generateKey()));
     }
 
-}
+}

+ 3 - 3
core/src/main/java/org/springframework/security/crypto/util/Digester.java → core/src/main/java/org/springframework/security/crypto/password/Digester.java

@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.security.crypto.util;
+package org.springframework.security.crypto.password;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -24,7 +24,7 @@ import java.security.NoSuchProviderException;
  * Performs 1024 iterations of the hashing algorithm per digest to aid in protecting against brute force attacks.
  * @author Keith Donald
  */
-public class Digester {
+class Digester {
 
     private final MessageDigest messageDigest;
 
@@ -59,4 +59,4 @@ public class Digester {
         return messageDigest.digest(value);
     }
 
-}
+}

+ 5 - 5
core/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java

@@ -18,16 +18,17 @@ package org.springframework.security.crypto.password;
 /**
  * A password encoder that does nothing.
  * Useful for testing where working with plain text passwords may be preferred.
+ *
  * @author Keith Donald
  */
 public final class NoOpPasswordEncoder implements PasswordEncoder {
 
-    public String encode(String rawPassword) {
-        return rawPassword;
+    public String encode(CharSequence rawPassword) {
+        return rawPassword.toString();
     }
 
-    public boolean matches(String rawPassword, String encodedPassword) {
-        return rawPassword.equals(encodedPassword);
+    public boolean matches(CharSequence rawPassword, String encodedPassword) {
+        return rawPassword.toString().equals(encodedPassword);
     }
 
     /**
@@ -40,7 +41,6 @@ public final class NoOpPasswordEncoder implements PasswordEncoder {
     private static final PasswordEncoder INSTANCE = new NoOpPasswordEncoder();
 
     private NoOpPasswordEncoder() {
-
     }
 
 }

+ 5 - 3
core/src/main/java/org/springframework/security/crypto/password/PasswordEncoder.java

@@ -23,18 +23,20 @@ public interface PasswordEncoder {
 
     /**
      * Encode the raw password.
-     * Generally, a good encoding algorithm applies a SHA-1 or greater hash combined with a 8-byte or greater randomly generated salt.
+     * Generally, a good encoding algorithm applies a SHA-1 or greater hash combined with an 8-byte or greater randomly
+     * generated salt.
      */
-    String encode(String rawPassword);
+    String encode(CharSequence rawPassword);
 
     /**
      * Verify the encoded password obtained from storage matches the submitted raw password after it too is encoded.
      * Returns true if the passwords match, false if they do not.
      * The stored password itself is never decoded.
+     *
      * @param rawPassword the raw password to encode and match
      * @param encodedPassword the encoded password from storage to compare with
      * @return true if the raw password, after encoding, matches the encoded password from storage
      */
-    boolean matches(String rawPassword, String encodedPassword);
+    boolean matches(CharSequence rawPassword, String encodedPassword);
 
 }

+ 19 - 20
core/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java

@@ -16,17 +16,19 @@
 package org.springframework.security.crypto.password;
 
 import static org.springframework.security.crypto.util.EncodingUtils.concatenate;
-import static org.springframework.security.crypto.util.EncodingUtils.hexDecode;
-import static org.springframework.security.crypto.util.EncodingUtils.hexEncode;
 import static org.springframework.security.crypto.util.EncodingUtils.subArray;
-import static org.springframework.security.crypto.util.EncodingUtils.utf8Encode;
 
+import org.springframework.security.crypto.codec.Hex;
+import org.springframework.security.crypto.codec.Utf8;
 import org.springframework.security.crypto.keygen.BytesKeyGenerator;
 import org.springframework.security.crypto.keygen.KeyGenerators;
-import org.springframework.security.crypto.util.Digester;
 
 /**
- * A standard PasswordEncoder implementation that uses SHA-256 1024 iteration hashing with 8-byte random salting.
+ * A standard {@code PasswordEncoder} implementation that uses SHA-256 hashing with 1024 iterations and a
+ * random 8-byte random salt value. It uses an additional system-wide secret value to provide additional protection.
+ * <p>
+ * The digest algorithm is invoked on the concatenated bytes of the salt, secret and password.
+ *
  * @author Keith Donald
  */
 public final class StandardPasswordEncoder implements PasswordEncoder {
@@ -41,15 +43,15 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
      * Constructs a standard password encoder.
      * @param secret the secret key used in the encoding process (should not be shared)
      */
-    public StandardPasswordEncoder(String secret) {
+    public StandardPasswordEncoder(CharSequence secret) {
         this("SHA-256", "SUN", secret);
     }
 
-    public String encode(String rawPassword) {
+    public String encode(CharSequence rawPassword) {
         return encode(rawPassword, saltGenerator.generateKey());
     }
 
-    public boolean matches(String rawPassword, String encodedPassword) {
+    public boolean matches(CharSequence rawPassword, String encodedPassword) {
         byte[] digested = decode(encodedPassword);
         byte[] salt = subArray(digested, 0, saltGenerator.getKeyLength());
         return matches(digested, digest(rawPassword, salt));
@@ -57,31 +59,28 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
 
     // internal helpers
 
-    private StandardPasswordEncoder(String algorithm, String provider, String secret) {
+    private StandardPasswordEncoder(String algorithm, String provider, CharSequence secret) {
         this.digester = new Digester(algorithm, provider);
-        this.secret = utf8Encode(secret);
+        this.secret = Utf8.encode(secret);
         this.saltGenerator = KeyGenerators.secureRandom();
     }
 
-    private String encode(String rawPassword, byte[] salt) {
+    private String encode(CharSequence rawPassword, byte[] salt) {
         byte[] digest = digest(rawPassword, salt);
-        return hexEncode(digest);
+        return new String(Hex.encode(digest));
     }
 
-    private byte[] digest(String rawPassword, byte[] salt) {
-        byte[] digest = digester.digest(concatenate(salt, secret, utf8Encode(rawPassword)));
+    private byte[] digest(CharSequence rawPassword, byte[] salt) {
+        byte[] digest = digester.digest(concatenate(salt, secret, Utf8.encode(rawPassword)));
         return concatenate(salt, digest);
     }
 
-    private byte[] decode(String encodedPassword) {
-        return hexDecode(encodedPassword);
+    private byte[] decode(CharSequence encodedPassword) {
+        return Hex.decode(encodedPassword);
     }
 
     /**
      * Constant time comparison to prevent against timing attacks.
-     * @param expected
-     * @param actual
-     * @return
      */
     private boolean matches(byte[] expected, byte[] actual) {
         if (expected.length != actual.length) {
@@ -94,4 +93,4 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
         }
         return result == 0;
     }
-}
+}

+ 3 - 65
core/src/main/java/org/springframework/security/crypto/util/EncodingUtils.java

@@ -15,73 +15,15 @@
  */
 package org.springframework.security.crypto.util;
 
-import java.io.UnsupportedEncodingException;
-
 /**
  * Static helper for encoding data.
+ * <p>
+ * For internal use only.
+ *
  * @author Keith Donald
  */
 public class EncodingUtils {
 
-    /**
-     * Encode the byte array into a hex String.
-     */
-    public static String hexEncode(byte[] bytes) {
-        StringBuilder result = new StringBuilder();
-        char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-        for (int i = 0; i < bytes.length; ++i) {
-            byte b = bytes[i];
-            result.append(digits[(b & 0xf0) >> 4]);
-            result.append(digits[b & 0x0f]);
-        }
-        return result.toString();
-    }
-
-    /**
-     * Decode the hex String into a byte array.
-     */
-    public static byte[] hexDecode(String s) {
-        int len = s.length();
-        byte[] r = new byte[len / 2];
-        for (int i = 0; i < r.length; i++) {
-            int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
-            if ((digit1 >= '0') && (digit1 <= '9'))  {
-                digit1 -= '0';
-            } else if ((digit1 >= 'a') && (digit1 <= 'f')) {
-                digit1 -= 'a' - 10;
-            }
-            if ((digit2 >= '0') && (digit2 <= '9')) {
-                digit2 -= '0';
-            } else if ((digit2 >= 'a') && (digit2 <= 'f')) {
-                digit2 -= 'a' - 10;
-            }
-            r[i] = (byte) ((digit1 << 4) + digit2);
-        }
-        return r;
-    }
-
-    /**
-     * Get the bytes of the String in UTF-8 encoded form.
-     */
-    public static byte[] utf8Encode(String string) {
-        try {
-            return string.getBytes("UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw encodingException(e);
-        }
-    }
-
-    /**
-     * Decode the bytes in UTF-8 form into a String.
-     */
-    public static String utf8Decode(byte[] bytes) {
-        try {
-            return new String(bytes, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw encodingException(e);
-        }
-    }
-
     /**
      * Combine the individual byte arrays into one array.
      */
@@ -115,8 +57,4 @@ public class EncodingUtils {
     private EncodingUtils() {
     }
 
-    private static RuntimeException encodingException(UnsupportedEncodingException e) {
-        return new IllegalStateException("UTF-8 is not an available char set", e);
-    }
-
 }

+ 1 - 1
core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java

@@ -22,7 +22,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 

+ 2 - 2
core/src/test/java/org/springframework/security/crypto/encrypt/EncryptorsTests.java

@@ -10,9 +10,9 @@ import org.junit.Test;
 public class EncryptorsTests {
 
     @Test
-    public void standard() {
+    public void standard() throws Exception {
         BytesEncryptor encryptor = Encryptors.standard("password", "5c0744940b5c369b");
-        byte[] result = encryptor.encrypt("text".getBytes());
+        byte[] result = encryptor.encrypt("text".getBytes("UTF-8"));
         assertNotNull(result);
         assertFalse(new String(result).equals("text"));
         assertEquals("text", new String(encryptor.decrypt(result)));

+ 2 - 2
core/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java

@@ -6,7 +6,7 @@ import static org.junit.Assert.assertFalse;
 import java.util.Arrays;
 
 import org.junit.Test;
-import org.springframework.security.crypto.util.EncodingUtils;
+import org.springframework.security.crypto.codec.Hex;
 
 public class KeyGeneratorsTests {
 
@@ -35,7 +35,7 @@ public class KeyGeneratorsTests {
         StringKeyGenerator keyGenerator = KeyGenerators.string();
         String hexStringKey = keyGenerator.generateKey();
         assertEquals(16, hexStringKey.length());
-        assertEquals(8, EncodingUtils.hexDecode(hexStringKey).length);
+        assertEquals(8, Hex.decode(hexStringKey).length);
         String hexStringKey2 = keyGenerator.generateKey();
         assertFalse(hexStringKey.equals(hexStringKey2));
     }

+ 2 - 1
core/src/test/java/org/springframework/security/crypto/util/DigesterTests.java → core/src/test/java/org/springframework/security/crypto/password/DigesterTests.java

@@ -1,4 +1,4 @@
-package org.springframework.security.crypto.util;
+package org.springframework.security.crypto.password;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -7,6 +7,7 @@ import java.security.MessageDigest;
 import java.util.Arrays;
 
 import org.junit.Test;
+import org.springframework.security.crypto.password.Digester;
 
 public class DigesterTests {
 

+ 1 - 1
core/src/test/java/org/springframework/security/crypto/password/StandardPasswordEncoderTests.java

@@ -19,7 +19,7 @@ public class StandardPasswordEncoderTests {
     @Test
     public void matchesLengthChecked() {
         String result = encoder.encode("password");
-        assertFalse(encoder.matches("password", result.substring(0,result.length()-1)));
+        assertFalse(encoder.matches("password", result.substring(0,result.length()-2)));
     }
 
     @Test

+ 3 - 2
core/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java

@@ -6,20 +6,21 @@ import static org.junit.Assert.assertTrue;
 import java.util.Arrays;
 
 import org.junit.Test;
+import org.springframework.security.crypto.codec.Hex;
 
 public class EncodingUtilsTests {
 
     @Test
     public void hexEncode() {
         byte[] bytes = new byte[] { (byte)0x01, (byte)0xFF, (byte)65, (byte)66, (byte)67, (byte)0xC0, (byte)0xC1, (byte)0xC2 };
-        String result = EncodingUtils.hexEncode(bytes);
+        String result = new String(Hex.encode(bytes));
         assertEquals("01ff414243c0c1c2", result);
     }
 
     @Test
     public void hexDecode() {
         byte[] bytes = new byte[] { (byte)0x01, (byte)0xFF, (byte)65, (byte)66, (byte)67, (byte)0xC0, (byte)0xC1, (byte)0xC2 };
-        byte[] result = EncodingUtils.hexDecode("01ff414243c0c1c2");
+        byte[] result = Hex.decode("01ff414243c0c1c2");
         assertTrue(Arrays.equals(bytes, result));
     }
 

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java

@@ -16,7 +16,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.SpringSecurityMessageSource;
 import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
 import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsChecker;
 import org.springframework.security.core.userdetails.UserDetailsService;

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java

@@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.dao.DataAccessException;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.web.authentication.RememberMeServices;
 import org.springframework.util.Assert;

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java

@@ -16,7 +16,7 @@
 package org.springframework.security.web.authentication.rememberme;
 
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Hex;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.util.StringUtils;
 

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java

@@ -31,7 +31,7 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.authentication.NullRememberMeServices;

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java

@@ -7,7 +7,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.springframework.security.core.codec.Hex;
+import org.springframework.security.crypto.codec.Hex;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java

@@ -26,7 +26,7 @@ import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.core.Ordered;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.web.AuthenticationEntryPoint;
 
 

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java

@@ -37,7 +37,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.SpringSecurityMessageSource;
-import org.springframework.security.core.codec.Base64;
+import org.springframework.security.crypto.codec.Base64;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserCache;
 import org.springframework.security.core.userdetails.UserDetails;

+ 1 - 0
web/template.mf

@@ -19,6 +19,7 @@ Ignored-Existing-Headers:
 Import-Template:
  org.apache.commons.logging.*;version="${cloggingRange}",
  org.springframework.security.core.*;version="${secRange}",
+ org.springframework.security.crypto.*;version="${secRange}",
  org.springframework.security.authentication.*;version="${secRange}",
  org.springframework.security.access.*;version="${secRange}",
  org.springframework.security.util;version="${secRange}",