Browse Source

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.

pull/1/head
Luke Taylor 15 years ago
parent
commit
e470eaa41d
  1. 2
      core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java
  2. 4
      core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java
  3. 4
      core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java
  4. 4
      core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java
  5. 2
      core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java
  6. 14
      core/src/main/java/org/springframework/security/crypto/codec/Base64.java
  7. 26
      core/src/main/java/org/springframework/security/crypto/codec/Hex.java
  8. 39
      core/src/main/java/org/springframework/security/crypto/codec/Utf8.java
  9. 2
      core/src/main/java/org/springframework/security/crypto/codec/package-info.java
  10. 17
      core/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java
  11. 4
      core/src/main/java/org/springframework/security/crypto/encrypt/CipherUtils.java
  12. 20
      core/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
  13. 10
      core/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java
  14. 1
      core/src/main/java/org/springframework/security/crypto/encrypt/TextEncryptor.java
  15. 6
      core/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java
  16. 6
      core/src/main/java/org/springframework/security/crypto/password/Digester.java
  17. 10
      core/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
  18. 8
      core/src/main/java/org/springframework/security/crypto/password/PasswordEncoder.java
  19. 39
      core/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java
  20. 68
      core/src/main/java/org/springframework/security/crypto/util/EncodingUtils.java
  21. 2
      core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java
  22. 4
      core/src/test/java/org/springframework/security/crypto/encrypt/EncryptorsTests.java
  23. 4
      core/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java
  24. 3
      core/src/test/java/org/springframework/security/crypto/password/DigesterTests.java
  25. 2
      core/src/test/java/org/springframework/security/crypto/password/StandardPasswordEncoderTests.java
  26. 5
      core/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java
  27. 2
      web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java
  28. 2
      web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java
  29. 2
      web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java
  30. 2
      web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java
  31. 2
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java
  32. 2
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java
  33. 2
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java
  34. 1
      web/template.mf

2
core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java

@ -19,7 +19,7 @@ package org.springframework.security.authentication.encoding; @@ -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;

4
core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java

@ -16,8 +16,8 @@ package org.springframework.security.authentication.encoding; @@ -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.

4
core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java

@ -4,8 +4,8 @@ import java.io.UnsupportedEncodingException; @@ -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;
/**

4
core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java

@ -5,8 +5,8 @@ import java.security.SecureRandom; @@ -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;

2
core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java

@ -3,7 +3,7 @@ package org.springframework.security.core.token; @@ -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.

14
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 @@ @@ -1,4 +1,4 @@
package org.springframework.security.core.codec;
package org.springframework.security.crypto.codec;
/**
@ -33,14 +33,14 @@ public final class Base64 { @@ -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. */

26
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 @@ @@ -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 { @@ -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
core/src/main/java/org/springframework/security/crypto/codec/Utf8.java

@ -0,0 +1,39 @@ @@ -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);
}
}
}

2
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 @@ @@ -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;

17
core/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java

@ -15,10 +15,10 @@ @@ -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; @@ -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 { @@ -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 { @@ -82,4 +83,4 @@ final class AesBytesEncryptor implements BytesEncryptor {
}
private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
}
}

4
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 @@ @@ -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; @@ -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.

20
core/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java

@ -20,6 +20,7 @@ import org.springframework.security.crypto.keygen.KeyGenerators; @@ -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 { @@ -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 { @@ -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 { @@ -84,4 +88,4 @@ public class Encryptors {
}
}
}

10
core/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java

@ -15,10 +15,8 @@ @@ -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 { @@ -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
core/src/main/java/org/springframework/security/crypto/encrypt/TextEncryptor.java

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

6
core/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java

@ -15,7 +15,7 @@ @@ -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 { @@ -31,7 +31,7 @@ final class HexEncodingStringKeyGenerator implements StringKeyGenerator {
}
public String generateKey() {
return hexEncode(keyGenerator.generateKey());
return new String(Hex.encode(keyGenerator.generateKey()));
}
}
}

6
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 @@ @@ -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; @@ -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 { @@ -59,4 +59,4 @@ public class Digester {
return messageDigest.digest(value);
}
}
}

10
core/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java

@ -18,16 +18,17 @@ package org.springframework.security.crypto.password; @@ -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 { @@ -40,7 +41,6 @@ public final class NoOpPasswordEncoder implements PasswordEncoder {
private static final PasswordEncoder INSTANCE = new NoOpPasswordEncoder();
private NoOpPasswordEncoder() {
}
}

8
core/src/main/java/org/springframework/security/crypto/password/PasswordEncoder.java

@ -23,18 +23,20 @@ public interface PasswordEncoder { @@ -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);
}

39
core/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java

@ -16,17 +16,19 @@ @@ -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 { @@ -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 { @@ -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 { @@ -94,4 +93,4 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
}
return result == 0;
}
}
}

68
core/src/main/java/org/springframework/security/crypto/util/EncodingUtils.java

@ -15,73 +15,15 @@ @@ -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 { @@ -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);
}
}

2
core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java

@ -22,7 +22,7 @@ import org.apache.commons.logging.Log; @@ -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;

4
core/src/test/java/org/springframework/security/crypto/encrypt/EncryptorsTests.java

@ -10,9 +10,9 @@ import org.junit.Test; @@ -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)));

4
core/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java

@ -6,7 +6,7 @@ import static org.junit.Assert.assertFalse; @@ -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 { @@ -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));
}

3
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 @@ @@ -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; @@ -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 {

2
core/src/test/java/org/springframework/security/crypto/password/StandardPasswordEncoderTests.java

@ -19,7 +19,7 @@ public class StandardPasswordEncoderTests { @@ -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

5
core/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java

@ -6,20 +6,21 @@ import static org.junit.Assert.assertTrue; @@ -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));
}

2
web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java

@ -16,7 +16,7 @@ import org.springframework.security.core.Authentication; @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java

@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletResponse; @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java

@ -16,7 +16,7 @@ @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java

@ -31,7 +31,7 @@ import org.springframework.security.authentication.BadCredentialsException; @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java

@ -7,7 +7,7 @@ import java.util.HashMap; @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java

@ -26,7 +26,7 @@ import org.apache.commons.logging.LogFactory; @@ -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;

2
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java

@ -37,7 +37,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio @@ -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
web/template.mf

@ -19,6 +19,7 @@ Ignored-Existing-Headers: @@ -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}",

Loading…
Cancel
Save