mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 955808 - Follow-up: Fix bustage. r=me
This commit is contained in:
parent
a1851de7a1
commit
5400cefddd
@ -0,0 +1,40 @@
|
||||
/* 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.security.GeneralSecurityException;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class FxAccount20CreateDelegate extends FxAccount20LoginDelegate {
|
||||
protected final boolean preVerified;
|
||||
|
||||
/**
|
||||
* Make a new "create account" delegate.
|
||||
*
|
||||
* @param emailUTF8
|
||||
* email as UTF-8 bytes.
|
||||
* @param passwordUTF8
|
||||
* password as UTF-8 bytes.
|
||||
* @param preVerified
|
||||
* true if account should be marked already verified; only effective
|
||||
* for non-production auth servers.
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
public FxAccount20CreateDelegate(byte[] emailUTF8, byte[] passwordUTF8, boolean preVerified) throws UnsupportedEncodingException, GeneralSecurityException {
|
||||
super(emailUTF8, passwordUTF8);
|
||||
this.preVerified = preVerified;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONObject getCreateBody() throws FxAccountClientException {
|
||||
final JSONObject body = super.getCreateBody();
|
||||
body.put("preVerified", preVerified);
|
||||
return body;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* 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.security.GeneralSecurityException;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient.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 {
|
||||
protected final byte[] emailUTF8;
|
||||
protected final byte[] passwordUTF8;
|
||||
protected final byte[] authPW;
|
||||
|
||||
public FxAccount20LoginDelegate(byte[] emailUTF8, byte[] passwordUTF8) throws UnsupportedEncodingException, GeneralSecurityException {
|
||||
this.emailUTF8 = emailUTF8;
|
||||
this.passwordUTF8 = passwordUTF8;
|
||||
this.authPW = FxAccountUtils.generateAuthPW(FxAccountUtils.generateQuickStretchedPW(emailUTF8, passwordUTF8));
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
118
mobile/android/base/background/fxa/FxAccountClient20.java
Normal file
118
mobile/android/base/background/fxa/FxAccountClient20.java
Normal file
@ -0,0 +1,118 @@
|
||||
/* 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.net.URI;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
|
||||
public class FxAccountClient20 extends FxAccountClient {
|
||||
protected static final String[] LOGIN_RESPONSE_REQUIRED_STRING_FIELDS = new String[] { JSON_KEY_UID, JSON_KEY_SESSIONTOKEN };
|
||||
protected static final String[] LOGIN_RESPONSE_REQUIRED_STRING_FIELDS_KEYS = new String[] { JSON_KEY_UID, JSON_KEY_SESSIONTOKEN, JSON_KEY_KEYFETCHTOKEN, };
|
||||
protected static final String[] LOGIN_RESPONSE_REQUIRED_BOOLEAN_FIELDS = new String[] { JSON_KEY_VERIFIED };
|
||||
|
||||
public FxAccountClient20(String serverURI, Executor executor) {
|
||||
super(serverURI, executor);
|
||||
}
|
||||
|
||||
public void createAccount(final byte[] emailUTF8, final byte[] passwordUTF8, final boolean preVerified,
|
||||
final RequestDelegate<String> delegate) {
|
||||
try {
|
||||
createAccount(new FxAccount20CreateDelegate(emailUTF8, passwordUTF8, preVerified), delegate);
|
||||
} catch (final Exception e) {
|
||||
invokeHandleError(delegate, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thin container for login response.
|
||||
*/
|
||||
public static class LoginResponse {
|
||||
public final String serverURI;
|
||||
public final String uid;
|
||||
public final byte[] sessionToken;
|
||||
public final boolean verified;
|
||||
public final byte[] keyFetchToken;
|
||||
|
||||
public LoginResponse(String serverURI, String uid, boolean verified, byte[] sessionToken, byte[] keyFetchToken) {
|
||||
// This is pretty awful.
|
||||
this.serverURI = serverURI.endsWith(VERSION_FRAGMENT) ?
|
||||
serverURI.substring(0, serverURI.length() - VERSION_FRAGMENT.length()) :
|
||||
serverURI;
|
||||
this.uid = uid;
|
||||
this.verified = verified;
|
||||
this.sessionToken = sessionToken;
|
||||
this.keyFetchToken = keyFetchToken;
|
||||
}
|
||||
}
|
||||
|
||||
public void login(final byte[] emailUTF8, final byte[] passwordUTF8,
|
||||
final RequestDelegate<LoginResponse> delegate) {
|
||||
login(emailUTF8, passwordUTF8, false, delegate);
|
||||
}
|
||||
|
||||
public void loginAndGetKeys(final byte[] emailUTF8, final byte[] passwordUTF8,
|
||||
final RequestDelegate<LoginResponse> delegate) {
|
||||
login(emailUTF8, passwordUTF8, true, delegate);
|
||||
}
|
||||
|
||||
// Public for testing only; prefer login and loginAndGetKeys (without boolean parameter).
|
||||
public void login(final byte[] emailUTF8, final byte[] passwordUTF8, final boolean getKeys,
|
||||
final RequestDelegate<LoginResponse> delegate) {
|
||||
BaseResource resource;
|
||||
JSONObject body;
|
||||
final String path = getKeys ? "account/login?keys=true" : "account/login";
|
||||
try {
|
||||
resource = new BaseResource(new URI(serverURI + path));
|
||||
body = new FxAccount20LoginDelegate(emailUTF8, passwordUTF8).getCreateBody();
|
||||
} catch (Exception e) {
|
||||
invokeHandleError(delegate, e);
|
||||
return;
|
||||
}
|
||||
|
||||
resource.delegate = new ResourceDelegate<LoginResponse>(resource, delegate) {
|
||||
@Override
|
||||
public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
|
||||
try {
|
||||
String[] requiredStringFields;
|
||||
if (!getKeys) {
|
||||
requiredStringFields = LOGIN_RESPONSE_REQUIRED_STRING_FIELDS;
|
||||
} else {
|
||||
requiredStringFields = LOGIN_RESPONSE_REQUIRED_STRING_FIELDS_KEYS;
|
||||
}
|
||||
String[] requiredBooleanFields = LOGIN_RESPONSE_REQUIRED_BOOLEAN_FIELDS;
|
||||
|
||||
body.throwIfFieldsMissingOrMisTyped(requiredStringFields, String.class);
|
||||
body.throwIfFieldsMissingOrMisTyped(requiredBooleanFields, Boolean.class);
|
||||
|
||||
LoginResponse loginResponse;
|
||||
String uid = body.getString(JSON_KEY_UID);
|
||||
boolean verified = body.getBoolean(JSON_KEY_VERIFIED);
|
||||
byte[] sessionToken = Utils.hex2Byte(body.getString(JSON_KEY_SESSIONTOKEN));
|
||||
byte[] keyFetchToken = null;
|
||||
if (getKeys) {
|
||||
keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN));
|
||||
}
|
||||
loginResponse = new LoginResponse(serverURI, uid, verified, sessionToken, keyFetchToken);
|
||||
|
||||
delegate.handleSuccess(loginResponse);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
delegate.handleError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
post(resource, body, delegate);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/* 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.sync;
|
87
mobile/android/base/sync/crypto/PBKDF2.java
Normal file
87
mobile/android/base/sync/crypto/PBKDF2.java
Normal file
@ -0,0 +1,87 @@
|
||||
/* 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.sync.crypto;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class PBKDF2 {
|
||||
public static byte[] pbkdf2SHA1(byte[] password, byte[] salt, int c, int dkLen)
|
||||
throws GeneralSecurityException {
|
||||
// Won't work on API level 8, but this is trivial.
|
||||
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
|
||||
PBEKeySpec keySpec;
|
||||
try {
|
||||
keySpec = new PBEKeySpec(new String(password, "UTF-8").toCharArray(), salt, c, dkLen * 8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new GeneralSecurityException(e);
|
||||
}
|
||||
SecretKey key = factory.generateSecret(keySpec);
|
||||
return key.getEncoded();
|
||||
}
|
||||
|
||||
public static byte[] pbkdf2SHA256(byte[] password, byte[] salt, int c, int dkLen)
|
||||
throws GeneralSecurityException {
|
||||
final String algorithm = "HmacSHA256";
|
||||
SecretKeySpec keyspec = new SecretKeySpec(password, algorithm);
|
||||
Mac prf = Mac.getInstance(algorithm);
|
||||
prf.init(keyspec);
|
||||
|
||||
int hLen = prf.getMacLength();
|
||||
int l = Math.max(dkLen, hLen);
|
||||
int r = dkLen - (l - 1) * hLen;
|
||||
byte T[] = new byte[l * hLen];
|
||||
int ti_offset = 0;
|
||||
for (int i = 1; i <= l; i++) {
|
||||
F(T, ti_offset, prf, salt, c, i);
|
||||
ti_offset += hLen;
|
||||
}
|
||||
|
||||
if (r < hLen) {
|
||||
// Incomplete last block.
|
||||
byte DK[] = new byte[dkLen];
|
||||
System.arraycopy(T, 0, DK, 0, dkLen);
|
||||
return DK;
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
private static void F(byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex) {
|
||||
final int hLen = prf.getMacLength();
|
||||
byte U_r[] = new byte[hLen];
|
||||
|
||||
// U0 = S || INT (i);
|
||||
byte U_i[] = new byte[S.length + 4];
|
||||
System.arraycopy(S, 0, U_i, 0, S.length);
|
||||
INT(U_i, S.length, blockIndex);
|
||||
|
||||
for (int i = 0; i < c; i++) {
|
||||
U_i = prf.doFinal(U_i);
|
||||
xor(U_r, U_i);
|
||||
}
|
||||
|
||||
System.arraycopy(U_r, 0, dest, offset, hLen);
|
||||
}
|
||||
|
||||
private static void xor(byte[] dest, byte[] src) {
|
||||
for (int i = 0; i < dest.length; i++) {
|
||||
dest[i] ^= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
private static void INT(byte[] dest, int offset, int i) {
|
||||
dest[offset + 0] = (byte) (i / (256 * 256 * 256));
|
||||
dest[offset + 1] = (byte) (i / (256 * 256));
|
||||
dest[offset + 2] = (byte) (i / (256));
|
||||
dest[offset + 3] = (byte) (i);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user