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.

This commit is contained in:
Luke Taylor 2011-03-17 00:48:53 +00:00
parent 3a3b2df1c5
commit e470eaa41d
34 changed files with 162 additions and 159 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 * or at the very least should not be called Base64 without also specifying that is
* was encoded using the URL- and Filename-safe dialect. * 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: * 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>. * <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; public final static int ORDERED = 32;
/** Maximum line length (76) of Base64 output. */ /** Maximum line length (76) of Base64 output. */

View File

@ -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) * Hex data encoder. Converts byte arrays (such as those obtained from message digests)
@ -30,7 +30,25 @@ public final class Hex {
return result; 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;
}
} }

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ import org.springframework.security.crypto.keygen.KeyGenerators;
/** /**
* Factory for commonly used encryptors. * Factory for commonly used encryptors.
* Defines the public API for constructing {@link BytesEncryptor} and {@link TextEncryptor} implementations. * Defines the public API for constructing {@link BytesEncryptor} and {@link TextEncryptor} implementations.
*
* @author Keith Donald * @author Keith Donald
*/ */
public class Encryptors { 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. * 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. * Also applies a random 16 byte initialization vector to ensure each encrypted message will be unique.
* Requires Java 6. * Requires Java 6.
*
* @param password the password used to generate the encryptor's secret key; should not be shared * @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) { public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
return new AesBytesEncryptor(password, password, KeyGenerators.secureRandom(16)); return new AesBytesEncryptor(password.toString(), salt, KeyGenerators.secureRandom(16));
} }
/** /**
* Creates a text encryptor that uses standard password-based encryption. * Creates a text encryptor that uses standard password-based encryption.
* Encrypted text is hex-encoded. * Encrypted text is hex-encoded.
*
* @param password the password used to generate the encryptor's secret key; should not be shared * @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)); 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. * 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. * This is done to allow encrypted data to be queried against.
* Encrypted text is hex-encoded. * Encrypted text is hex-encoded.
*
* @param password the password used to generate the encryptor's secret key; should not be shared * @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) { public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password, salt, KeyGenerators.shared(16))); return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(), salt, KeyGenerators.shared(16)));
} }
/** /**

View File

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

View File

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

View File

@ -15,7 +15,7 @@
*/ */
package org.springframework.security.crypto.keygen; 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. * A StringKeyGenerator that generates hex-encoded String keys.
@ -31,7 +31,7 @@ final class HexEncodingStringKeyGenerator implements StringKeyGenerator {
} }
public String generateKey() { public String generateKey() {
return hexEncode(keyGenerator.generateKey()); return new String(Hex.encode(keyGenerator.generateKey()));
} }
} }

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.crypto.util; package org.springframework.security.crypto.password;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; 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. * Performs 1024 iterations of the hashing algorithm per digest to aid in protecting against brute force attacks.
* @author Keith Donald * @author Keith Donald
*/ */
public class Digester { class Digester {
private final MessageDigest messageDigest; private final MessageDigest messageDigest;

View File

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

View File

@ -23,18 +23,20 @@ public interface PasswordEncoder {
/** /**
* Encode the raw password. * 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. * 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. * Returns true if the passwords match, false if they do not.
* The stored password itself is never decoded. * The stored password itself is never decoded.
*
* @param rawPassword the raw password to encode and match * @param rawPassword the raw password to encode and match
* @param encodedPassword the encoded password from storage to compare with * @param encodedPassword the encoded password from storage to compare with
* @return true if the raw password, after encoding, matches the encoded password from storage * @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);
} }

View File

@ -16,17 +16,19 @@
package org.springframework.security.crypto.password; package org.springframework.security.crypto.password;
import static org.springframework.security.crypto.util.EncodingUtils.concatenate; 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.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.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators; 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 * @author Keith Donald
*/ */
public final class StandardPasswordEncoder implements PasswordEncoder { public final class StandardPasswordEncoder implements PasswordEncoder {
@ -41,15 +43,15 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
* Constructs a standard password encoder. * Constructs a standard password encoder.
* @param secret the secret key used in the encoding process (should not be shared) * @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); this("SHA-256", "SUN", secret);
} }
public String encode(String rawPassword) { public String encode(CharSequence rawPassword) {
return encode(rawPassword, saltGenerator.generateKey()); return encode(rawPassword, saltGenerator.generateKey());
} }
public boolean matches(String rawPassword, String encodedPassword) { public boolean matches(CharSequence rawPassword, String encodedPassword) {
byte[] digested = decode(encodedPassword); byte[] digested = decode(encodedPassword);
byte[] salt = subArray(digested, 0, saltGenerator.getKeyLength()); byte[] salt = subArray(digested, 0, saltGenerator.getKeyLength());
return matches(digested, digest(rawPassword, salt)); return matches(digested, digest(rawPassword, salt));
@ -57,31 +59,28 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
// internal helpers // 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.digester = new Digester(algorithm, provider);
this.secret = utf8Encode(secret); this.secret = Utf8.encode(secret);
this.saltGenerator = KeyGenerators.secureRandom(); this.saltGenerator = KeyGenerators.secureRandom();
} }
private String encode(String rawPassword, byte[] salt) { private String encode(CharSequence rawPassword, byte[] salt) {
byte[] digest = digest(rawPassword, salt); byte[] digest = digest(rawPassword, salt);
return hexEncode(digest); return new String(Hex.encode(digest));
} }
private byte[] digest(String rawPassword, byte[] salt) { private byte[] digest(CharSequence rawPassword, byte[] salt) {
byte[] digest = digester.digest(concatenate(salt, secret, utf8Encode(rawPassword))); byte[] digest = digester.digest(concatenate(salt, secret, Utf8.encode(rawPassword)));
return concatenate(salt, digest); return concatenate(salt, digest);
} }
private byte[] decode(String encodedPassword) { private byte[] decode(CharSequence encodedPassword) {
return hexDecode(encodedPassword); return Hex.decode(encodedPassword);
} }
/** /**
* Constant time comparison to prevent against timing attacks. * Constant time comparison to prevent against timing attacks.
* @param expected
* @param actual
* @return
*/ */
private boolean matches(byte[] expected, byte[] actual) { private boolean matches(byte[] expected, byte[] actual) {
if (expected.length != actual.length) { if (expected.length != actual.length) {

View File

@ -15,73 +15,15 @@
*/ */
package org.springframework.security.crypto.util; package org.springframework.security.crypto.util;
import java.io.UnsupportedEncodingException;
/** /**
* Static helper for encoding data. * Static helper for encoding data.
* <p>
* For internal use only.
*
* @author Keith Donald * @author Keith Donald
*/ */
public class EncodingUtils { 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. * Combine the individual byte arrays into one array.
*/ */
@ -115,8 +57,4 @@ public class EncodingUtils {
private EncodingUtils() { private EncodingUtils() {
} }
private static RuntimeException encodingException(UnsupportedEncodingException e) {
return new IllegalStateException("UTF-8 is not an available char set", e);
}
} }

View File

@ -22,7 +22,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor; import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;
import org.springframework.security.core.Authentication; 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; import org.springframework.security.core.context.SecurityContextHolder;

View File

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

View File

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

View File

@ -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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@ -7,6 +7,7 @@ import java.security.MessageDigest;
import java.util.Arrays; import java.util.Arrays;
import org.junit.Test; import org.junit.Test;
import org.springframework.security.crypto.password.Digester;
public class DigesterTests { public class DigesterTests {

View File

@ -19,7 +19,7 @@ public class StandardPasswordEncoderTests {
@Test @Test
public void matchesLengthChecked() { public void matchesLengthChecked() {
String result = encoder.encode("password"); 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 @Test

View File

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

View File

@ -16,7 +16,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; 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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsChecker; import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;

View File

@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.security.core.Authentication; 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.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.util.Assert; import org.springframework.util.Assert;

View File

@ -16,7 +16,7 @@
package org.springframework.security.web.authentication.rememberme; package org.springframework.security.web.authentication.rememberme;
import org.springframework.security.core.Authentication; 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.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;

View File

@ -31,7 +31,7 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; 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.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.NullRememberMeServices; import org.springframework.security.web.authentication.NullRememberMeServices;

View File

@ -7,7 +7,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;

View File

@ -26,7 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.security.core.AuthenticationException; 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; import org.springframework.security.web.AuthenticationEntryPoint;

View File

@ -37,7 +37,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource; 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.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;

View File

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