--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -776,18 +776,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'background/common/log/writers/SimpleTagLogWriter.java',
'background/common/log/writers/StringLogWriter.java',
'background/common/log/writers/TagLogWriter.java',
'background/common/log/writers/ThreadLocalTagLogWriter.java',
'background/common/PrefsBranch.java',
'background/common/telemetry/TelemetryWrapper.java',
'background/db/CursorDumper.java',
'background/db/Tab.java',
- 'background/fxa/FxAccount10AuthDelegate.java',
- 'background/fxa/FxAccount10CreateDelegate.java',
'background/fxa/FxAccount20CreateDelegate.java',
'background/fxa/FxAccount20LoginDelegate.java',
'background/fxa/FxAccountClient.java',
'background/fxa/FxAccountClient10.java',
'background/fxa/FxAccountClient20.java',
'background/fxa/FxAccountClientException.java',
'background/fxa/FxAccountRemoteError.java',
'background/fxa/FxAccountUtils.java',
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount10AuthDelegate.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.background.fxa;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.net.SRPConstants;
-
-public class FxAccount10AuthDelegate implements FxAccountClient10.AuthDelegate {
- // Fixed by protocol.
- protected final BigInteger N;
- protected final BigInteger g;
- protected final int modNLengthBytes;
-
- // Configured at construction time.
- protected final String email;
- protected final byte[] stretchedPWBytes;
-
- // Encapsulate state.
- protected static class AuthState {
- protected String srpToken;
- protected String mainSalt;
- protected String srpSalt;
-
- protected BigInteger x;
- protected BigInteger A;
- protected byte[] Kbytes;
- protected byte[] Mbytes;
- }
-
- // State should be written exactly once.
- protected AuthState internalAuthState = null;
-
- public FxAccount10AuthDelegate(String email, byte[] stretchedPWBytes) {
- this.email = email;
- this.stretchedPWBytes = stretchedPWBytes;
- this.N = SRPConstants._2048.N;
- this.g = SRPConstants._2048.g;
- this.modNLengthBytes = SRPConstants._2048.byteLength;
- }
-
- protected BigInteger generateSecretValue() {
- return Utils.generateBigIntegerLessThan(N);
- }
-
- public static class FxAccountClientMalformedAuthException extends FxAccountClientException {
- private static final long serialVersionUID = 3585262174699395505L;
-
- public FxAccountClientMalformedAuthException(String detailMessage) {
- super(detailMessage);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public JSONObject getAuthStartBody() throws FxAccountClientException {
- try {
- final JSONObject body = new JSONObject();
- body.put("email", FxAccountUtils.bytes(email));
- return body;
- } catch (UnsupportedEncodingException e) {
- throw new FxAccountClientException(e);
- }
- }
-
- @Override
- public void onAuthStartResponse(final ExtendedJSONObject body) throws FxAccountClientException {
- if (this.internalAuthState != null) {
- throw new FxAccountClientException("auth must not be written before calling onAuthStartResponse");
- }
-
- String srpToken = null;
- String srpSalt = null;
- String srpB = null;
- String mainSalt = null;
-
- try {
- srpToken = body.getString("srpToken");
- if (srpToken == null) {
- throw new FxAccountClientMalformedAuthException("srpToken must be a non-null object");
- }
- ExtendedJSONObject srp = body.getObject("srp");
- if (srp == null) {
- throw new FxAccountClientMalformedAuthException("srp must be a non-null object");
- }
- srpSalt = srp.getString("salt");
- if (srpSalt == null) {
- throw new FxAccountClientMalformedAuthException("srp.salt must not be null");
- }
- srpB = srp.getString("B");
- if (srpB == null) {
- throw new FxAccountClientMalformedAuthException("srp.B must not be null");
- }
- ExtendedJSONObject passwordStretching = body.getObject("passwordStretching");
- if (passwordStretching == null) {
- throw new FxAccountClientMalformedAuthException("passwordStretching must be a non-null object");
- }
- mainSalt = passwordStretching.getString("salt");
- if (mainSalt == null) {
- throw new FxAccountClientMalformedAuthException("srp.passwordStretching.salt must not be null");
- }
- throwIfParametersAreBad(passwordStretching);
-
- this.internalAuthState = authStateFromParameters(srpToken, mainSalt, srpSalt, srpB, generateSecretValue());
- } catch (FxAccountClientException e) {
- throw e;
- } catch (Exception e) {
- throw new FxAccountClientException(e);
- }
- }
-
- /**
- * Expect object like:
- * "passwordStretching": {
- * "type": "PBKDF2/scrypt/PBKDF2/v1",
- * "PBKDF2_rounds_1": 20000,
- * "scrypt_N": 65536,
- * "scrypt_r": 8,
- * "scrypt_p": 1,
- * "PBKDF2_rounds_2": 20000,
- * "salt": "996bc6b1aa63cd69856a2ec81cbf19d5c8a604713362df9ee15c2bf07128efab"
- * }
- * @param params to verify.
- * @throws FxAccountClientMalformedAuthException
- */
- protected void throwIfParametersAreBad(ExtendedJSONObject params) throws FxAccountClientMalformedAuthException {
- if (params == null ||
- params.size() != 7 ||
- params.getString("salt") == null ||
- !("PBKDF2/scrypt/PBKDF2/v1".equals(params.getString("type"))) ||
- 20000 != params.getLong("PBKDF2_rounds_1") ||
- 65536 != params.getLong("scrypt_N") ||
- 8 != params.getLong("scrypt_r") ||
- 1 != params.getLong("scrypt_p") ||
- 20000 != params.getLong("PBKDF2_rounds_2")) {
- throw new FxAccountClientMalformedAuthException("malformed passwordStretching parameters: '" + params.toJSONString() + "'.");
- }
- }
-
- /**
- * All state is written in this method.
- */
- protected AuthState authStateFromParameters(String srpToken, String mainSalt, String srpSalt, String srpB, BigInteger a) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- AuthState authState = new AuthState();
- authState.srpToken = srpToken;
- authState.mainSalt = mainSalt;
- authState.srpSalt = srpSalt;
-
- authState.x = FxAccountUtils.srpVerifierLowercaseX(email.getBytes("UTF-8"), this.stretchedPWBytes, Utils.hex2Byte(srpSalt, FxAccountUtils.SALT_LENGTH_BYTES));
-
- authState.A = g.modPow(a, N);
- String srpA = FxAccountUtils.hexModN(authState.A, N);
- BigInteger B = new BigInteger(srpB, 16);
-
- byte[] srpABytes = Utils.hex2Byte(srpA, modNLengthBytes);
- byte[] srpBBytes = Utils.hex2Byte(srpB, modNLengthBytes);
-
- // u = H(pad(A) | pad(B))
- byte[] uBytes = Utils.sha256(Utils.concatAll(
- srpABytes,
- srpBBytes));
- BigInteger u = new BigInteger(Utils.byte2Hex(uBytes, FxAccountUtils.HASH_LENGTH_HEX), 16);
-
- // S = (B - k*g^x)^(a u*x) % N
- // k = H(pad(N) | pad(g))
- int byteLength = (N.bitLength() + 7) / 8;
- byte[] kBytes = Utils.sha256(Utils.concatAll(
- Utils.hex2Byte(N.toString(16), byteLength),
- Utils.hex2Byte(g.toString(16), byteLength)));
- BigInteger k = new BigInteger(Utils.byte2Hex(kBytes, FxAccountUtils.HASH_LENGTH_HEX), 16);
-
- BigInteger base = B.subtract(k.multiply(g.modPow(authState.x, N)).mod(N)).mod(N);
- BigInteger pow = a.add(u.multiply(authState.x));
- BigInteger S = base.modPow(pow, N);
- String srpS = FxAccountUtils.hexModN(S, N);
-
- byte[] sBytes = Utils.hex2Byte(srpS, modNLengthBytes);
-
- // M = H(pad(A) | pad(B) | pad(S))
- authState.Mbytes = Utils.sha256(Utils.concatAll(
- srpABytes,
- srpBBytes,
- sBytes));
-
- // K = H(pad(S))
- authState.Kbytes = Utils.sha256(sBytes);
-
- return authState;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public JSONObject getAuthFinishBody() throws FxAccountClientException {
- if (internalAuthState == null) {
- throw new FxAccountClientException("auth must be successfully written before calling getAuthFinishBody.");
- }
- JSONObject body = new JSONObject();
- body.put("srpToken", internalAuthState.srpToken);
- body.put("A", FxAccountUtils.hexModN(internalAuthState.A, N));
- body.put("M", Utils.byte2Hex(internalAuthState.Mbytes, FxAccountUtils.HASH_LENGTH_HEX));
- return body;
- }
-
- @Override
- public byte[] getSharedBytes() throws FxAccountClientException {
- if (internalAuthState == null) {
- throw new FxAccountClientException("auth must be successfully finished before calling getSharedBytes.");
- }
- return internalAuthState.Kbytes;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount10CreateDelegate.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.background.fxa;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.background.fxa.FxAccountClient10.CreateDelegate;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.net.SRPConstants;
-
-public class FxAccount10CreateDelegate implements CreateDelegate {
- protected final String email;
- protected final String mainSalt;
- protected final String srpSalt;
- protected final BigInteger v;
-
- public FxAccount10CreateDelegate(String email, byte[] stretchedPWBytes, String mainSalt, String srpSalt) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- this.email = email;
- this.mainSalt = mainSalt;
- this.srpSalt = srpSalt;
- byte[] srpSaltBytes = Utils.hex2Byte(srpSalt, FxAccountUtils.SALT_LENGTH_BYTES);
- this.v = FxAccountUtils.srpVerifierLowercaseV(email.getBytes("UTF-8"), stretchedPWBytes, srpSaltBytes, SRPConstants._2048.g, SRPConstants._2048.N);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public JSONObject getCreateBody() throws FxAccountClientException {
- final JSONObject body = new JSONObject();
- try {
- body.put("email", FxAccountUtils.bytes(email));
- } catch (UnsupportedEncodingException e) {
- throw new FxAccountClientException(e);
- }
-
- final JSONObject stretching = new JSONObject();
- stretching.put("type", "PBKDF2/scrypt/PBKDF2/v1");
- stretching.put("PBKDF2_rounds_1", 20000);
- stretching.put("scrypt_N", 65536);
- stretching.put("scrypt_r", 8);
- stretching.put("scrypt_p", 1);
- stretching.put("PBKDF2_rounds_2", 20000);
- stretching.put("salt", mainSalt);
- body.put("passwordStretching", stretching);
-
- final JSONObject srp = new JSONObject();
- srp.put("type", "SRP-6a/SHA256/2048/v1");
- srp.put("verifier", FxAccountUtils.hexModN(v, SRPConstants._2048.N));
- srp.put("salt", srpSalt);
- body.put("srp", srp);
- return body;
- }
-}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java
@@ -1,22 +1,21 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.background.fxa;
+import org.json.simple.JSONObject;
+import org.mozilla.gecko.sync.Utils;
+
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.background.fxa.FxAccountClient10.CreateDelegate;
-import org.mozilla.gecko.sync.Utils;
-
-public class FxAccount20CreateDelegate implements CreateDelegate {
+public class FxAccount20CreateDelegate {
protected final byte[] emailUTF8;
protected final byte[] authPW;
protected final boolean preVerified;
/**
* Make a new "create account" delegate.
*
* @param emailUTF8
@@ -31,17 +30,16 @@ public class FxAccount20CreateDelegate i
*/
public FxAccount20CreateDelegate(byte[] emailUTF8, byte[] quickStretchedPW, boolean preVerified) throws UnsupportedEncodingException, GeneralSecurityException {
this.emailUTF8 = emailUTF8;
this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW);
this.preVerified = preVerified;
}
@SuppressWarnings("unchecked")
- @Override
public JSONObject getCreateBody() throws FxAccountClientException {
final JSONObject body = new JSONObject();
try {
body.put("email", new String(emailUTF8, "UTF-8"));
body.put("authPW", Utils.byte2Hex(authPW));
if (preVerified) {
// Production endpoints do not allow preVerified; this assumes we only
// set it when it's okay to send it.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java
@@ -3,34 +3,32 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.background.fxa;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import org.json.simple.JSONObject;
-import org.mozilla.gecko.background.fxa.FxAccountClient10.CreateDelegate;
import org.mozilla.gecko.sync.Utils;
/**
* An abstraction around providing an email and authorization token to the auth
* server.
*/
-public class FxAccount20LoginDelegate implements CreateDelegate {
+public class FxAccount20LoginDelegate {
protected final byte[] emailUTF8;
protected final byte[] authPW;
public FxAccount20LoginDelegate(byte[] emailUTF8, byte[] quickStretchedPW) throws UnsupportedEncodingException, GeneralSecurityException {
this.emailUTF8 = emailUTF8;
this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW);
}
@SuppressWarnings("unchecked")
- @Override
public JSONObject getCreateBody() throws FxAccountClientException {
final JSONObject body = new JSONObject();
try {
body.put("email", new String(emailUTF8, "UTF-8"));
body.put("authPW", Utils.byte2Hex(authPW));
return body;
} catch (UnsupportedEncodingException e) {
throw new FxAccountClientException(e);
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient10.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient10.java
@@ -150,35 +150,16 @@ public class FxAccountClient10 {
*/
public interface RequestDelegate<T> {
public void handleError(Exception e);
public void handleFailure(FxAccountClientRemoteException e);
public void handleSuccess(T result);
}
/**
- * A <code>CreateDelegate</code> produces the body of a /create request.
- */
- public interface CreateDelegate {
- public JSONObject getCreateBody() throws FxAccountClientException;
- }
-
- /**
- * A <code>AuthDelegate</code> produces the bodies of an /auth/{start,finish}
- * request pair and exposes state generated by a successful response.
- */
- public interface AuthDelegate {
- public JSONObject getAuthStartBody() throws FxAccountClientException;
- public void onAuthStartResponse(ExtendedJSONObject body) throws FxAccountClientException;
- public JSONObject getAuthFinishBody() throws FxAccountClientException;
-
- public byte[] getSharedBytes() throws FxAccountClientException;
- }
-
- /**
* Thin container for two cryptographic keys.
*/
public static class TwoKeys {
public final byte[] kA;
public final byte[] wrapkB;
public TwoKeys(byte[] kA, byte[] wrapkB) {
this.kA = kA;
this.wrapkB = wrapkB;
@@ -359,152 +340,16 @@ public class FxAccountClient10 {
message = body.getString(JSON_KEY_MESSAGE);
info = body.getString(JSON_KEY_INFO);
} catch (Exception e) {
throw new FxAccountClientMalformedResponseException(response);
}
throw new FxAccountClientRemoteException(response, code, errno, error, message, info, body);
}
- public void createAccount(final String email, final byte[] stretchedPWBytes,
- final String srpSalt, final String mainSalt,
- final RequestDelegate<String> delegate) {
- try {
- createAccount(new FxAccount10CreateDelegate(email, stretchedPWBytes, srpSalt, mainSalt), delegate);
- } catch (final Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
- }
-
- protected void createAccount(final CreateDelegate createDelegate, final RequestDelegate<String> delegate) {
- JSONObject body = null;
- try {
- body = createDelegate.getCreateBody();
- } catch (FxAccountClientException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("account/create");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<String>(resource, delegate) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- String uid = body.getString("uid");
- if (uid == null) {
- delegate.handleError(new FxAccountClientException("uid must be a non-null string"));
- return;
- }
- delegate.handleSuccess(uid);
- }
- };
- post(resource, body, delegate);
- }
-
- protected void authStart(final AuthDelegate authDelegate, final RequestDelegate<AuthDelegate> delegate) {
- JSONObject body;
- try {
- body = authDelegate.getAuthStartBody();
- } catch (FxAccountClientException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("auth/start");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<AuthDelegate>(resource, delegate) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- authDelegate.onAuthStartResponse(body);
- delegate.handleSuccess(authDelegate);
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
- }
- };
- post(resource, body, delegate);
- }
-
- protected void authFinish(final AuthDelegate authDelegate, RequestDelegate<byte[]> delegate) {
- JSONObject body;
- try {
- body = authDelegate.getAuthFinishBody();
- } catch (FxAccountClientException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("auth/finish");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<byte[]>(resource, delegate) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- byte[] authToken = new byte[32];
- unbundleBody(body, authDelegate.getSharedBytes(), FxAccountUtils.KW("auth/finish"), authToken);
- delegate.handleSuccess(authToken);
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
- }
- };
- post(resource, body, delegate);
- }
-
- public void login(final String email, final byte[] stretchedPWBytes, final RequestDelegate<byte[]> delegate) {
- login(new FxAccount10AuthDelegate(email, stretchedPWBytes), delegate);
- }
-
- protected void login(final AuthDelegate authDelegate, final RequestDelegate<byte[]> delegate) {
- authStart(authDelegate, new RequestDelegate<AuthDelegate>() {
- @Override
- public void handleSuccess(AuthDelegate srpSession) {
- authFinish(srpSession, delegate);
- }
-
- @Override
- public void handleError(final Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- @Override
- public void handleFailure(final FxAccountClientRemoteException e) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- delegate.handleFailure(e);
- }
- });
- }
- });
- }
-
/**
* Don't call this directly. Use <code>unbundleBody</code> instead.
*/
protected void unbundleBytes(byte[] bundleBytes, byte[] respHMACKey, byte[] respXORKey, byte[]... rest)
throws InvalidKeyException, NoSuchAlgorithmException, FxAccountClientException {
if (bundleBytes.length < 32) {
throw new IllegalArgumentException("input bundle must include HMAC");
}