Browse Source

Polish spring-security-crypto main code

Manually polish `spring-security-crypto` following the formatting
and checkstyle fixes.

Issue gh-8945
pull/8983/head
Phillip Webb 6 years ago committed by Rob Winch
parent
commit
da22e97147
  1. 34
      crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java
  2. 19
      crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2PasswordEncoder.java
  3. 28
      crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java
  4. 9
      crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java
  5. 1
      crypto/src/main/java/org/springframework/security/crypto/codec/Utf8.java
  6. 66
      crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java
  7. 7
      crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java
  8. 7
      crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java
  9. 6
      crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
  10. 1
      crypto/src/main/java/org/springframework/security/crypto/factory/PasswordEncoderFactories.java
  11. 4
      crypto/src/main/java/org/springframework/security/crypto/keygen/SecureRandomBytesKeyGenerator.java
  12. 62
      crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java
  13. 3
      crypto/src/main/java/org/springframework/security/crypto/password/Md4.java
  14. 6
      crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java
  15. 5
      crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java
  16. 10
      crypto/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
  17. 6
      crypto/src/main/java/org/springframework/security/crypto/password/PasswordEncoderUtils.java
  18. 2
      crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java
  19. 4
      crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java
  20. 14
      crypto/src/main/java/org/springframework/security/crypto/scrypt/SCryptPasswordEncoder.java

34
crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java

