Loading services/core/java/com/android/server/net/watchlist/HarmfulCrcs.java 0 → 100644 +63 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.net.watchlist; import com.android.internal.util.HexDump; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Helper class to store a set of harmful CRC32s in memory. * TODO: Optimize memory usage using int array with binary search. */ class HarmfulCrcs { private final Set<Integer> mCrcSet; HarmfulCrcs(List<byte[]> digests) { final HashSet<Integer> crcSet = new HashSet<>(); final int size = digests.size(); for (int i = 0; i < size; i++) { byte[] bytes = digests.get(i); if (bytes.length <= 4) { int crc = 0; for (byte b : bytes) { // Remember byte is signed crc = (crc << 8) | (b & 0xff); } crcSet.add(crc); } } mCrcSet = Collections.unmodifiableSet(crcSet); } public boolean contains(int crc) { return mCrcSet.contains(crc); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { for (int crc : mCrcSet) { pw.println(HexDump.toHexString(crc)); } pw.println(""); } } services/core/java/com/android/server/net/watchlist/WatchlistConfig.java +14 −19 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.net.watchlist; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.FileUtils; import android.os.FileUtils; import android.util.AtomicFile; import android.util.Log; import android.util.Log; import android.util.Slog; import android.util.Slog; import android.util.Xml; import android.util.Xml; Loading Loading @@ -66,11 +65,11 @@ class WatchlistConfig { } } private static class CrcShaDigests { private static class CrcShaDigests { final HarmfulDigests crc32Digests; public final HarmfulCrcs crc32s; final HarmfulDigests sha256Digests; public final HarmfulDigests sha256Digests; public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) { CrcShaDigests(HarmfulCrcs crc32s, HarmfulDigests sha256Digests) { this.crc32Digests = crc32Digests; this.crc32s = crc32s; this.sha256Digests = sha256Digests; this.sha256Digests = sha256Digests; } } } } Loading Loading @@ -140,9 +139,9 @@ class WatchlistConfig { } } } } parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_CONFIG); parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_CONFIG); mDomainDigests = new CrcShaDigests(new HarmfulDigests(crc32DomainList), mDomainDigests = new CrcShaDigests(new HarmfulCrcs(crc32DomainList), new HarmfulDigests(sha256DomainList)); new HarmfulDigests(sha256DomainList)); mIpDigests = new CrcShaDigests(new HarmfulDigests(crc32IpList), mIpDigests = new CrcShaDigests(new HarmfulCrcs(crc32IpList), new HarmfulDigests(sha256IpList)); new HarmfulDigests(sha256IpList)); Log.i(TAG, "Reload watchlist done"); Log.i(TAG, "Reload watchlist done"); } catch (IllegalStateException | NullPointerException | NumberFormatException | } catch (IllegalStateException | NullPointerException | NumberFormatException | Loading Loading @@ -171,8 +170,8 @@ class WatchlistConfig { return false; return false; } } // First it does a quick CRC32 check. // First it does a quick CRC32 check. final byte[] crc32 = getCrc32(domain); final int crc32 = getCrc32(domain); if (!domainDigests.crc32Digests.contains(crc32)) { if (!domainDigests.crc32s.contains(crc32)) { return false; return false; } } // Now we do a slow SHA256 check. // Now we do a slow SHA256 check. Loading @@ -187,8 +186,8 @@ class WatchlistConfig { return false; return false; } } // First it does a quick CRC32 check. // First it does a quick CRC32 check. final byte[] crc32 = getCrc32(ip); final int crc32 = getCrc32(ip); if (!ipDigests.crc32Digests.contains(crc32)) { if (!ipDigests.crc32s.contains(crc32)) { return false; return false; } } // Now we do a slow SHA256 check. // Now we do a slow SHA256 check. Loading @@ -198,15 +197,11 @@ class WatchlistConfig { /** Get CRC32 of a string /** Get CRC32 of a string * * TODO: Review if we should use CRC32 or other algorithms */ */ private byte[] getCrc32(String str) { private int getCrc32(String str) { final CRC32 crc = new CRC32(); final CRC32 crc = new CRC32(); crc.update(str.getBytes()); crc.update(str.getBytes()); final long tmp = crc.getValue(); return (int) crc.getValue(); return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255), (byte) (tmp >> 8 & 255), (byte) (tmp & 255)}; } } /** Get SHA256 of a string */ /** Get SHA256 of a string */ Loading Loading @@ -279,7 +274,7 @@ class WatchlistConfig { pw.println("Domain CRC32 digest list:"); pw.println("Domain CRC32 digest list:"); // mDomainDigests won't go from non-null to null so it's safe // mDomainDigests won't go from non-null to null so it's safe if (mDomainDigests != null) { if (mDomainDigests != null) { mDomainDigests.crc32Digests.dump(fd, pw, args); mDomainDigests.crc32s.dump(fd, pw, args); } } pw.println("Domain SHA256 digest list:"); pw.println("Domain SHA256 digest list:"); if (mDomainDigests != null) { if (mDomainDigests != null) { Loading @@ -288,7 +283,7 @@ class WatchlistConfig { pw.println("Ip CRC32 digest list:"); pw.println("Ip CRC32 digest list:"); // mIpDigests won't go from non-null to null so it's safe // mIpDigests won't go from non-null to null so it's safe if (mIpDigests != null) { if (mIpDigests != null) { mIpDigests.crc32Digests.dump(fd, pw, args); mIpDigests.crc32s.dump(fd, pw, args); } } pw.println("Ip SHA256 digest list:"); pw.println("Ip SHA256 digest list:"); if (mIpDigests != null) { if (mIpDigests != null) { Loading services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulCrcsTests.java 0 → 100644 +60 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.net.watchlist; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; /** * runtest frameworks-services -c com.android.server.net.watchlist.HarmfulCrcTests */ @RunWith(AndroidJUnit4.class) @SmallTest public class HarmfulCrcsTests { private static final byte[] TEST_DIGEST = HexDump.hexStringToByteArray("AABBCCDD"); @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testHarmfulCrcs_setAndContains() throws Exception { HarmfulCrcs harmfulCrcs = new HarmfulCrcs( Arrays.asList(new byte[][] {TEST_DIGEST})); assertTrue(harmfulCrcs.contains(0xaabbccdd)); assertFalse(harmfulCrcs.contains(0xbbbbbbbb)); assertFalse(harmfulCrcs.contains(0x01020304)); assertFalse(harmfulCrcs.contains(0xddccbbaa)); } } Loading
services/core/java/com/android/server/net/watchlist/HarmfulCrcs.java 0 → 100644 +63 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.net.watchlist; import com.android.internal.util.HexDump; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Helper class to store a set of harmful CRC32s in memory. * TODO: Optimize memory usage using int array with binary search. */ class HarmfulCrcs { private final Set<Integer> mCrcSet; HarmfulCrcs(List<byte[]> digests) { final HashSet<Integer> crcSet = new HashSet<>(); final int size = digests.size(); for (int i = 0; i < size; i++) { byte[] bytes = digests.get(i); if (bytes.length <= 4) { int crc = 0; for (byte b : bytes) { // Remember byte is signed crc = (crc << 8) | (b & 0xff); } crcSet.add(crc); } } mCrcSet = Collections.unmodifiableSet(crcSet); } public boolean contains(int crc) { return mCrcSet.contains(crc); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { for (int crc : mCrcSet) { pw.println(HexDump.toHexString(crc)); } pw.println(""); } }
services/core/java/com/android/server/net/watchlist/WatchlistConfig.java +14 −19 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.server.net.watchlist; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.FileUtils; import android.os.FileUtils; import android.util.AtomicFile; import android.util.Log; import android.util.Log; import android.util.Slog; import android.util.Slog; import android.util.Xml; import android.util.Xml; Loading Loading @@ -66,11 +65,11 @@ class WatchlistConfig { } } private static class CrcShaDigests { private static class CrcShaDigests { final HarmfulDigests crc32Digests; public final HarmfulCrcs crc32s; final HarmfulDigests sha256Digests; public final HarmfulDigests sha256Digests; public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) { CrcShaDigests(HarmfulCrcs crc32s, HarmfulDigests sha256Digests) { this.crc32Digests = crc32Digests; this.crc32s = crc32s; this.sha256Digests = sha256Digests; this.sha256Digests = sha256Digests; } } } } Loading Loading @@ -140,9 +139,9 @@ class WatchlistConfig { } } } } parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_CONFIG); parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_CONFIG); mDomainDigests = new CrcShaDigests(new HarmfulDigests(crc32DomainList), mDomainDigests = new CrcShaDigests(new HarmfulCrcs(crc32DomainList), new HarmfulDigests(sha256DomainList)); new HarmfulDigests(sha256DomainList)); mIpDigests = new CrcShaDigests(new HarmfulDigests(crc32IpList), mIpDigests = new CrcShaDigests(new HarmfulCrcs(crc32IpList), new HarmfulDigests(sha256IpList)); new HarmfulDigests(sha256IpList)); Log.i(TAG, "Reload watchlist done"); Log.i(TAG, "Reload watchlist done"); } catch (IllegalStateException | NullPointerException | NumberFormatException | } catch (IllegalStateException | NullPointerException | NumberFormatException | Loading Loading @@ -171,8 +170,8 @@ class WatchlistConfig { return false; return false; } } // First it does a quick CRC32 check. // First it does a quick CRC32 check. final byte[] crc32 = getCrc32(domain); final int crc32 = getCrc32(domain); if (!domainDigests.crc32Digests.contains(crc32)) { if (!domainDigests.crc32s.contains(crc32)) { return false; return false; } } // Now we do a slow SHA256 check. // Now we do a slow SHA256 check. Loading @@ -187,8 +186,8 @@ class WatchlistConfig { return false; return false; } } // First it does a quick CRC32 check. // First it does a quick CRC32 check. final byte[] crc32 = getCrc32(ip); final int crc32 = getCrc32(ip); if (!ipDigests.crc32Digests.contains(crc32)) { if (!ipDigests.crc32s.contains(crc32)) { return false; return false; } } // Now we do a slow SHA256 check. // Now we do a slow SHA256 check. Loading @@ -198,15 +197,11 @@ class WatchlistConfig { /** Get CRC32 of a string /** Get CRC32 of a string * * TODO: Review if we should use CRC32 or other algorithms */ */ private byte[] getCrc32(String str) { private int getCrc32(String str) { final CRC32 crc = new CRC32(); final CRC32 crc = new CRC32(); crc.update(str.getBytes()); crc.update(str.getBytes()); final long tmp = crc.getValue(); return (int) crc.getValue(); return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255), (byte) (tmp >> 8 & 255), (byte) (tmp & 255)}; } } /** Get SHA256 of a string */ /** Get SHA256 of a string */ Loading Loading @@ -279,7 +274,7 @@ class WatchlistConfig { pw.println("Domain CRC32 digest list:"); pw.println("Domain CRC32 digest list:"); // mDomainDigests won't go from non-null to null so it's safe // mDomainDigests won't go from non-null to null so it's safe if (mDomainDigests != null) { if (mDomainDigests != null) { mDomainDigests.crc32Digests.dump(fd, pw, args); mDomainDigests.crc32s.dump(fd, pw, args); } } pw.println("Domain SHA256 digest list:"); pw.println("Domain SHA256 digest list:"); if (mDomainDigests != null) { if (mDomainDigests != null) { Loading @@ -288,7 +283,7 @@ class WatchlistConfig { pw.println("Ip CRC32 digest list:"); pw.println("Ip CRC32 digest list:"); // mIpDigests won't go from non-null to null so it's safe // mIpDigests won't go from non-null to null so it's safe if (mIpDigests != null) { if (mIpDigests != null) { mIpDigests.crc32Digests.dump(fd, pw, args); mIpDigests.crc32s.dump(fd, pw, args); } } pw.println("Ip SHA256 digest list:"); pw.println("Ip SHA256 digest list:"); if (mIpDigests != null) { if (mIpDigests != null) { Loading
services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulCrcsTests.java 0 → 100644 +60 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.net.watchlist; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; /** * runtest frameworks-services -c com.android.server.net.watchlist.HarmfulCrcTests */ @RunWith(AndroidJUnit4.class) @SmallTest public class HarmfulCrcsTests { private static final byte[] TEST_DIGEST = HexDump.hexStringToByteArray("AABBCCDD"); @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testHarmfulCrcs_setAndContains() throws Exception { HarmfulCrcs harmfulCrcs = new HarmfulCrcs( Arrays.asList(new byte[][] {TEST_DIGEST})); assertTrue(harmfulCrcs.contains(0xaabbccdd)); assertFalse(harmfulCrcs.contains(0xbbbbbbbb)); assertFalse(harmfulCrcs.contains(0x01020304)); assertFalse(harmfulCrcs.contains(0xddccbbaa)); } }