29 changed files with 1254 additions and 1 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
// crypto module build file |
||||
|
||||
dependencies { |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.encrypt; |
||||
|
||||
/** |
||||
* Service interface for symmetric data encryption. |
||||
* @author Keith Donald |
||||
*/ |
||||
public interface BytesEncryptor { |
||||
|
||||
/** |
||||
* Encrypt the byte array. |
||||
*/ |
||||
byte[] encrypt(byte[] byteArray); |
||||
|
||||
/** |
||||
* Decrypt the byte array. |
||||
*/ |
||||
byte[] decrypt(byte[] encryptedByteArray); |
||||
|
||||
} |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.encrypt; |
||||
|
||||
/** |
||||
* Factory for commonly used encryptors. |
||||
* Defines the public API for constructing {@link BytesEncryptor} and {@link TextEncryptor} implementations. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class Encryptors { |
||||
|
||||
/** |
||||
* Creates a standard password-based bytes encryptor. |
||||
* Uses MD5 PRF hashing with 1024 iterations and DES-based encryption. |
||||
* Salts each encrypted value to ensure it will be unique. |
||||
* TODO - switch standard algorithm from DES to AES. Switch hashing to SHA-1 from MD5. |
||||
* @param password the password used to generate the encryptor's secret key; should not be shared |
||||
*/ |
||||
public static BytesEncryptor standard(String password) { |
||||
return new PasswordBasedBytesEncryptor(PBE_MD5_DES_ALGORITHM, password); |
||||
} |
||||
|
||||
/** |
||||
* 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) { |
||||
return new HexEncodingTextEncryptor(standard(password)); |
||||
} |
||||
|
||||
/** |
||||
* Creates an encryptor for queryable text strings that uses standard password-based encryption. |
||||
* The hex-encoded salt string provided should be random and is used to protect against password dictionary attacks. |
||||
* Does not salt each encrypted value so an encrypted value may 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 initialize the cipher |
||||
*/ |
||||
public static TextEncryptor queryableText(String password, String salt) { |
||||
return new QueryableTextEncryptor(PBE_MD5_DES_ALGORITHM, password, salt); |
||||
} |
||||
|
||||
/** |
||||
* Creates a text encrypter that performs no encryption. |
||||
* Useful for test environments where working with plain text strings is desired for simplicity. |
||||
*/ |
||||
public static TextEncryptor noOpText() { |
||||
return NO_OP_TEXT_INSTANCE; |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private Encryptors() { |
||||
} |
||||
|
||||
private static final String PBE_MD5_DES_ALGORITHM = "PBEWithMD5AndDES"; |
||||
|
||||
private static final TextEncryptor NO_OP_TEXT_INSTANCE = new NoOpTextEncryptor(); |
||||
|
||||
private static final class NoOpTextEncryptor implements TextEncryptor { |
||||
|
||||
public String encrypt(String text) { |
||||
return text; |
||||
} |
||||
|
||||
public String decrypt(String encryptedText) { |
||||
return encryptedText; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.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; |
||||
|
||||
/** |
||||
* Delegates to an {@link BytesEncryptor} to encrypt text strings. |
||||
* Raw text strings are UTF-8 encoded before being passed to the encryptor. |
||||
* Encrypted strings are returned hex-encoded. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class HexEncodingTextEncryptor implements TextEncryptor { |
||||
|
||||
private final BytesEncryptor encryptor; |
||||
|
||||
public HexEncodingTextEncryptor(BytesEncryptor encryptor) { |
||||
this.encryptor = encryptor; |
||||
} |
||||
|
||||
public String encrypt(String text) { |
||||
return hexEncode(encryptor.encrypt(utf8Encode(text))); |
||||
} |
||||
|
||||
public String decrypt(String encryptedText) { |
||||
return utf8Decode(encryptor.decrypt(hexDecode(encryptedText))); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.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.util.EncodingUtils.concatenate; |
||||
import static org.springframework.security.crypto.util.EncodingUtils.subArray; |
||||
|
||||
import javax.crypto.Cipher; |
||||
import javax.crypto.SecretKey; |
||||
|
||||
import org.springframework.security.crypto.keygen.BytesKeyGenerator; |
||||
import org.springframework.security.crypto.keygen.KeyGenerators; |
||||
|
||||
/** |
||||
* A general purpose encryptor for password-based encryption (PBEwith{prf}and{encryption} algorithms). |
||||
* Prepends a random salt to each encrypted value to aid in the prevention of password compromise with the aid of a dictionary/rainbow table. |
||||
* The salt allows the same secret key to be used for multiple encryption operations. |
||||
* The password should be not be shared. |
||||
* Note: {prf} = Pseudo random function e.g. MD5; {encryption} = Encryption method e.g. DES or AES. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class PasswordBasedBytesEncryptor implements BytesEncryptor { |
||||
|
||||
private final SecretKey secretKey; |
||||
|
||||
private final BytesKeyGenerator saltGenerator; |
||||
|
||||
private final Cipher encryptor; |
||||
|
||||
private final Cipher decryptor; |
||||
|
||||
public PasswordBasedBytesEncryptor(String algorithm, String password) { |
||||
secretKey = newSecretKey(algorithm, password); |
||||
saltGenerator = KeyGenerators.secureRandom(); |
||||
encryptor = newCipher(algorithm); |
||||
decryptor = newCipher(algorithm); |
||||
} |
||||
|
||||
public byte[] encrypt(byte[] bytes) { |
||||
byte[] salt = saltGenerator.generateKey(); |
||||
byte[] encrypted; |
||||
synchronized (encryptor) { |
||||
initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, salt, 1024); |
||||
encrypted = doFinal(encryptor, bytes); |
||||
} |
||||
return concatenate(salt, encrypted); |
||||
} |
||||
|
||||
public byte[] decrypt(byte[] encryptedBytes) { |
||||
byte[] salt = saltPart(encryptedBytes); |
||||
byte[] decrypted; |
||||
synchronized (decryptor) { |
||||
initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, salt, 1024); |
||||
decrypted = doFinal(decryptor, cipherPart(encryptedBytes, salt)); |
||||
} |
||||
return decrypted; |
||||
} |
||||
|
||||
private byte[] saltPart(byte[] encrypted) { |
||||
return subArray(encrypted, 0, saltGenerator.getKeyLength()); |
||||
} |
||||
|
||||
private byte[] cipherPart(byte[] encrypted, byte[] salt) { |
||||
return subArray(encrypted, salt.length, encrypted.length); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.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.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 javax.crypto.Cipher; |
||||
import javax.crypto.SecretKey; |
||||
|
||||
/** |
||||
* A text encryptor that applies password-based MD5 plus DES symmetric key encryption. |
||||
* Designed to be used to encrypt fields that are queryable; for example, an indexed field such as an OAuth apiKey. |
||||
* Requires a random site-global salt to protect against password dictionary attacks. |
||||
* Does not salt on each {@link #encrypt(String)} operation to allow the encrypted field to be queried. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class QueryableTextEncryptor implements TextEncryptor { |
||||
|
||||
private final Cipher encryptor; |
||||
|
||||
private final Cipher decryptor; |
||||
|
||||
public QueryableTextEncryptor(String algorithm, String password, String salt) { |
||||
byte[] saltBytes = hexDecode(salt); |
||||
SecretKey secretKey = newSecretKey(algorithm, password); |
||||
encryptor = newCipher(algorithm); |
||||
initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, saltBytes, 1000); |
||||
decryptor = newCipher(algorithm); |
||||
initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, saltBytes, 1000); |
||||
} |
||||
|
||||
public String encrypt(String text) { |
||||
return hexEncode(doFinal(encryptor, utf8Encode(text))); |
||||
} |
||||
|
||||
public String decrypt(String encryptedText) { |
||||
return utf8Decode(doFinal(decryptor, hexDecode(encryptedText))); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.encrypt; |
||||
|
||||
/** |
||||
* Service interface for symmetric encryption of text strings. |
||||
* @author Keith Donald |
||||
*/ |
||||
public interface TextEncryptor { |
||||
|
||||
/** |
||||
* Encrypt the raw text string. |
||||
*/ |
||||
String encrypt(String text); |
||||
|
||||
/** |
||||
* Decrypt the encrypted text string. |
||||
*/ |
||||
String decrypt(String encryptedText); |
||||
|
||||
} |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
/** |
||||
* Symmetric-key data encryption. |
||||
*/ |
||||
package org.springframework.security.crypto.encrypt; |
||||
|
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
/** |
||||
* A generator for unique byte array-based keys. |
||||
* @author Keith Donald |
||||
*/ |
||||
public interface BytesKeyGenerator { |
||||
|
||||
/** |
||||
* Get the length, in bytes, of keys created by this generator. |
||||
* Most unique keys are at least 8 bytes in length. |
||||
*/ |
||||
int getKeyLength(); |
||||
|
||||
/** |
||||
* Generate a new key. |
||||
*/ |
||||
byte[] generateKey(); |
||||
|
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
import static org.springframework.security.crypto.util.EncodingUtils.hexEncode; |
||||
|
||||
/** |
||||
* A StringKeyGenerator that generates hex-encoded String keys. |
||||
* Delegates to a {@link BytesKeyGenerator} for the actual key generation. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class HexEncodingStringKeyGenerator implements StringKeyGenerator { |
||||
|
||||
private final BytesKeyGenerator keyGenerator; |
||||
|
||||
public HexEncodingStringKeyGenerator(BytesKeyGenerator keyGenerator) { |
||||
this.keyGenerator = keyGenerator; |
||||
} |
||||
|
||||
public String generateKey() { |
||||
return hexEncode(keyGenerator.generateKey()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
import java.security.SecureRandom; |
||||
|
||||
/** |
||||
* Factory for commonly used key generators. |
||||
* Public API for constructing a {@link BytesKeyGenerator} or {@link StringKeyGenerator}. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class KeyGenerators { |
||||
|
||||
/** |
||||
* Create a {@link BytesKeyGenerator} that uses a {@link SecureRandom} to generate keys of 8 bytes in length. |
||||
*/ |
||||
public static BytesKeyGenerator secureRandom() { |
||||
return new SecureRandomBytesKeyGenerator(); |
||||
} |
||||
|
||||
/** |
||||
* Create a {@link BytesKeyGenerator} that uses a {@link SecureRandom} to generate keys of a custom length. |
||||
* @param keyLength the key length in bytes, e.g. 16, for a 16 byte key. |
||||
*/ |
||||
public static BytesKeyGenerator secureRandom(int keyLength) { |
||||
return new SecureRandomBytesKeyGenerator(keyLength); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link StringKeyGenerator} that hex-encodes {@link SecureRandom} keys of 8 bytes in length. |
||||
* The hex-encoded string is keyLength * 2 characters in length. |
||||
*/ |
||||
public static StringKeyGenerator string() { |
||||
return new HexEncodingStringKeyGenerator(secureRandom()); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private KeyGenerators() { |
||||
} |
||||
} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
import java.security.NoSuchAlgorithmException; |
||||
import java.security.NoSuchProviderException; |
||||
import java.security.SecureRandom; |
||||
|
||||
/** |
||||
* A KeyGenerator that uses SecureRandom to generate byte array-based keys. |
||||
* Defaults to 8 byte keys produced by the SHA1PRNG algorithm developed by the Sun Provider. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class SecureRandomBytesKeyGenerator implements BytesKeyGenerator { |
||||
|
||||
private final SecureRandom random; |
||||
|
||||
private final int keyLength; |
||||
|
||||
/** |
||||
* Creates a secure random key generator using the defaults. |
||||
*/ |
||||
public SecureRandomBytesKeyGenerator() { |
||||
this(DEFAULT_ALGORITHM, DEFAULT_PROVIDER, DEFAULT_KEY_LENGTH); |
||||
} |
||||
|
||||
/** |
||||
* Creates a secure random key generator with a custom key length. |
||||
*/ |
||||
public SecureRandomBytesKeyGenerator(int keyLength) { |
||||
this(DEFAULT_ALGORITHM, DEFAULT_PROVIDER, keyLength); |
||||
} |
||||
|
||||
public int getKeyLength() { |
||||
return keyLength; |
||||
} |
||||
|
||||
public byte[] generateKey() { |
||||
byte[] bytes = new byte[keyLength]; |
||||
random.nextBytes(bytes); |
||||
return bytes; |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
/** |
||||
* Creates a secure random key generator that is fully customized. |
||||
*/ |
||||
private SecureRandomBytesKeyGenerator(String algorithm, String provider, int keyLength) { |
||||
this.random = createSecureRandom(algorithm, provider, keyLength); |
||||
this.keyLength = keyLength; |
||||
} |
||||
|
||||
private SecureRandom createSecureRandom(String algorithm, String provider, int keyLength) { |
||||
try { |
||||
SecureRandom random = SecureRandom.getInstance(algorithm, provider); |
||||
random.setSeed(random.generateSeed(keyLength)); |
||||
return random; |
||||
} catch (NoSuchAlgorithmException e) { |
||||
throw new IllegalArgumentException("Not a supported SecureRandom key generation algorithm", e); |
||||
} catch (NoSuchProviderException e) { |
||||
throw new IllegalArgumentException("Not a supported SecureRandom key provider", e); |
||||
} |
||||
} |
||||
|
||||
private static final String DEFAULT_ALGORITHM = "SHA1PRNG"; |
||||
|
||||
private static final String DEFAULT_PROVIDER = "SUN"; |
||||
|
||||
private static final int DEFAULT_KEY_LENGTH = 8; |
||||
|
||||
} |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
/** |
||||
* A generator for unique string keys. |
||||
* @author Keith Donald |
||||
*/ |
||||
public interface StringKeyGenerator { |
||||
|
||||
String generateKey(); |
||||
|
||||
} |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
/** |
||||
* Secure random key generators. |
||||
*/ |
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
|
||||
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.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 boolean matches(String rawPassword, String encodedPassword) { |
||||
return rawPassword.equals(encodedPassword); |
||||
} |
||||
|
||||
/** |
||||
* Get the singleton {@link NoOpPasswordEncoder}. |
||||
*/ |
||||
public static PasswordEncoder getInstance() { |
||||
return INSTANCE; |
||||
} |
||||
|
||||
private static final PasswordEncoder INSTANCE = new NoOpPasswordEncoder(); |
||||
|
||||
private NoOpPasswordEncoder() { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.password; |
||||
|
||||
/** |
||||
* Service interface for encoding passwords. |
||||
* @author Keith Donald |
||||
*/ |
||||
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. |
||||
*/ |
||||
String encode(String 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); |
||||
|
||||
} |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.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 java.util.Arrays; |
||||
|
||||
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. |
||||
* @author Keith Donald |
||||
*/ |
||||
public final class StandardPasswordEncoder implements PasswordEncoder { |
||||
|
||||
private final Digester digester; |
||||
|
||||
private final byte[] secret; |
||||
|
||||
private final BytesKeyGenerator saltGenerator; |
||||
|
||||
/** |
||||
* Constructs a standard password encoder. |
||||
* @param secret the secret key used in the encoding process (should not be shared) |
||||
*/ |
||||
public StandardPasswordEncoder(String secret) { |
||||
this("SHA-256", "SUN", secret); |
||||
} |
||||
|
||||
public String encode(String rawPassword) { |
||||
return encode(rawPassword, saltGenerator.generateKey()); |
||||
} |
||||
|
||||
public boolean matches(String rawPassword, String encodedPassword) { |
||||
byte[] digested = decode(encodedPassword); |
||||
byte[] salt = subArray(digested, 0, saltGenerator.getKeyLength()); |
||||
return matches(digested, digest(rawPassword, salt)); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private StandardPasswordEncoder(String algorithm, String provider, String secret) { |
||||
this.digester = new Digester(algorithm, provider); |
||||
this.secret = utf8Encode(secret); |
||||
this.saltGenerator = KeyGenerators.secureRandom(); |
||||
} |
||||
|
||||
private String encode(String rawPassword, byte[] salt) { |
||||
byte[] digest = digest(rawPassword, salt); |
||||
return hexEncode(digest); |
||||
} |
||||
|
||||
private byte[] digest(String rawPassword, byte[] salt) { |
||||
byte[] digest = digester.digest(concatenate(salt, secret, utf8Encode(rawPassword))); |
||||
return concatenate(salt, digest); |
||||
} |
||||
|
||||
private byte[] decode(String encodedPassword) { |
||||
return hexDecode(encodedPassword); |
||||
} |
||||
|
||||
private boolean matches(byte[] expected, byte[] actual) { |
||||
return Arrays.equals(expected, actual); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
/** |
||||
* Password encoders. |
||||
*/ |
||||
package org.springframework.security.crypto.password; |
||||
|
||||
@ -0,0 +1,95 @@
@@ -0,0 +1,95 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.util; |
||||
|
||||
import java.security.InvalidAlgorithmParameterException; |
||||
import java.security.InvalidKeyException; |
||||
import java.security.NoSuchAlgorithmException; |
||||
import java.security.spec.InvalidKeySpecException; |
||||
|
||||
import javax.crypto.BadPaddingException; |
||||
import javax.crypto.Cipher; |
||||
import javax.crypto.IllegalBlockSizeException; |
||||
import javax.crypto.NoSuchPaddingException; |
||||
import javax.crypto.SecretKey; |
||||
import javax.crypto.SecretKeyFactory; |
||||
import javax.crypto.spec.PBEKeySpec; |
||||
import javax.crypto.spec.PBEParameterSpec; |
||||
|
||||
/** |
||||
* Static helper for working with the Cipher API. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class CipherUtils { |
||||
|
||||
/** |
||||
* Generates a SecretKey. |
||||
*/ |
||||
public static SecretKey newSecretKey(String algorithm, String secret) { |
||||
try { |
||||
PBEKeySpec pbeKeySpec = new PBEKeySpec(secret.toCharArray()); |
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm); |
||||
return factory.generateSecret(pbeKeySpec); |
||||
} catch (NoSuchAlgorithmException e) { |
||||
throw new IllegalArgumentException("Not a valid encryption algorithm", e); |
||||
} catch (InvalidKeySpecException e) { |
||||
throw new IllegalArgumentException("Not a valid secert key", e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new Cipher. |
||||
*/ |
||||
public static Cipher newCipher(String algorithm) { |
||||
try { |
||||
return Cipher.getInstance(algorithm); |
||||
} catch (NoSuchAlgorithmException e) { |
||||
throw new IllegalArgumentException("Not a valid encryption algorithm", e); |
||||
} catch (NoSuchPaddingException e) { |
||||
throw new IllegalStateException("Should not happen", e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Initializes the Cipher for use. |
||||
*/ |
||||
public static void initCipher(Cipher cipher, int mode, SecretKey secretKey, byte[] salt, int iterationCount) { |
||||
try { |
||||
cipher.init(mode, secretKey, new PBEParameterSpec(salt, iterationCount)); |
||||
} catch (InvalidKeyException e) { |
||||
throw new IllegalArgumentException("Unable to initialize due to invalid secret key", e); |
||||
} catch (InvalidAlgorithmParameterException e) { |
||||
throw new IllegalStateException("Unable to initialize due to invalid decryption parameter spec", e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Invokes the Cipher to perform encryption or decryption (depending on the initialized mode). |
||||
*/ |
||||
public static byte[] doFinal(Cipher cipher, byte[] input) { |
||||
try { |
||||
return cipher.doFinal(input); |
||||
} catch (IllegalBlockSizeException e) { |
||||
throw new IllegalStateException("Unable to invoke Cipher due to illegal block size", e); |
||||
} catch (BadPaddingException e) { |
||||
throw new IllegalStateException("Unable to invoke Cipher due to bad padding", e); |
||||
} |
||||
} |
||||
|
||||
private CipherUtils() { |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.util; |
||||
|
||||
import java.security.MessageDigest; |
||||
import java.security.NoSuchAlgorithmException; |
||||
import java.security.NoSuchProviderException; |
||||
|
||||
/** |
||||
* Helper for working with the MessageDigest API. |
||||
* Performs 1024 iterations of the hashing algorithm per digest to aid in protecting against brute force attacks. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class Digester { |
||||
|
||||
private final MessageDigest messageDigest; |
||||
|
||||
private final int iterations = 1024; |
||||
|
||||
/** |
||||
* Create a new Digester. |
||||
* @param algorithm the digest algorithm; for example, "SHA-1" or "SHA-256". |
||||
* @param provider the provider of the digest algorithm, for example "SUN". |
||||
*/ |
||||
public Digester(String algorithm, String provider) { |
||||
try { |
||||
messageDigest = MessageDigest.getInstance(algorithm, provider); |
||||
} catch (NoSuchAlgorithmException e) { |
||||
throw new IllegalStateException("No such hashing algorithm", e); |
||||
} catch (NoSuchProviderException e) { |
||||
throw new IllegalStateException("No such provider for hashing algorithm", e); |
||||
} |
||||
} |
||||
|
||||
public byte[] digest(byte[] value) { |
||||
synchronized (messageDigest) { |
||||
for (int i = 0; i < (iterations - 1); i++) { |
||||
invokeDigest(value); |
||||
} |
||||
return messageDigest.digest(value); |
||||
} |
||||
} |
||||
|
||||
private byte[] invokeDigest(byte[] value) { |
||||
messageDigest.reset(); |
||||
return messageDigest.digest(value); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.security.crypto.util; |
||||
|
||||
import java.io.UnsupportedEncodingException; |
||||
|
||||
/** |
||||
* Static helper for encoding data. |
||||
* @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. |
||||
*/ |
||||
public static byte[] concatenate(byte[]... arrays) { |
||||
int length = 0; |
||||
for (byte[] array : arrays) { |
||||
length += array.length; |
||||
} |
||||
byte[] newArray = new byte[length]; |
||||
int destPos = 0; |
||||
for (byte[] array : arrays) { |
||||
System.arraycopy(array, 0, newArray, destPos, array.length); |
||||
destPos += array.length; |
||||
} |
||||
return newArray; |
||||
} |
||||
|
||||
/** |
||||
* Extract a sub array of bytes out of the byte array. |
||||
* @param array the byte array to extract from |
||||
* @param beginIndex the beginning index of the sub array, inclusive |
||||
* @param endIndex the ending index of the sub array, exclusive |
||||
*/ |
||||
public static byte[] subArray(byte[] array, int beginIndex, int endIndex) { |
||||
int length = endIndex - beginIndex; |
||||
byte[] subarray = new byte[length]; |
||||
System.arraycopy(array, beginIndex, subarray, 0, length); |
||||
return subarray; |
||||
} |
||||
|
||||
private EncodingUtils() { |
||||
} |
||||
|
||||
private static RuntimeException encodingException(UnsupportedEncodingException e) { |
||||
return new IllegalStateException("UTF-8 is not an available char set", e); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
/** |
||||
* Shared crypto utilities. |
||||
*/ |
||||
package org.springframework.security.crypto.util; |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
package org.springframework.security.crypto.encrypt; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertNotNull; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class EncryptorsTests { |
||||
|
||||
@Test |
||||
public void standard() { |
||||
BytesEncryptor encryptor = Encryptors.standard("password"); |
||||
byte[] result = encryptor.encrypt("text".getBytes()); |
||||
assertNotNull(result); |
||||
assertFalse(new String(result).equals("text")); |
||||
assertEquals("text", new String(encryptor.decrypt(result))); |
||||
assertFalse(new String(result).equals(new String(encryptor.encrypt("text".getBytes())))); |
||||
} |
||||
|
||||
@Test |
||||
public void text() { |
||||
TextEncryptor encryptor = Encryptors.text("password"); |
||||
String result = encryptor.encrypt("text"); |
||||
assertNotNull(result); |
||||
assertFalse(result.equals("text")); |
||||
assertEquals("text", encryptor.decrypt(result)); |
||||
assertFalse(result.equals(encryptor.encrypt("text"))); |
||||
} |
||||
|
||||
@Test |
||||
public void queryableText() { |
||||
TextEncryptor encryptor = Encryptors.queryableText("password", "5c0744940b5c369b"); |
||||
String result = encryptor.encrypt("text"); |
||||
assertNotNull(result); |
||||
assertFalse(result.equals("text")); |
||||
assertEquals("text", encryptor.decrypt(result)); |
||||
assertTrue(result.equals(encryptor.encrypt("text"))); |
||||
} |
||||
|
||||
@Test |
||||
public void noOpText() { |
||||
TextEncryptor encryptor = Encryptors.noOpText(); |
||||
assertEquals("text", encryptor.encrypt("text")); |
||||
assertEquals("text", encryptor.decrypt("text")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
package org.springframework.security.crypto.keygen; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.security.crypto.util.EncodingUtils; |
||||
|
||||
public class KeyGeneratorsTests { |
||||
|
||||
@Test |
||||
public void secureRandom() { |
||||
BytesKeyGenerator keyGenerator = KeyGenerators.secureRandom(); |
||||
assertEquals(8, keyGenerator.getKeyLength()); |
||||
byte[] key = keyGenerator.generateKey(); |
||||
assertEquals(8, key.length); |
||||
byte[] key2 = keyGenerator.generateKey(); |
||||
assertFalse(Arrays.equals(key, key2)); |
||||
} |
||||
|
||||
@Test |
||||
public void secureRandomCustomLength() { |
||||
BytesKeyGenerator keyGenerator = KeyGenerators.secureRandom(16); |
||||
assertEquals(16, keyGenerator.getKeyLength()); |
||||
byte[] key = keyGenerator.generateKey(); |
||||
assertEquals(16, key.length); |
||||
byte[] key2 = keyGenerator.generateKey(); |
||||
assertFalse(Arrays.equals(key, key2)); |
||||
} |
||||
|
||||
@Test |
||||
public void string() { |
||||
StringKeyGenerator keyGenerator = KeyGenerators.string(); |
||||
String hexStringKey = keyGenerator.generateKey(); |
||||
assertEquals(16, hexStringKey.length()); |
||||
assertEquals(8, EncodingUtils.hexDecode(hexStringKey).length); |
||||
String hexStringKey2 = keyGenerator.generateKey(); |
||||
assertFalse(hexStringKey.equals(hexStringKey2)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
package org.springframework.security.crypto.password; |
||||
|
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class StandardPasswordEncoderTests { |
||||
|
||||
private StandardPasswordEncoder encoder = new StandardPasswordEncoder("secret"); |
||||
|
||||
@Test |
||||
public void matches() { |
||||
String result = encoder.encode("password"); |
||||
assertFalse(result.equals("password")); |
||||
assertTrue(encoder.matches("password", result)); |
||||
} |
||||
|
||||
@Test |
||||
public void notMatches() { |
||||
String result = encoder.encode("password"); |
||||
assertFalse(encoder.matches("bogus", result)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
package org.springframework.security.crypto.util; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class DigesterTests { |
||||
|
||||
private Digester digester = new Digester("SHA-1", "SUN"); |
||||
|
||||
@Test |
||||
public void digest() { |
||||
byte[] result = digester.digest("text".getBytes()); |
||||
assertEquals(20, result.length); |
||||
assertFalse(new String(result).equals("text")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
package org.springframework.security.crypto.util; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
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); |
||||
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"); |
||||
assertTrue(Arrays.equals(bytes, result)); |
||||
} |
||||
|
||||
@Test |
||||
public void concatenate() { |
||||
byte[] bytes = new byte[] { (byte)0x01, (byte)0xFF, (byte)65, (byte)66, (byte)67, (byte)0xC0, (byte)0xC1, (byte)0xC2 }; |
||||
byte[] one = new byte[] { (byte)0x01 }; |
||||
byte[] two = new byte[] { (byte)0xFF, (byte)65, (byte)66 }; |
||||
byte[] three = new byte[] { (byte)67, (byte)0xC0, (byte)0xC1, (byte)0xC2 }; |
||||
assertTrue(Arrays.equals(bytes, EncodingUtils.concatenate(one, two, three))); |
||||
} |
||||
|
||||
@Test |
||||
public void subArray() { |
||||
byte[] bytes = new byte[] { (byte)0x01, (byte)0xFF, (byte)65, (byte)66, (byte)67, (byte)0xC0, (byte)0xC1, (byte)0xC2 }; |
||||
byte[] two = new byte[] { (byte)0xFF, (byte)65, (byte)66 }; |
||||
byte[] subArray = EncodingUtils.subArray(bytes, 1, 4); |
||||
assertEquals(3, subArray.length); |
||||
assertTrue(Arrays.equals(two, subArray)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
Implementation-Title: org.springframework.security.crypto |
||||
Implementation-Version: ${version} |
||||
Bundle-SymbolicName: org.springframework.security.crypto |
||||
Bundle-Name: Spring Security Web |
||||
Bundle-Vendor: SpringSource |
||||
Bundle-Version: ${version} |
||||
Bundle-ManifestVersion: 2 |
||||
Excluded-Imports: |
||||
javax.naming.*, |
||||
javax.rmi.*, |
||||
javax.sql.*, |
||||
javax.security.auth.* |
||||
Ignored-Existing-Headers: |
||||
Import-Package, |
||||
Export-Package |
||||
Import-Template: |
||||
Loading…
Reference in new issue