1103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai/*
2103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * Copyright 2017 The Android Open Source Project
3103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai *
4103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * Licensed under the Apache License, Version 2.0 (the "License");
5103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * you may not use this file except in compliance with the License.
6103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * You may obtain a copy of the License at
7103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai *
8103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai *      http://www.apache.org/licenses/LICENSE-2.0
9103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai *
10103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * Unless required by applicable law or agreed to in writing, software
11103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * distributed under the License is distributed on an "AS IS" BASIS,
12103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * See the License for the specific language governing permissions and
14103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai * limitations under the License.
15103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai */
16103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
17103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
18103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waipackage com.android.server.net.watchlist;
19103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
20103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport android.annotation.Nullable;
21103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport android.util.Log;
22d89243bf546501fd6105d0373754e4c62681812aRicky Waiimport android.util.proto.ProtoOutputStream;
23103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
24103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport com.android.internal.annotations.VisibleForTesting;
25103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport com.android.internal.util.HexDump;
26d89243bf546501fd6105d0373754e4c62681812aRicky Waiimport com.android.service.NetworkWatchlistReportProto;
27d89243bf546501fd6105d0373754e4c62681812aRicky Waiimport com.android.service.NetworkWatchlistAppResultProto;
28103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
29d89243bf546501fd6105d0373754e4c62681812aRicky Waiimport java.io.ByteArrayOutputStream;
30103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport java.util.ArrayList;
31103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport java.util.Collections;
32103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport java.util.List;
33103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiimport java.util.Map;
34103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
35103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai/**
36d89243bf546501fd6105d0373754e4c62681812aRicky Wai * Helper class to encode and generate serialized DP encoded watchlist proto report.
37103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai */
38103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Waiclass ReportEncoder {
39103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
40103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    private static final String TAG = "ReportEncoder";
41103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
42103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    // Report version number, as file format / parameters can be changed in later version, we need
43103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    // to have versioning on watchlist report format
44d89243bf546501fd6105d0373754e4c62681812aRicky Wai    private static final int REPORT_VERSION = 1;
45103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
46103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    private static final int WATCHLIST_HASH_SIZE = 32;
47103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
48103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    /**
49103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     * Apply DP on watchlist results, and generate a serialized watchlist report ready to store
50103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     * in DropBox.
51103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     */
529973345b15fb0e45c89ba87e76ed727147215d7fRicky Wai    @Nullable
53103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    static byte[] encodeWatchlistReport(WatchlistConfig config, byte[] userSecret,
54103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
55103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        Map<String, Boolean> resultMap = PrivacyUtils.createDpEncodedReportMap(
56103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai                config.isConfigSecure(), userSecret, appDigestList, aggregatedResult);
57103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        return serializeReport(config, resultMap);
58103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    }
59103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
60103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    /**
61d89243bf546501fd6105d0373754e4c62681812aRicky Wai     * Convert DP encoded watchlist report into proto format.
62103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     *
63103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     * @param encodedReportMap DP encoded watchlist report.
64d89243bf546501fd6105d0373754e4c62681812aRicky Wai     * @return Watchlist report in proto format, which will be shared in Dropbox. Null if
65103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     * watchlist report cannot be generated.
66103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai     */
67103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    @Nullable
68103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    @VisibleForTesting
69103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    static byte[] serializeReport(WatchlistConfig config,
70103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            Map<String, Boolean> encodedReportMap) {
71103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        // TODO: Handle watchlist config changed case
72103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        final byte[] watchlistHash = config.getWatchlistConfigHash();
73103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        if (watchlistHash == null) {
74103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            Log.e(TAG, "No watchlist hash");
75103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            return null;
76103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        }
77103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        if (watchlistHash.length != WATCHLIST_HASH_SIZE) {
78103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            Log.e(TAG, "Unexpected hash length");
79103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            return null;
80103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        }
81d89243bf546501fd6105d0373754e4c62681812aRicky Wai        final ByteArrayOutputStream reportOutputStream = new ByteArrayOutputStream();
82d89243bf546501fd6105d0373754e4c62681812aRicky Wai        final ProtoOutputStream proto = new ProtoOutputStream(reportOutputStream);
83103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
84103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        // Set report version to report
85d89243bf546501fd6105d0373754e4c62681812aRicky Wai        proto.write(NetworkWatchlistReportProto.REPORT_VERSION, REPORT_VERSION);
86d89243bf546501fd6105d0373754e4c62681812aRicky Wai        proto.write(NetworkWatchlistReportProto.WATCHLIST_CONFIG_HASH,
87d89243bf546501fd6105d0373754e4c62681812aRicky Wai                HexDump.toHexString(watchlistHash));
88103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai
89103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        // Set app digest, encoded_isPha pair to report
90d89243bf546501fd6105d0373754e4c62681812aRicky Wai        for (Map.Entry<String, Boolean> entry : encodedReportMap.entrySet()) {
91d89243bf546501fd6105d0373754e4c62681812aRicky Wai            String key = entry.getKey();
92103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai            byte[] digest = HexDump.hexStringToByteArray(key);
93d89243bf546501fd6105d0373754e4c62681812aRicky Wai            boolean encodedResult = entry.getValue();
94d89243bf546501fd6105d0373754e4c62681812aRicky Wai            long token = proto.start(NetworkWatchlistReportProto.APP_RESULT);
95d89243bf546501fd6105d0373754e4c62681812aRicky Wai            proto.write(NetworkWatchlistAppResultProto.APP_DIGEST, key);
96d89243bf546501fd6105d0373754e4c62681812aRicky Wai            proto.write(NetworkWatchlistAppResultProto.ENCODED_RESULT, encodedResult);
97d89243bf546501fd6105d0373754e4c62681812aRicky Wai            proto.end(token);
98103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai        }
99d89243bf546501fd6105d0373754e4c62681812aRicky Wai        proto.flush();
100d89243bf546501fd6105d0373754e4c62681812aRicky Wai        return reportOutputStream.toByteArray();
101103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai    }
102103ebf5bc56b25c8b4d77daa82692a026da32e85Ricky Wai}
103