Support for v2 registration lock

This commit is contained in:
Moxie Marlinspike
2019-06-07 15:19:11 -07:00
parent 4fdbe9b9ff
commit 11902dec3c
22 changed files with 538 additions and 127 deletions

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (C) 2013 Open WhisperSystems
*
* This program is free software: you can redistribute it and/or modify
@@ -17,18 +17,14 @@
package org.whispersystems.textsecuregcm.auth;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AuthenticationCredentials {
private final Logger logger = LoggerFactory.getLogger(AuthenticationCredentials.class);
private final String hashedAuthenticationToken;
private final String salt;
@@ -38,7 +34,7 @@ public class AuthenticationCredentials {
}
public AuthenticationCredentials(String authenticationToken) {
this.salt = Math.abs(new SecureRandom().nextInt()) + "";
this.salt = String.valueOf(Math.abs(new SecureRandom().nextInt()));
this.hashedAuthenticationToken = getHashedValue(salt, authenticationToken);
}
@@ -52,19 +48,13 @@ public class AuthenticationCredentials {
public boolean verify(String authenticationToken) {
String theirValue = getHashedValue(salt, authenticationToken);
logger.debug("Comparing: " + theirValue + " , " + this.hashedAuthenticationToken);
return theirValue.equals(this.hashedAuthenticationToken);
return MessageDigest.isEqual(theirValue.getBytes(StandardCharsets.UTF_8), this.hashedAuthenticationToken.getBytes(StandardCharsets.UTF_8));
}
private static String getHashedValue(String salt, String token) {
Logger logger = LoggerFactory.getLogger(AuthenticationCredentials.class);
logger.debug("Getting hashed token: " + salt + " , " + token);
try {
return new String(Hex.encodeHex(MessageDigest.getInstance("SHA1").digest((salt + token).getBytes("UTF-8"))));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
return new String(Hex.encodeHex(MessageDigest.getInstance("SHA1").digest((salt + token).getBytes(StandardCharsets.UTF_8))));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}

View File

@@ -1,6 +1,5 @@
package org.whispersystems.textsecuregcm.auth;
import com.google.common.base.Optional;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
@@ -14,27 +13,29 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;
public class DirectoryCredentialsGenerator {
public class ExternalServiceCredentialGenerator {
private final Logger logger = LoggerFactory.getLogger(DirectoryCredentialsGenerator.class);
private final Logger logger = LoggerFactory.getLogger(ExternalServiceCredentialGenerator.class);
private final byte[] key;
private final byte[] userIdKey;
private final boolean usernameDerivation;
public DirectoryCredentialsGenerator(byte[] key, byte[] userIdKey) {
this.key = key;
this.userIdKey = userIdKey;
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation) {
this.key = key;
this.userIdKey = userIdKey;
this.usernameDerivation = usernameDerivation;
}
public DirectoryCredentials generateFor(String number) {
public ExternalServiceCredentials generateFor(String number) {
Mac mac = getMacInstance();
String username = getUserId(number, mac);
String username = getUserId(number, mac, usernameDerivation);
long currentTimeSeconds = System.currentTimeMillis() / 1000;
String prefix = username + ":" + currentTimeSeconds;
String output = Hex.encodeHexString(Util.truncate(getHmac(key, prefix.getBytes(), mac), 10));
String token = prefix + ":" + output;
return new DirectoryCredentials(username, token);
return new ExternalServiceCredentials(username, token);
}
@@ -46,7 +47,7 @@ public class DirectoryCredentialsGenerator {
return false;
}
if (!getUserId(number, mac).equals(parts[0])) {
if (!getUserId(number, mac, usernameDerivation).equals(parts[0])) {
return false;
}
@@ -57,8 +58,9 @@ public class DirectoryCredentialsGenerator {
return isValidSignature(parts[0] + ":" + parts[1], parts[2], mac);
}
private String getUserId(String number, Mac mac) {
return Hex.encodeHexString(Util.truncate(getHmac(userIdKey, number.getBytes(), mac), 10));
private String getUserId(String number, Mac mac, boolean usernameDerivation) {
if (usernameDerivation) return Hex.encodeHexString(Util.truncate(getHmac(userIdKey, number.getBytes(), mac), 10));
else return number;
}
private boolean isValidTime(String timeString, long currentTimeMillis) {

View File

@@ -3,7 +3,7 @@ package org.whispersystems.textsecuregcm.auth;
import com.fasterxml.jackson.annotation.JsonProperty;
public class DirectoryCredentials {
public class ExternalServiceCredentials {
@JsonProperty
private String username;
@@ -11,12 +11,12 @@ public class DirectoryCredentials {
@JsonProperty
private String password;
public DirectoryCredentials(String username, String password) {
public ExternalServiceCredentials(String username, String password) {
this.username = username;
this.password = password;
}
public DirectoryCredentials() {}
public ExternalServiceCredentials() {}
public String getUsername() {
return username;