SEC-1569: initial commit of spring-security-crypto module, consisting of encrypt, keygen, password, and util packages
This commit is contained in:
parent
afd586c96e
commit
ffa7301e7f
|
@ -0,0 +1,5 @@
|
|||
// crypto module build file
|
||||
|
||||
dependencies {
|
||||
|
||||
}
|
|
@ -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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/**
|
||||
* Symmetric-key data encryption.
|
||||
*/
|
||||
package org.springframework.security.crypto.encrypt;
|
||||
|
|
@ -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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/**
|
||||
* Secure random key generators.
|
||||
*/
|
||||
package org.springframework.security.crypto.keygen;
|
||||
|
||||
|
|
@ -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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/**
|
||||
* Password encoders.
|
||||
*/
|
||||
package org.springframework.security.crypto.password;
|
||||
|
|
@ -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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/*
|
||||
* 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 @@
|
|||
/**
|
||||
* Shared crypto utilities.
|
||||
*/
|
||||
package org.springframework.security.crypto.util;
|
|
@ -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 @@
|
|||
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 @@
|
|||
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 @@
|
|||
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 @@
|
|||
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 @@
|
|||
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:
|
|
@ -7,7 +7,8 @@ def String[] modules = [
|
|||
'cas',
|
||||
'openid',
|
||||
'taglibs',
|
||||
'aspects'
|
||||
'aspects',
|
||||
'crypto'
|
||||
]
|
||||
|
||||
def String[] samples = [
|
||||
|
|
Loading…
Reference in New Issue