Skip to content

Commit e95effc

Browse files
larsgreferrwinch
authored andcommitted
Allow upgrading between different SCrypt encodings
Fixes gh-7057
1 parent 742df2c commit e95effc

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,30 @@ public boolean matches(CharSequence rawPassword, String encodedPassword) {
135135
return decodeAndCheckMatches(rawPassword, encodedPassword);
136136
}
137137

138+
@Override
139+
public boolean upgradeEncoding(String encodedPassword) {
140+
if (encodedPassword == null || encodedPassword.isEmpty()) {
141+
return false;
142+
}
143+
144+
String[] parts = encodedPassword.split("\\$");
145+
146+
if (parts.length != 4) {
147+
throw new IllegalArgumentException("Encoded password does not look like SCrypt: " + encodedPassword);
148+
}
149+
150+
long params = Long.parseLong(parts[1], 16);
151+
152+
int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
153+
int memoryCost = (int) params >> 8 & 0xff;
154+
int parallelization = (int) params & 0xff;
155+
156+
return cpuCost < this.cpuCost
157+
|| memoryCost < this.memoryCost
158+
|| parallelization < this.parallelization;
159+
160+
}
161+
138162
private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) {
139163
String[] parts = encodedPassword.split("\\$");
140164

crypto/src/test/java/org/springframework/security/crypto/scrypt/SCryptPasswordEncoderTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,35 @@ public void invalidKeyLengthParameter() {
116116
new SCryptPasswordEncoder(2, 8, 1, -1, 16);
117117
}
118118

119+
@Test
120+
public void upgradeEncoding_nullOrEmptyInput() {
121+
SCryptPasswordEncoder encoder = new SCryptPasswordEncoder();
122+
assertThat(encoder.upgradeEncoding(null)).isFalse();
123+
assertThat(encoder.upgradeEncoding("")).isFalse();
124+
}
125+
126+
@Test
127+
public void upgradeEncoding_sameEncoder() {
128+
SCryptPasswordEncoder encoder = new SCryptPasswordEncoder();
129+
String encoded = encoder.encode("password");
130+
assertThat(encoder.upgradeEncoding(encoded)).isFalse();
131+
}
132+
133+
@Test
134+
public void upgradeEncoding_weakerToStronger() {
135+
SCryptPasswordEncoder weakEncoder = new SCryptPasswordEncoder((int) Math.pow(2, 10), 4, 1, 32, 64);
136+
SCryptPasswordEncoder strongEncoder = new SCryptPasswordEncoder((int) Math.pow(2, 16), 8, 1, 32, 64);
137+
138+
String weakPassword = weakEncoder.encode("password");
139+
String strongPassword = strongEncoder.encode("password");
140+
141+
assertThat(strongEncoder.upgradeEncoding(weakPassword)).isTrue();
142+
assertThat(weakEncoder.upgradeEncoding(strongPassword)).isFalse();
143+
}
144+
145+
@Test(expected = IllegalArgumentException.class)
146+
public void upgradeEncoding_invalidInput() {
147+
new SCryptPasswordEncoder().upgradeEncoding("not-a-scrypt-password");
148+
}
119149
}
120150

0 commit comments

Comments
 (0)