OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.content.browser.installedapp; | |
6 | |
7 import org.chromium.base.VisibleForTesting; | |
8 | |
9 import java.io.UnsupportedEncodingException; | |
10 import java.security.MessageDigest; | |
11 import java.security.NoSuchAlgorithmException; | |
12 import java.util.UUID; | |
13 | |
14 /** | |
15 * Helper class for retrieving a device-unique hash for an Android package name. | |
16 * | |
17 * This is used to counter a potential timing attack against the getInstalledRel atedApps API, by | |
18 * adding a pseudo-random time delay to the query. The delay is a hash of a glob ally unique | |
19 * identifier for the current browser session, and the package name, which means websites are unable | |
20 * to predict what each user's delay will be, nor compare between apps on a give n device. | |
21 * | |
22 * The salt is generated per browser session (not per query, page load, user or device) because it | |
23 * we want it to change "occasionally" -- not too frequently, but sometimes. Eac h time the salt | |
24 * changes, it gives the site another opportunity to collect data that could be averaged out to | |
25 * cancel out the random noise and find the true timing. So we don't want it cha nging too often. | |
26 * However, it does need to change periodically: because installing or uninstall ing the app creates | |
27 * a noticeable change to the timing of the operation, we need to occasionally c hange the salt to | |
28 * create plausible deniability (the attacker can't tell the difference between the salt changing | |
29 * and the app being installed/uninstalled). | |
30 */ | |
31 class PackageHash { | |
32 // Global salt string for the life of the browser process. A unique salt is generated for | |
33 // each run of the browser process that will be stable for its lifetime. | |
34 private static String sSalt; | |
35 | |
36 /** | |
37 * Returns a SHA-256 hash of the package name, truncated to a 16-bit integer . | |
38 */ | |
39 public static short hashForPackage(String packageName) { | |
40 String salt = getGlobalSalt(); | |
palmer
2017/04/07 18:56:33
Instead, use ByteArrayGenerator.getBytes (content/
Matt Giuca
2017/04/10 08:33:40
Acknowledged. Will review tomorrow (ran out of tim
Matt Giuca
2017/04/11 08:34:08
Done.
| |
41 String input = salt + ':' + packageName; | |
palmer
2017/04/07 18:56:33
It not hugely important for this low-entropy, best
Matt Giuca
2017/04/10 08:33:40
Acknowledged. Will review tomorrow.
Matt Giuca
2017/04/11 08:34:08
Done.
| |
42 MessageDigest hasher; | |
43 try { | |
44 hasher = MessageDigest.getInstance("SHA-256"); | |
45 } catch (NoSuchAlgorithmException e) { | |
46 // Should never happen. | |
47 throw new RuntimeException(e); | |
48 } | |
49 | |
50 byte[] inputBytes; | |
51 try { | |
52 inputBytes = input.getBytes("UTF-8"); | |
53 } catch (UnsupportedEncodingException e) { | |
54 // Should never happen. | |
55 throw new RuntimeException(e); | |
56 } | |
57 | |
58 byte[] digest = hasher.digest(inputBytes); | |
59 // Take just the first two bytes of the digest. | |
60 int hash = ((((int) digest[0]) & 0xff) << 8) | (((int) digest[1]) & 0xff ); | |
61 return (short) hash; | |
62 } | |
63 | |
64 /** | |
65 * Gets the global salt for the current browser session. | |
66 * | |
67 * If one does not exist, generates one using a PRNG and caches it, then ret urns it. | |
68 */ | |
69 private static String getGlobalSalt() { | |
70 if (sSalt == null) sSalt = UUID.randomUUID().toString(); | |
71 return sSalt; | |
72 } | |
73 | |
74 @VisibleForTesting | |
75 public static void setGlobalSaltForTesting(String salt) { | |
76 sSalt = salt; | |
77 } | |
78 } | |
OLD | NEW |