1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package com.android.server.net.watchlist; 19 20 import android.annotation.Nullable; 21 import android.util.Log; 22 import android.util.proto.ProtoOutputStream; 23 24 import com.android.internal.annotations.VisibleForTesting; 25 import com.android.internal.util.HexDump; 26 import com.android.service.NetworkWatchlistReportProto; 27 import com.android.service.NetworkWatchlistAppResultProto; 28 29 import java.io.ByteArrayOutputStream; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Map; 34 35 /** 36 * Helper class to encode and generate serialized DP encoded watchlist proto report. 37 */ 38 class ReportEncoder { 39 40 private static final String TAG = "ReportEncoder"; 41 42 // Report version number, as file format / parameters can be changed in later version, we need 43 // to have versioning on watchlist report format 44 private static final int REPORT_VERSION = 1; 45 46 private static final int WATCHLIST_HASH_SIZE = 32; 47 48 /** 49 * Apply DP on watchlist results, and generate a serialized watchlist report ready to store 50 * in DropBox. 51 */ 52 @Nullable encodeWatchlistReport(WatchlistConfig config, byte[] userSecret, List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult)53 static byte[] encodeWatchlistReport(WatchlistConfig config, byte[] userSecret, 54 List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) { 55 Map<String, Boolean> resultMap = PrivacyUtils.createDpEncodedReportMap( 56 config.isConfigSecure(), userSecret, appDigestList, aggregatedResult); 57 return serializeReport(config, resultMap); 58 } 59 60 /** 61 * Convert DP encoded watchlist report into proto format. 62 * 63 * @param encodedReportMap DP encoded watchlist report. 64 * @return Watchlist report in proto format, which will be shared in Dropbox. Null if 65 * watchlist report cannot be generated. 66 */ 67 @Nullable 68 @VisibleForTesting serializeReport(WatchlistConfig config, Map<String, Boolean> encodedReportMap)69 static byte[] serializeReport(WatchlistConfig config, 70 Map<String, Boolean> encodedReportMap) { 71 // TODO: Handle watchlist config changed case 72 final byte[] watchlistHash = config.getWatchlistConfigHash(); 73 if (watchlistHash == null) { 74 Log.e(TAG, "No watchlist hash"); 75 return null; 76 } 77 if (watchlistHash.length != WATCHLIST_HASH_SIZE) { 78 Log.e(TAG, "Unexpected hash length"); 79 return null; 80 } 81 final ByteArrayOutputStream reportOutputStream = new ByteArrayOutputStream(); 82 final ProtoOutputStream proto = new ProtoOutputStream(reportOutputStream); 83 84 // Set report version to report 85 proto.write(NetworkWatchlistReportProto.REPORT_VERSION, REPORT_VERSION); 86 proto.write(NetworkWatchlistReportProto.WATCHLIST_CONFIG_HASH, 87 HexDump.toHexString(watchlistHash)); 88 89 // Set app digest, encoded_isPha pair to report 90 for (Map.Entry<String, Boolean> entry : encodedReportMap.entrySet()) { 91 String key = entry.getKey(); 92 byte[] digest = HexDump.hexStringToByteArray(key); 93 boolean encodedResult = entry.getValue(); 94 long token = proto.start(NetworkWatchlistReportProto.APP_RESULT); 95 proto.write(NetworkWatchlistAppResultProto.APP_DIGEST, key); 96 proto.write(NetworkWatchlistAppResultProto.ENCODED_RESULT, encodedResult); 97 proto.end(token); 98 } 99 proto.flush(); 100 return reportOutputStream.toByteArray(); 101 } 102 } 103