@ -58,7 +58,6 @@ final class Argon2EncodingUtils {
*/ */
static String encode(byte[] hash, Argon2Parameters parameters) throws IllegalArgumentException { static String encode(byte[] hash, Argon2Parameters parameters) throws IllegalArgumentException {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
switch (parameters.getType()) { switch (parameters.getType()) {
case Argon2Parameters.ARGON2_d: case Argon2Parameters.ARGON2_d:
stringBuilder.append("$argon2d"); stringBuilder.append("$argon2d");
@ -74,13 +73,10 @@ final class Argon2EncodingUtils {
} }
stringBuilder.append("$v=").append(parameters.getVersion()).append("$m=").append(parameters.getMemory()) stringBuilder.append("$v=").append(parameters.getVersion()).append("$m=").append(parameters.getMemory())
.append(",t=").append(parameters.getIterations()).append(",p=").append(parameters.getLanes()); .append(",t=").append(parameters.getIterations()).append(",p=").append(parameters.getLanes());
if (parameters.getSalt() != null) { if (parameters.getSalt() != null) {
stringBuilder.append("$").append(b64encoder.encodeToString(parameters.getSalt())); stringBuilder.append("$").append(b64encoder.encodeToString(parameters.getSalt()));
} }
stringBuilder.append("$").append(b64encoder.encodeToString(hash)); stringBuilder.append("$").append(b64encoder.encodeToString(hash));
return stringBuilder.toString(); return stringBuilder.toString();
} }
@ -106,15 +102,11 @@ final class Argon2EncodingUtils {
*/ */
static Argon2Hash decode(String encodedHash) throws IllegalArgumentException { static Argon2Hash decode(String encodedHash) throws IllegalArgumentException {
Argon2Parameters.Builder paramsBuilder; Argon2Parameters.Builder paramsBuilder;
String[] parts = encodedHash.split("\\$"); String[] parts = encodedHash.split("\\$");
if (parts.length < 4) { if (parts.length < 4) {
throw new IllegalArgumentException("Invalid encoded Argon2-hash"); throw new IllegalArgumentException("Invalid encoded Argon2-hash");
} }
int currentPart = 1; int currentPart = 1;
switch (parts[currentPart++]) { switch (parts[currentPart++]) {
case "argon2d": case "argon2d":
paramsBuilder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d); paramsBuilder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d);
@ -128,41 +120,27 @@ final class Argon2EncodingUtils {
default: default:
throw new IllegalArgumentException("Invalid algorithm type: " + parts[0]); throw new IllegalArgumentException("Invalid algorithm type: " + parts[0]);
} }
if (parts[currentPart].startsWith("v=")) { if (parts[currentPart].startsWith("v=")) {
paramsBuilder.withVersion(Integer.parseInt(parts[currentPart].substring(2))); paramsBuilder.withVersion(Integer.parseInt(parts[currentPart].substring(2)));
currentPart++; currentPart++;
} }
String[] performanceParams = parts[currentPart++].split(","); String[] performanceParams = parts[currentPart++].split(",");
if (performanceParams.length != 3) { if (performanceParams.length != 3) {
throw new IllegalArgumentException("Amount of performance parameters invalid"); throw new IllegalArgumentException("Amount of performance parameters invalid");
} }
if (!performanceParams[0].startsWith("m=")) {
if (performanceParams[0].startsWith("m=")) {
paramsBuilder.withMemoryAsKB(Integer.parseInt(performanceParams[0].substring(2)));
}
else {
throw new IllegalArgumentException("Invalid memory parameter"); throw new IllegalArgumentException("Invalid memory parameter");
} }
paramsBuilder.withMemoryAsKB(Integer.parseInt(performanceParams[0].substring(2)));
if (performanceParams[1].startsWith("t=")) { if (!performanceParams[1].startsWith("t=")) {
paramsBuilder.withIterations(Integer.parseInt(performanceParams[1].substring(2)));
}
else {
throw new IllegalArgumentException("Invalid iterations parameter"); throw new IllegalArgumentException("Invalid iterations parameter");
} }
paramsBuilder.withIterations(Integer.parseInt(performanceParams[1].substring(2)));
if (performanceParams[2].startsWith("p=")) { if (!performanceParams[2].startsWith("p=")) {
paramsBuilder.withParallelism(Integer.parseInt(performanceParams[2].substring(2)));
}
else {
throw new IllegalArgumentException("Invalid parallelity parameter"); throw new IllegalArgumentException("Invalid parallelity parameter");
} }
paramsBuilder.withParallelism(Integer.parseInt(performanceParams[2].substring(2)));
paramsBuilder.withSalt(b64decoder.decode(parts[currentPart++])); paramsBuilder.withSalt(b64decoder.decode(parts[currentPart++]));
return new Argon2Hash(b64decoder.decode(parts[currentPart]), paramsBuilder.build()); return new Argon2Hash(b64decoder.decode(parts[currentPart]), paramsBuilder.build());
} }

19
crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2PasswordEncoder.java

@ -68,30 +68,27 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
private final BytesKeyGenerator saltGenerator; private final BytesKeyGenerator saltGenerator;
public Argon2PasswordEncoder() {
this(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY, DEFAULT_ITERATIONS);
}
public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) { public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) {
this.hashLength = hashLength; this.hashLength = hashLength;
this.parallelism = parallelism; this.parallelism = parallelism;
this.memory = memory; this.memory = memory;
this.iterations = iterations; this.iterations = iterations;
this.saltGenerator = KeyGenerators.secureRandom(saltLength); this.saltGenerator = KeyGenerators.secureRandom(saltLength);
} }
public Argon2PasswordEncoder() {
this(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY, DEFAULT_ITERATIONS);
}
@Override @Override
public String encode(CharSequence rawPassword) { public String encode(CharSequence rawPassword) {
byte[] salt = this.saltGenerator.generateKey(); byte[] salt = this.saltGenerator.generateKey();
byte[] hash = new byte[this.hashLength]; byte[] hash = new byte[this.hashLength];
Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id).withSalt(salt) Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id).withSalt(salt)
.withParallelism(this.parallelism).withMemoryAsKB(this.memory).withIterations(this.iterations).build(); .withParallelism(this.parallelism).withMemoryAsKB(this.memory).withIterations(this.iterations).build();
Argon2BytesGenerator generator = new Argon2BytesGenerator(); Argon2BytesGenerator generator = new Argon2BytesGenerator();
generator.init(params); generator.init(params);
generator.generateBytes(rawPassword.toString().toCharArray(), hash); generator.generateBytes(rawPassword.toString().toCharArray(), hash);
return Argon2EncodingUtils.encode(hash, params); return Argon2EncodingUtils.encode(hash, params);
} }
@ -101,9 +98,7 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
this.logger.warn("password hash is null"); this.logger.warn("password hash is null");
return false; return false;
} }
Argon2EncodingUtils.Argon2Hash decoded; Argon2EncodingUtils.Argon2Hash decoded;
try { try {
decoded = Argon2EncodingUtils.decode(encodedPassword); decoded = Argon2EncodingUtils.decode(encodedPassword);
} }
@ -111,13 +106,10 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
this.logger.warn("Malformed password hash", ex); this.logger.warn("Malformed password hash", ex);
return false; return false;
} }
byte[] hashBytes = new byte[decoded.getHash().length]; byte[] hashBytes = new byte[decoded.getHash().length];
Argon2BytesGenerator generator = new Argon2BytesGenerator(); Argon2BytesGenerator generator = new Argon2BytesGenerator();
generator.init(decoded.getParameters()); generator.init(decoded.getParameters());
generator.generateBytes(rawPassword.toString().toCharArray(), hashBytes); generator.generateBytes(rawPassword.toString().toCharArray(), hashBytes);
return constantTimeArrayEquals(decoded.getHash(), hashBytes); return constantTimeArrayEquals(decoded.getHash(), hashBytes);
} }
@ -127,9 +119,7 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
this.logger.warn("password hash is null"); this.logger.warn("password hash is null");
return false; return false;
} }
Argon2Parameters parameters = Argon2EncodingUtils.decode(encodedPassword).getParameters(); Argon2Parameters parameters = Argon2EncodingUtils.decode(encodedPassword).getParameters();
return parameters.getMemory() < this.memory || parameters.getIterations() < this.iterations; return parameters.getMemory() < this.memory || parameters.getIterations() < this.iterations;
} }
@ -137,7 +127,6 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
if (expected.length != actual.length) { if (expected.length != actual.length) {
return false; return false;
} }
int result = 0; int result = 0;
for (int i = 0; i < expected.length; i++) { for (int i = 0; i < expected.length; i++) {
result |= expected[i] ^ actual[i]; result |= expected[i] ^ actual[i];

28
crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java

@ -106,15 +106,15 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
if (rawPassword == null) { if (rawPassword == null) {
throw new IllegalArgumentException("rawPassword cannot be null"); throw new IllegalArgumentException("rawPassword cannot be null");
} }
String salt = getSalt();
return BCrypt.hashpw(rawPassword.toString(), salt);
}
String salt; private String getSalt() {
if (this.random != null) { if (this.random != null) {
salt = BCrypt.gensalt(this.version.getVersion(), this.strength, this.random); return BCrypt.gensalt(this.version.getVersion(), this.strength, this.random);
}
else {
salt = BCrypt.gensalt(this.version.getVersion(), this.strength);
} }
return BCrypt.hashpw(rawPassword.toString(), salt); return BCrypt.gensalt(this.version.getVersion(), this.strength);
} }
@Override @Override
@ -122,17 +122,14 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
if (rawPassword == null) { if (rawPassword == null) {
throw new IllegalArgumentException("rawPassword cannot be null"); throw new IllegalArgumentException("rawPassword cannot be null");
} }
if (encodedPassword == null || encodedPassword.length() == 0) { if (encodedPassword == null || encodedPassword.length() == 0) {
this.logger.warn("Empty encoded password"); this.logger.warn("Empty encoded password");
return false; return false;
} }
if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) { if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
this.logger.warn("Encoded password does not look like BCrypt"); this.logger.warn("Encoded password does not look like BCrypt");
return false; return false;
} }
return BCrypt.checkpw(rawPassword.toString(), encodedPassword); return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
} }
@ -142,15 +139,12 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
this.logger.warn("Empty encoded password"); this.logger.warn("Empty encoded password");
return false; return false;
} }
Matcher matcher = this.BCRYPT_PATTERN.matcher(encodedPassword); Matcher matcher = this.BCRYPT_PATTERN.matcher(encodedPassword);
if (!matcher.matches()) { if (!matcher.matches()) {
throw new IllegalArgumentException("Encoded password does not look like BCrypt: " + encodedPassword); throw new IllegalArgumentException("Encoded password does not look like BCrypt: " + encodedPassword);
} }
else { int strength = Integer.parseInt(matcher.group(2));
int strength = Integer.parseInt(matcher.group(2)); return strength < this.strength;
return strength < this.strength;
}
} }
/** /**
@ -160,7 +154,11 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
*/ */
public enum BCryptVersion { public enum BCryptVersion {
$2A("$2a"), $2Y("$2y"), $2B("$2b"); $2A("$2a"),
$2Y("$2y"),
$2B("$2b");
private final String version; private final String version;

9
crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java

@ -27,8 +27,7 @@ package org.springframework.security.crypto.codec;
*/ */
public final class Hex { public final class Hex {
private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', private static final char[] HEX = "0123456789abcdef".toCharArray();
'f' };
private Hex() { private Hex() {
} }
@ -36,7 +35,6 @@ public final class Hex {
public static char[] encode(byte[] bytes) { public static char[] encode(byte[] bytes) {
final int nBytes = bytes.length; final int nBytes = bytes.length;
char[] result = new char[2 * nBytes]; char[] result = new char[2 * nBytes];
int j = 0; int j = 0;
for (byte aByte : bytes) { for (byte aByte : bytes) {
// Char for top 4 bits // Char for top 4 bits
@ -44,23 +42,18 @@ public final class Hex {
// Bottom 4 // Bottom 4
result[j++] = HEX[(0x0F & aByte)]; result[j++] = HEX[(0x0F & aByte)];
} }
return result; return result;
} }
public static byte[] decode(CharSequence s) { public static byte[] decode(CharSequence s) {
int nChars = s.length(); int nChars = s.length();
if (nChars % 2 != 0) { if (nChars % 2 != 0) {
throw new IllegalArgumentException("Hex-encoded string must have an even number of characters"); throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");
} }
byte[] result = new byte[nChars / 2]; byte[] result = new byte[nChars / 2];
for (int i = 0; i < nChars; i += 2) { for (int i = 0; i < nChars; i += 2) {
int msb = Character.digit(s.charAt(i), 16); int msb = Character.digit(s.charAt(i), 16);
int lsb = Character.digit(s.charAt(i + 1), 16); int lsb = Character.digit(s.charAt(i + 1), 16);
if (msb < 0 || lsb < 0) { if (msb < 0 || lsb < 0) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position"); "Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position");

1
crypto/src/main/java/org/springframework/security/crypto/codec/Utf8.java

@ -44,7 +44,6 @@ public final class Utf8 {
ByteBuffer bytes = CHARSET.newEncoder().encode(CharBuffer.wrap(string)); ByteBuffer bytes = CHARSET.newEncoder().encode(CharBuffer.wrap(string));
byte[] bytesCopy = new byte[bytes.limit()]; byte[] bytesCopy = new byte[bytes.limit()];
System.arraycopy(bytes.array(), 0, bytesCopy, 0, bytes.limit()); System.arraycopy(bytes.array(), 0, bytesCopy, 0, bytes.limit());
return bytesCopy; return bytesCopy;
} }
catch (CharacterCodingException ex) { catch (CharacterCodingException ex) {

66
crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java

@ -52,38 +52,6 @@ public final class AesBytesEncryptor implements BytesEncryptor {
private static final String AES_GCM_ALGORITHM = "AES/GCM/NoPadding"; private static final String AES_GCM_ALGORITHM = "AES/GCM/NoPadding";
public enum CipherAlgorithm {
CBC(AES_CBC_ALGORITHM, NULL_IV_GENERATOR), GCM(AES_GCM_ALGORITHM, KeyGenerators.secureRandom(16));
private BytesKeyGenerator ivGenerator;
private String name;
CipherAlgorithm(String name, BytesKeyGenerator ivGenerator) {
this.name = name;
this.ivGenerator = ivGenerator;
}
@Override
public String toString() {
return this.name;
}
public AlgorithmParameterSpec getParameterSpec(byte[] iv) {
return (this != CBC) ? new GCMParameterSpec(128, iv) : new IvParameterSpec(iv);
}
public Cipher createCipher() {
return CipherUtils.newCipher(this.toString());
}
public BytesKeyGenerator defaultIvGenerator() {
return this.ivGenerator;
}
}
public AesBytesEncryptor(String password, CharSequence salt) { public AesBytesEncryptor(String password, CharSequence salt) {
this(password, salt, null); this(password, salt, null);
} }
@ -159,4 +127,38 @@ public final class AesBytesEncryptor implements BytesEncryptor {
}; };
public enum CipherAlgorithm {
CBC(AES_CBC_ALGORITHM, NULL_IV_GENERATOR),
GCM(AES_GCM_ALGORITHM, KeyGenerators.secureRandom(16));
private BytesKeyGenerator ivGenerator;
private String name;
CipherAlgorithm(String name, BytesKeyGenerator ivGenerator) {
this.name = name;
this.ivGenerator = ivGenerator;
}
@Override
public String toString() {
return this.name;
}
public AlgorithmParameterSpec getParameterSpec(byte[] iv) {
return (this != CBC) ? new GCMParameterSpec(128, iv) : new IvParameterSpec(iv);
}
public Cipher createCipher() {
return CipherUtils.newCipher(this.toString());
}
public BytesKeyGenerator defaultIvGenerator() {
return this.ivGenerator;
}
}
} }

7
crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java

@ -33,7 +33,6 @@ import org.springframework.security.crypto.util.EncodingUtils;
* "AES/CBC/PKCS5Padding". * "AES/CBC/PKCS5Padding".
* *
* @author William Tran * @author William Tran
*
*/ */
public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryptor { public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryptor {
@ -46,10 +45,9 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp
} }
@Override @Override
@SuppressWarnings("deprecation")
public byte[] encrypt(byte[] bytes) { public byte[] encrypt(byte[] bytes) {
byte[] iv = this.ivGenerator.generateKey(); byte[] iv = this.ivGenerator.generateKey();
@SuppressWarnings("deprecation")
PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding()); new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding());
blockCipher.init(true, new ParametersWithIV(this.secretKey, iv)); blockCipher.init(true, new ParametersWithIV(this.secretKey, iv));
@ -58,11 +56,10 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp
} }
@Override @Override
@SuppressWarnings("deprecation")
public byte[] decrypt(byte[] encryptedBytes) { public byte[] decrypt(byte[] encryptedBytes) {
byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength());
encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length);
@SuppressWarnings("deprecation")
PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding()); new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding());
blockCipher.init(false, new ParametersWithIV(this.secretKey, iv)); blockCipher.init(false, new ParametersWithIV(this.secretKey, iv));

7
crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java

@ -44,23 +44,20 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp
} }
@Override @Override
@SuppressWarnings("deprecation")
public byte[] encrypt(byte[] bytes) { public byte[] encrypt(byte[] bytes) {
byte[] iv = this.ivGenerator.generateKey(); byte[] iv = this.ivGenerator.generateKey();
@SuppressWarnings("deprecation")
GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()); GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine());
blockCipher.init(true, new AEADParameters(this.secretKey, 128, iv, null)); blockCipher.init(true, new AEADParameters(this.secretKey, 128, iv, null));
byte[] encrypted = process(blockCipher, bytes); byte[] encrypted = process(blockCipher, bytes);
return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted;
} }
@Override @Override
@SuppressWarnings("deprecation")
public byte[] decrypt(byte[] encryptedBytes) { public byte[] decrypt(byte[] encryptedBytes) {
byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength());
encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length);
@SuppressWarnings("deprecation")
GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()); GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine());
blockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null)); blockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null));
return process(blockCipher, encryptedBytes); return process(blockCipher, encryptedBytes);

