Separate username and signature truncation fields

This commit is contained in:
Ravi Khadiwala 2023-04-04 16:59:46 -05:00 committed by ravi-signal
parent e4da59c236
commit 7b331edcde
3 changed files with 15 additions and 12 deletions

View File

@ -22,6 +22,8 @@ public class ExternalServiceCredentialsGenerator {
private static final String DELIMITER = ":"; private static final String DELIMITER = ":";
private static final int TRUNCATED_SIGNATURE_LENGTH = 10;
private final byte[] key; private final byte[] key;
private final byte[] userDerivationKey; private final byte[] userDerivationKey;
@ -36,7 +38,7 @@ public class ExternalServiceCredentialsGenerator {
private final Clock clock; private final Clock clock;
private final int truncateLength; private final int derivedUsernameTruncateLength;
public static ExternalServiceCredentialsGenerator.Builder builder(final byte[] key) { public static ExternalServiceCredentialsGenerator.Builder builder(final byte[] key) {
return new Builder(key); return new Builder(key);
@ -47,7 +49,7 @@ public class ExternalServiceCredentialsGenerator {
final byte[] userDerivationKey, final byte[] userDerivationKey,
final boolean prependUsername, final boolean prependUsername,
final boolean truncateSignature, final boolean truncateSignature,
final int truncateLength, final int derivedUsernameTruncateLength,
final String usernameTimestampPrefix, final String usernameTimestampPrefix,
final Function<Instant, Instant> usernameTimestampTruncator, final Function<Instant, Instant> usernameTimestampTruncator,
final Clock clock) { final Clock clock) {
@ -58,7 +60,7 @@ public class ExternalServiceCredentialsGenerator {
this.usernameTimestampPrefix = usernameTimestampPrefix; this.usernameTimestampPrefix = usernameTimestampPrefix;
this.usernameTimestampTruncator = usernameTimestampTruncator; this.usernameTimestampTruncator = usernameTimestampTruncator;
this.clock = requireNonNull(clock); this.clock = requireNonNull(clock);
this.truncateLength = truncateLength; this.derivedUsernameTruncateLength = derivedUsernameTruncateLength;
if (hasUsernameTimestampPrefix() ^ hasUsernameTimestampTruncator()) { if (hasUsernameTimestampPrefix() ^ hasUsernameTimestampTruncator()) {
throw new RuntimeException("Configured to have only one of (usernameTimestampPrefix, usernameTimestampTruncator)"); throw new RuntimeException("Configured to have only one of (usernameTimestampPrefix, usernameTimestampTruncator)");
@ -102,7 +104,7 @@ public class ExternalServiceCredentialsGenerator {
private ExternalServiceCredentials generate(final String identity) { private ExternalServiceCredentials generate(final String identity) {
final String username = shouldDeriveUsername() final String username = shouldDeriveUsername()
? hmac256TruncatedToHexString(userDerivationKey, identity, truncateLength) ? hmac256TruncatedToHexString(userDerivationKey, identity, derivedUsernameTruncateLength)
: identity; : identity;
final long currentTimeSeconds = currentTimeSeconds(); final long currentTimeSeconds = currentTimeSeconds();
@ -110,7 +112,7 @@ public class ExternalServiceCredentialsGenerator {
final String dataToSign = usernameIsTimestamp() ? username : username + DELIMITER + currentTimeSeconds; final String dataToSign = usernameIsTimestamp() ? username : username + DELIMITER + currentTimeSeconds;
final String signature = truncateSignature final String signature = truncateSignature
? hmac256TruncatedToHexString(key, dataToSign, truncateLength) ? hmac256TruncatedToHexString(key, dataToSign, TRUNCATED_SIGNATURE_LENGTH)
: hmac256ToHexString(key, dataToSign); : hmac256ToHexString(key, dataToSign);
final String token = (prependUsername ? dataToSign : currentTimeSeconds) + DELIMITER + signature; final String token = (prependUsername ? dataToSign : currentTimeSeconds) + DELIMITER + signature;
@ -173,7 +175,7 @@ public class ExternalServiceCredentialsGenerator {
final String signedData = usernameIsTimestamp() ? credentials.username() : credentials.username() + DELIMITER + timestampSeconds; final String signedData = usernameIsTimestamp() ? credentials.username() : credentials.username() + DELIMITER + timestampSeconds;
final String expectedSignature = truncateSignature final String expectedSignature = truncateSignature
? hmac256TruncatedToHexString(key, signedData, truncateLength) ? hmac256TruncatedToHexString(key, signedData, TRUNCATED_SIGNATURE_LENGTH)
: hmac256ToHexString(key, signedData); : hmac256ToHexString(key, signedData);
// if the signature is valid it's safe to parse the `timestampSeconds` string into Long // if the signature is valid it's safe to parse the `timestampSeconds` string into Long
@ -225,7 +227,7 @@ public class ExternalServiceCredentialsGenerator {
private boolean truncateSignature = true; private boolean truncateSignature = true;
private int truncateLength = 10; private int derivedUsernameTruncateLength = 10;
private String usernameTimestampPrefix = null; private String usernameTimestampPrefix = null;
@ -249,9 +251,9 @@ public class ExternalServiceCredentialsGenerator {
return this; return this;
} }
public Builder withTruncateLength(int truncateLength) { public Builder withDerivedUsernameTruncateLength(int truncateLength) {
Validate.inclusiveBetween(10, 32, truncateLength); Validate.inclusiveBetween(10, 32, truncateLength);
this.truncateLength = truncateLength; this.derivedUsernameTruncateLength = truncateLength;
return this; return this;
} }
@ -273,7 +275,7 @@ public class ExternalServiceCredentialsGenerator {
public ExternalServiceCredentialsGenerator build() { public ExternalServiceCredentialsGenerator build() {
return new ExternalServiceCredentialsGenerator( return new ExternalServiceCredentialsGenerator(
key, userDerivationKey, prependUsername, truncateSignature, truncateLength, usernameTimestampPrefix, usernameTimestampTruncator, clock); key, userDerivationKey, prependUsername, truncateSignature, derivedUsernameTruncateLength, usernameTimestampPrefix, usernameTimestampTruncator, clock);
} }
} }
} }

View File

@ -29,7 +29,7 @@ public class SecureValueRecovery2Controller {
.builder(cfg.userAuthenticationTokenSharedSecret()) .builder(cfg.userAuthenticationTokenSharedSecret())
.withUserDerivationKey(cfg.userIdTokenSharedSecret()) .withUserDerivationKey(cfg.userIdTokenSharedSecret())
.prependUsername(false) .prependUsername(false)
.withTruncateLength(16) .withDerivedUsernameTruncateLength(16)
.build(); .build();
} }

View File

@ -170,10 +170,11 @@ class ExternalServiceCredentialsGeneratorTest {
public void testTruncateLength() throws Exception { public void testTruncateLength() throws Exception {
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator.builder(new byte[32]) final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator.builder(new byte[32])
.withUserDerivationKey(new byte[32]) .withUserDerivationKey(new byte[32])
.withTruncateLength(14) .withDerivedUsernameTruncateLength(14)
.build(); .build();
final ExternalServiceCredentials creds = generator.generateFor(E164); final ExternalServiceCredentials creds = generator.generateFor(E164);
assertEquals(14*2 /* 2 chars per byte, because hex */, creds.username().length()); assertEquals(14*2 /* 2 chars per byte, because hex */, creds.username().length());
assertEquals("805b84df7eff1e8fe1baf0c6e838", creds.username()); assertEquals("805b84df7eff1e8fe1baf0c6e838", creds.username());
generator.validateAndGetTimestamp(creds);
} }
} }