diff options
Diffstat (limited to 'mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java')
-rw-r--r-- | mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java | 217 |
1 files changed, 0 insertions, 217 deletions
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java deleted file mode 100644 index 2d29725a0..000000000 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java +++ /dev/null @@ -1,217 +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.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import org.mozilla.gecko.AppConstants; -import org.mozilla.gecko.R; -import org.mozilla.gecko.background.common.log.Logger; -import org.mozilla.gecko.background.nativecode.NativeCrypto; -import org.mozilla.gecko.sync.Utils; -import org.mozilla.gecko.sync.crypto.HKDF; -import org.mozilla.gecko.sync.crypto.KeyBundle; -import org.mozilla.gecko.sync.crypto.PBKDF2; - -import android.content.Context; - -public class FxAccountUtils { - private static final String LOG_TAG = FxAccountUtils.class.getSimpleName(); - - public static final int SALT_LENGTH_BYTES = 32; - public static final int SALT_LENGTH_HEX = 2 * SALT_LENGTH_BYTES; - - public static final int HASH_LENGTH_BYTES = 16; - public static final int HASH_LENGTH_HEX = 2 * HASH_LENGTH_BYTES; - - public static final int CRYPTO_KEY_LENGTH_BYTES = 32; - public static final int CRYPTO_KEY_LENGTH_HEX = 2 * CRYPTO_KEY_LENGTH_BYTES; - - public static final String KW_VERSION_STRING = "identity.mozilla.com/picl/v1/"; - - public static final int NUMBER_OF_QUICK_STRETCH_ROUNDS = 1000; - - // For extra debugging. Not final so it can be changed from Fennec, or from - // an add-on. - public static boolean LOG_PERSONAL_INFORMATION = false; - - public static void pii(String tag, String message) { - if (FxAccountUtils.LOG_PERSONAL_INFORMATION) { - Logger.info(tag, "$$FxA PII$$: " + message); - } - } - - public static String bytes(String string) throws UnsupportedEncodingException { - return Utils.byte2Hex(string.getBytes("UTF-8")); - } - - public static byte[] KW(String name) throws UnsupportedEncodingException { - return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8")); - } - - public static byte[] KWE(String name, byte[] emailUTF8) throws UnsupportedEncodingException { - return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8"), - ":".getBytes("UTF-8"), - emailUTF8); - } - - /** - * Calculate the SRP verifier <tt>x</tt> value. - */ - public static BigInteger srpVerifierLowercaseX(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes("UTF-8"), srpPWBytes)); - byte[] outer = Utils.sha256(Utils.concatAll(srpSaltBytes, inner)); - return new BigInteger(1, outer); - } - - /** - * Calculate the SRP verifier <tt>v</tt> value. - */ - public static BigInteger srpVerifierLowercaseV(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes, BigInteger g, BigInteger N) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - BigInteger x = srpVerifierLowercaseX(emailUTF8, srpPWBytes, srpSaltBytes); - BigInteger v = g.modPow(x, N); - return v; - } - - /** - * Format x modulo N in hexadecimal, using as many characters as N takes (in hexadecimal). - * @param x to format. - * @param N modulus. - * @return x modulo N in hexadecimal. - */ - public static String hexModN(BigInteger x, BigInteger N) { - int byteLength = (N.bitLength() + 7) / 8; - int hexLength = 2 * byteLength; - return Utils.byte2Hex(Utils.hex2Byte((x.mod(N)).toString(16), byteLength), hexLength); - } - - /** - * The first engineering milestone of PICL (Profile-in-the-Cloud) was - * comprised of Sync 1.1 fronted by a Firefox Account. The sync key was - * generated from the Firefox Account password-derived kB value using this - * method. - */ - public static KeyBundle generateSyncKeyBundle(final byte[] kB) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { - byte[] encryptionKey = new byte[32]; - byte[] hmacKey = new byte[32]; - byte[] derived = HKDF.derive(kB, new byte[0], FxAccountUtils.KW("oldsync"), 2*32); - System.arraycopy(derived, 0*32, encryptionKey, 0, 1*32); - System.arraycopy(derived, 1*32, hmacKey, 0, 1*32); - return new KeyBundle(encryptionKey, hmacKey); - } - - /** - * Firefox Accounts are password authenticated, but clients should not store - * the plain-text password for any amount of time. Equivalent, but slightly - * more secure, is the quickly client-side stretched password. - * <p> - * We separate this since multiple login-time operations want it, and the - * PBKDF2 operation is computationally expensive. - */ - public static byte[] generateQuickStretchedPW(byte[] emailUTF8, byte[] passwordUTF8) throws GeneralSecurityException, UnsupportedEncodingException { - byte[] S = FxAccountUtils.KWE("quickStretch", emailUTF8); - try { - return NativeCrypto.pbkdf2SHA256(passwordUTF8, S, NUMBER_OF_QUICK_STRETCH_ROUNDS, 32); - } catch (final LinkageError e) { - // This will throw UnsatisfiedLinkError (missing mozglue) the first time it is called, and - // ClassNotDefFoundError, for the uninitialized NativeCrypto class, each subsequent time this - // is called; LinkageError is their common ancestor. - Logger.warn(LOG_TAG, "Got throwable stretching password using native pbkdf2SHA256 " + - "implementation; ignoring and using Java implementation.", e); - return PBKDF2.pbkdf2SHA256(passwordUTF8, S, NUMBER_OF_QUICK_STRETCH_ROUNDS, 32); - } - } - - /** - * The password-derived credential used to authenticate to the Firefox Account - * auth server. - */ - public static byte[] generateAuthPW(byte[] quickStretchedPW) throws GeneralSecurityException, UnsupportedEncodingException { - return HKDF.derive(quickStretchedPW, new byte[0], FxAccountUtils.KW("authPW"), 32); - } - - /** - * The password-derived credential used to unwrap keys managed by the Firefox - * Account auth server. - */ - public static byte[] generateUnwrapBKey(byte[] quickStretchedPW) throws GeneralSecurityException, UnsupportedEncodingException { - return HKDF.derive(quickStretchedPW, new byte[0], FxAccountUtils.KW("unwrapBkey"), 32); - } - - public static byte[] unwrapkB(byte[] unwrapkB, byte[] wrapkB) { - if (unwrapkB == null) { - throw new IllegalArgumentException("unwrapkB must not be null"); - } - if (wrapkB == null) { - throw new IllegalArgumentException("wrapkB must not be null"); - } - if (unwrapkB.length != CRYPTO_KEY_LENGTH_BYTES || wrapkB.length != CRYPTO_KEY_LENGTH_BYTES) { - throw new IllegalArgumentException("unwrapkB and wrapkB must be " + CRYPTO_KEY_LENGTH_BYTES + " bytes long"); - } - byte[] kB = new byte[CRYPTO_KEY_LENGTH_BYTES]; - for (int i = 0; i < wrapkB.length; i++) { - kB[i] = (byte) (wrapkB[i] ^ unwrapkB[i]); - } - return kB; - } - - /** - * The token server accepts an X-Client-State header, which is the - * lowercase-hex-encoded first 16 bytes of the SHA-256 hash of the - * bytes of kB. - * @param kB a byte array, expected to be 32 bytes long. - * @return a 32-character string. - * @throws NoSuchAlgorithmException - */ - public static String computeClientState(byte[] kB) throws NoSuchAlgorithmException { - if (kB == null || - kB.length != 32) { - throw new IllegalArgumentException("Unexpected kB."); - } - byte[] sha256 = Utils.sha256(kB); - byte[] truncated = new byte[16]; - System.arraycopy(sha256, 0, truncated, 0, 16); - return Utils.byte2Hex(truncated); // This is automatically lowercase. - } - - /** - * Given an endpoint, calculate the corresponding BrowserID audience. - * <p> - * This is the domain, in web parlance. - * - * @param serverURI endpoint. - * @return BrowserID audience. - * @throws URISyntaxException - */ - public static String getAudienceForURL(String serverURI) throws URISyntaxException { - URI uri = new URI(serverURI); - return new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), null, null, null).toString(); - } - - public static String defaultClientName(Context context) { - String name = AppConstants.MOZ_APP_DISPLAYNAME; // The display name is never translated. - // Change "Firefox Aurora" or similar into "Aurora". - if (name.contains("Aurora")) { - name = "Aurora"; - } else if (name.contains("Beta")) { - name = "Beta"; - } else if (name.contains("Nightly")) { - name = "Nightly"; - } - return context.getResources().getString(R.string.sync_default_client_name, name, android.os.Build.MODEL); - } -} |