6
crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java

@ -113,13 +113,13 @@ public final class Encryptors {
* environments where working with plain text strings is desired for simplicity. * environments where working with plain text strings is desired for simplicity.
*/ */
public static TextEncryptor noOpText() { public static TextEncryptor noOpText() {
return NO_OP_TEXT_INSTANCE; return NoOpTextEncryptor.INSTANCE;
} }
private static final TextEncryptor NO_OP_TEXT_INSTANCE = new NoOpTextEncryptor();
private static final class NoOpTextEncryptor implements TextEncryptor { private static final class NoOpTextEncryptor implements TextEncryptor {
static final TextEncryptor INSTANCE = new NoOpTextEncryptor();
@Override @Override
public String encrypt(String text) { public String encrypt(String text) {
return text; return text;

1
crypto/src/main/java/org/springframework/security/crypto/factory/PasswordEncoderFactories.java

@ -78,7 +78,6 @@ public final class PasswordEncoderFactories {
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256")); new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder()); encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder()); encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders); return new DelegatingPasswordEncoder(encodingId, encoders);
} }

4
crypto/src/main/java/org/springframework/security/crypto/keygen/SecureRandomBytesKeyGenerator.java

@ -28,6 +28,8 @@ import java.security.SecureRandom;
*/ */
final class SecureRandomBytesKeyGenerator implements BytesKeyGenerator { final class SecureRandomBytesKeyGenerator implements BytesKeyGenerator {
private static final int DEFAULT_KEY_LENGTH = 8;
private final SecureRandom random; private final SecureRandom random;
private final int keyLength; private final int keyLength;
@ -59,6 +61,4 @@ final class SecureRandomBytesKeyGenerator implements BytesKeyGenerator {
return bytes; return bytes;
} }
private static final int DEFAULT_KEY_LENGTH = 8;
} }

62
crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java

@ -75,11 +75,9 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
if (salt == null) { if (salt == null) {
return hash; return hash;
} }
byte[] hashAndSalt = new byte[hash.length + salt.length]; byte[] hashAndSalt = new byte[hash.length + salt.length];
System.arraycopy(hash, 0, hashAndSalt, 0, hash.length); System.arraycopy(hash, 0, hashAndSalt, 0, hash.length);
System.arraycopy(salt, 0, hashAndSalt, hash.length, salt.length); System.arraycopy(salt, 0, hashAndSalt, hash.length, salt.length);
return hashAndSalt; return hashAndSalt;
} }
@ -98,42 +96,39 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
} }
private String encode(CharSequence rawPassword, byte[] salt) { private String encode(CharSequence rawPassword, byte[] salt) {
MessageDigest sha; MessageDigest sha = getSha(rawPassword);
if (salt != null) {
sha.update(salt);
}
byte[] hash = combineHashAndSalt(sha.digest(), salt);
String prefix = getPrefix(salt);
return prefix + Utf8.decode(Base64.getEncoder().encode(hash));
}
private MessageDigest getSha(CharSequence rawPassword) {
try { try {
sha = MessageDigest.getInstance("SHA"); MessageDigest sha = MessageDigest.getInstance("SHA");
sha.update(Utf8.encode(rawPassword)); sha.update(Utf8.encode(rawPassword));
return sha;
} }
catch (java.security.NoSuchAlgorithmException ex) { catch (java.security.NoSuchAlgorithmException ex) {
throw new IllegalStateException("No SHA implementation available!"); throw new IllegalStateException("No SHA implementation available!");
} }
}
if (salt != null) { private String getPrefix(byte[] salt) {
sha.update(salt);
}
byte[] hash = combineHashAndSalt(sha.digest(), salt);
String prefix;
if (salt == null || salt.length == 0) { if (salt == null || salt.length == 0) {
prefix = this.forceLowerCasePrefix ? SHA_PREFIX_LC : SHA_PREFIX; return this.forceLowerCasePrefix ? SHA_PREFIX_LC : SHA_PREFIX;
} }
else { return this.forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
prefix = this.forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
}
return prefix + Utf8.decode(Base64.getEncoder().encode(hash));
} }
private byte[] extractSalt(String encPass) { private byte[] extractSalt(String encPass) {
String encPassNoLabel = encPass.substring(6); String encPassNoLabel = encPass.substring(6);
byte[] hashAndSalt = Base64.getDecoder().decode(encPassNoLabel.getBytes()); byte[] hashAndSalt = Base64.getDecoder().decode(encPassNoLabel.getBytes());
int saltLength = hashAndSalt.length - SHA_LENGTH; int saltLength = hashAndSalt.length - SHA_LENGTH;
byte[] salt = new byte[saltLength]; byte[] salt = new byte[saltLength];
System.arraycopy(hashAndSalt, SHA_LENGTH, salt, 0, saltLength); System.arraycopy(hashAndSalt, SHA_LENGTH, salt, 0, saltLength);
return salt; return salt;
} }
@ -151,28 +146,24 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
private boolean matches(String rawPassword, String encodedPassword) { private boolean matches(String rawPassword, String encodedPassword) {
String prefix = extractPrefix(encodedPassword); String prefix = extractPrefix(encodedPassword);
if (prefix == null) { if (prefix == null) {
return PasswordEncoderUtils.equals(encodedPassword, rawPassword); return PasswordEncoderUtils.equals(encodedPassword, rawPassword);
} }
byte[] salt = getSalt(encodedPassword, prefix);
int startOfHash = prefix.length();
String encodedRawPass = encode(rawPassword, salt).substring(startOfHash);
return PasswordEncoderUtils.equals(encodedRawPass, encodedPassword.substring(startOfHash));
}
byte[] salt; private byte[] getSalt(String encodedPassword, String prefix) {
if (prefix.equals(SSHA_PREFIX) || prefix.equals(SSHA_PREFIX_LC)) { if (prefix.equals(SSHA_PREFIX) || prefix.equals(SSHA_PREFIX_LC)) {
salt = extractSalt(encodedPassword); return extractSalt(encodedPassword);
} }
else if (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) { if (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) {
throw new IllegalArgumentException("Unsupported password prefix '" + prefix + "'"); throw new IllegalArgumentException("Unsupported password prefix '" + prefix + "'");
} }
else { // Standard SHA
// Standard SHA return null;
salt = null;
}
int startOfHash = prefix.length();
String encodedRawPass = encode(rawPassword, salt).substring(startOfHash);
return PasswordEncoderUtils.equals(encodedRawPass, encodedPassword.substring(startOfHash));
} }
/** /**
@ -182,13 +173,10 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
if (!encPass.startsWith("{")) { if (!encPass.startsWith("{")) {
return null; return null;
} }
int secondBrace = encPass.lastIndexOf('}'); int secondBrace = encPass.lastIndexOf('}');
if (secondBrace < 0) { if (secondBrace < 0) {
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix"); throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
} }
return encPass.substring(0, secondBrace + 1); return encPass.substring(0, secondBrace + 1);
} }

3
crypto/src/main/java/org/springframework/security/crypto/password/Md4.java

@ -76,16 +76,13 @@ class Md4 {
update(this.buffer, 0); update(this.buffer, 0);
this.bufferOffset = 0; this.bufferOffset = 0;
} }
while (this.bufferOffset < C) { while (this.bufferOffset < C) {
this.buffer[this.bufferOffset++] = (byte) 0x00; this.buffer[this.bufferOffset++] = (byte) 0x00;
} }
long bitCount = this.byteCount * 8; long bitCount = this.byteCount * 8;
for (int i = 0; i < 64; i += 8) { for (int i = 0; i < 64; i += 8) {
this.buffer[this.bufferOffset++] = (byte) (bitCount >>> (i)); this.buffer[this.bufferOffset++] = (byte) (bitCount >>> (i));
} }
update(this.buffer, 0); update(this.buffer, 0);
digest(buffer, offset); digest(buffer, offset);
} }

6
crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java

@ -111,10 +111,8 @@ public class Md4PasswordEncoder implements PasswordEncoder {
} }
String saltedPassword = rawPassword + salt; String saltedPassword = rawPassword + salt;
byte[] saltedPasswordBytes = Utf8.encode(saltedPassword); byte[] saltedPasswordBytes = Utf8.encode(saltedPassword);
Md4 md4 = new Md4(); Md4 md4 = new Md4();
md4.update(saltedPasswordBytes, 0, saltedPasswordBytes.length); md4.update(saltedPasswordBytes, 0, saltedPasswordBytes.length);
byte[] digest = md4.digest(); byte[] digest = md4.digest();
String encoded = encode(digest); String encoded = encode(digest);
return salt + encoded; return salt + encoded;
@ -124,9 +122,7 @@ public class Md4PasswordEncoder implements PasswordEncoder {
if (this.encodeHashAsBase64) { if (this.encodeHashAsBase64) {
return Utf8.decode(Base64.getEncoder().encode(digest)); return Utf8.decode(Base64.getEncoder().encode(digest));
} }
else { return new String(Hex.encode(digest));
return new String(Hex.encode(digest));
}
} }
/** /**

5
crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java

@ -123,7 +123,6 @@ public class MessageDigestPasswordEncoder implements PasswordEncoder {
private String digest(String salt, CharSequence rawPassword) { private String digest(String salt, CharSequence rawPassword) {
String saltedPassword = rawPassword + salt; String saltedPassword = rawPassword + salt;
byte[] digest = this.digester.digest(Utf8.encode(saltedPassword)); byte[] digest = this.digester.digest(Utf8.encode(saltedPassword));
String encoded = encode(digest); String encoded = encode(digest);
return salt + encoded; return salt + encoded;
@ -133,9 +132,7 @@ public class MessageDigestPasswordEncoder implements PasswordEncoder {
if (this.encodeHashAsBase64) { if (this.encodeHashAsBase64) {
return Utf8.decode(Base64.getEncoder().encode(digest)); return Utf8.decode(Base64.getEncoder().encode(digest));
} }
else { return new String(Hex.encode(digest));
return new String(Hex.encode(digest));
}
} }
/** /**

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

@ -33,6 +33,11 @@ package org.springframework.security.crypto.password;
@Deprecated @Deprecated
public final class NoOpPasswordEncoder implements PasswordEncoder { public final class NoOpPasswordEncoder implements PasswordEncoder {
private static final PasswordEncoder INSTANCE = new NoOpPasswordEncoder();
private NoOpPasswordEncoder() {
}
@Override @Override
public String encode(CharSequence rawPassword) { public String encode(CharSequence rawPassword) {
return rawPassword.toString(); return rawPassword.toString();
@ -50,9 +55,4 @@ public final class NoOpPasswordEncoder implements PasswordEncoder {
return INSTANCE; return INSTANCE;
} }
private static final PasswordEncoder INSTANCE = new NoOpPasswordEncoder();
private NoOpPasswordEncoder() {
}
} }

6
crypto/src/main/java/org/springframework/security/crypto/password/PasswordEncoderUtils.java

@ -39,17 +39,13 @@ final class PasswordEncoderUtils {
static boolean equals(String expected, String actual) { static boolean equals(String expected, String actual) {
byte[] expectedBytes = bytesUtf8(expected); byte[] expectedBytes = bytesUtf8(expected);
byte[] actualBytes = bytesUtf8(actual); byte[] actualBytes = bytesUtf8(actual);
return MessageDigest.isEqual(expectedBytes, actualBytes); return MessageDigest.isEqual(expectedBytes, actualBytes);
} }
private static byte[] bytesUtf8(String s) { private static byte[] bytesUtf8(String s) {
if (s == null) {
return null;
}
// need to check if Utf8.encode() runs in constant time (probably not). // need to check if Utf8.encode() runs in constant time (probably not).
// This may leak length of string. // This may leak length of string.
return Utf8.encode(s); return (s != null) ? Utf8.encode(s) : null;
} }
} }

2
crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java

@ -112,11 +112,11 @@ public class Pbkdf2PasswordEncoder implements PasswordEncoder {
String algorithmName = secretKeyFactoryAlgorithm.name(); String algorithmName = secretKeyFactoryAlgorithm.name();
try { try {
SecretKeyFactory.getInstance(algorithmName); SecretKeyFactory.getInstance(algorithmName);
this.algorithm = algorithmName;
} }
catch (NoSuchAlgorithmException ex) { catch (NoSuchAlgorithmException ex) {
throw new IllegalArgumentException("Invalid algorithm '" + algorithmName + "'.", ex); throw new IllegalArgumentException("Invalid algorithm '" + algorithmName + "'.", ex);
} }
this.algorithm = algorithmName;
} }
/** /**

4
crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java

@ -50,6 +50,8 @@ import org.springframework.security.crypto.util.EncodingUtils;
@Deprecated @Deprecated
public final class StandardPasswordEncoder implements PasswordEncoder { public final class StandardPasswordEncoder implements PasswordEncoder {
private static final int DEFAULT_ITERATIONS = 1024;
private final Digester digester; private final Digester digester;
private final byte[] secret; private final byte[] secret;
@ -104,6 +106,4 @@ public final class StandardPasswordEncoder implements PasswordEncoder {
return Hex.decode(encodedPassword); return Hex.decode(encodedPassword);
} }
private static final int DEFAULT_ITERATIONS = 1024;
} }

14
crypto/src/main/java/org/springframework/security/crypto/scrypt/SCryptPasswordEncoder.java

@ -109,7 +109,6 @@ public class SCryptPasswordEncoder implements PasswordEncoder {
if (saltLength < 1 || saltLength > Integer.MAX_VALUE) { if (saltLength < 1 || saltLength > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Salt length must be >= 1 and <= " + Integer.MAX_VALUE); throw new IllegalArgumentException("Salt length must be >= 1 and <= " + Integer.MAX_VALUE);
} }
this.cpuCost = cpuCost; this.cpuCost = cpuCost;
this.memoryCost = memoryCost; this.memoryCost = memoryCost;
this.parallelization = parallelization; this.parallelization = parallelization;
@ -136,56 +135,43 @@ public class SCryptPasswordEncoder implements PasswordEncoder {
if (encodedPassword == null || encodedPassword.isEmpty()) { if (encodedPassword == null || encodedPassword.isEmpty()) {
return false; return false;
} }
String[] parts = encodedPassword.split("\\$"); String[] parts = encodedPassword.split("\\$");
if (parts.length != 4) { if (parts.length != 4) {
throw new IllegalArgumentException("Encoded password does not look like SCrypt: " + encodedPassword); throw new IllegalArgumentException("Encoded password does not look like SCrypt: " + encodedPassword);
} }
long params = Long.parseLong(parts[1], 16); long params = Long.parseLong(parts[1], 16);
int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff); int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
int memoryCost = (int) params >> 8 & 0xff; int memoryCost = (int) params >> 8 & 0xff;
int parallelization = (int) params & 0xff; int parallelization = (int) params & 0xff;
return cpuCost < this.cpuCost || memoryCost < this.memoryCost || parallelization < this.parallelization; return cpuCost < this.cpuCost || memoryCost < this.memoryCost || parallelization < this.parallelization;
} }
private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) { private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) {
String[] parts = encodedPassword.split("\\$"); String[] parts = encodedPassword.split("\\$");
if (parts.length != 4) { if (parts.length != 4) {
return false; return false;
} }
long params = Long.parseLong(parts[1], 16); long params = Long.parseLong(parts[1], 16);
byte[] salt = decodePart(parts[2]); byte[] salt = decodePart(parts[2]);
byte[] derived = decodePart(parts[3]); byte[] derived = decodePart(parts[3]);
int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff); int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
int memoryCost = (int) params >> 8 & 0xff; int memoryCost = (int) params >> 8 & 0xff;
int parallelization = (int) params & 0xff; int parallelization = (int) params & 0xff;
byte[] generated = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization, byte[] generated = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization,
this.keyLength); this.keyLength);
return MessageDigest.isEqual(derived, generated); return MessageDigest.isEqual(derived, generated);
} }
private String digest(CharSequence rawPassword, byte[] salt) { private String digest(CharSequence rawPassword, byte[] salt) {
byte[] derived = SCrypt.generate(Utf8.encode(rawPassword), salt, this.cpuCost, this.memoryCost, byte[] derived = SCrypt.generate(Utf8.encode(rawPassword), salt, this.cpuCost, this.memoryCost,
this.parallelization, this.keyLength); this.parallelization, this.keyLength);
String params = Long.toString( String params = Long.toString(
((int) (Math.log(this.cpuCost) / Math.log(2)) << 16L) | this.memoryCost << 8 | this.parallelization, ((int) (Math.log(this.cpuCost) / Math.log(2)) << 16L) | this.memoryCost << 8 | this.parallelization,
16); 16);
StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2); StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2);
sb.append("$").append(params).append('$'); sb.append("$").append(params).append('$');
sb.append(encodePart(salt)).append('$'); sb.append(encodePart(salt)).append('$');
sb.append(encodePart(derived)); sb.append(encodePart(derived));
return sb.toString(); return sb.toString();
} }

Loading…
Cancel
Save