View Javadoc
1   package emissary.kff;
2   
3   import emissary.core.DataObjectFactory;
4   import emissary.core.IBaseDataObject;
5   import emissary.core.channels.AbstractSeekableByteChannel;
6   import emissary.core.channels.SeekableByteChannelFactory;
7   import emissary.core.channels.SeekableByteChannelHelper;
8   import emissary.test.core.junit5.UnitTest;
9   import emissary.util.io.ResourceReader;
10  
11  import jakarta.annotation.Nullable;
12  import org.apache.commons.io.IOUtils;
13  import org.junit.jupiter.api.AfterEach;
14  import org.junit.jupiter.api.BeforeEach;
15  import org.junit.jupiter.api.Test;
16  
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.nio.ByteBuffer;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
24  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
25  import static org.junit.jupiter.api.Assertions.assertEquals;
26  import static org.junit.jupiter.api.Assertions.assertFalse;
27  import static org.junit.jupiter.api.Assertions.assertNotEquals;
28  import static org.junit.jupiter.api.Assertions.assertNotNull;
29  import static org.junit.jupiter.api.Assertions.assertNull;
30  import static org.junit.jupiter.api.Assertions.assertTrue;
31  import static org.junit.jupiter.api.Assertions.fail;
32  
33  class KffDataObjectHandlerTest extends UnitTest {
34      static final byte[] DATA = "This is a test".getBytes();
35      static final SeekableByteChannelFactory SBC_DATA = SeekableByteChannelHelper.memory("This is a test".getBytes());
36  
37      // echo -n "This is a test" | openssl sha1
38      static final String DATA_SHA1 = "a54d88e06612d820bc3be72877c74f257b561b19";
39  
40      // echo -n "This is a test" | openssl md5
41      static final String DATA_MD5 = "ce114e4501d2f4e2dcea3e17b546f339";
42  
43      // echo -n "This is a test" | openssl sha256
44      static final String DATA_SHA256 = "c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e";
45  
46      // echo -n "This is a test" | openssl sha384
47      static final String DATA_SHA384 =
48              "a27c7667e58200d4c0688ea136968404a0da366b1a9fc19bb38a0c7a609a1eef2bcc82837f4f4d92031a66051494b38c";
49  
50      // echo -n "This is a test" | openssl sha512
51      static final String DATA_SHA512 =
52              "a028d4f74b602ba45eb0a93c9a4677240dcf281a1a9322f183bd32f0bed82ec72de9c3957b2f4c9a1ccf7ed14f85d73498df38017e703d47ebb9f0b3bf116f69";
53  
54      static final String DATA_SSDEEP = "3:hMCEpn:hup";
55  
56      static final String DATA_CRC32 = "33323239323631363138";
57  
58      /**
59       * HashCode hashCode = Hashing.murmur3_128().newHasher() .putString(DATA_MD5, StandardCharsets.UTF_8)
60       * .putString(DATA_SHA1, StandardCharsets.UTF_8) .putString(DATA_SHA256, StandardCharsets.UTF_8) .hash();
61       *
62       * return new StringBuilder(hashCode.toString()) .insert(20, "-") .insert(16, "-") .insert(12, "-") .insert(8, "-")
63       * .toString();
64       */
65      static final String DATA_HASH_ID = "b0cf6000-dbd3-3df6-eead-e7b144bdcc48";
66  
67      @Nullable
68      protected KffDataObjectHandler kff;
69      @Nullable
70      protected IBaseDataObject payload;
71      private static final String resource = "emissary/kff/test.dat";
72  
73      @Override
74      @BeforeEach
75      public void setUp() {
76          kff = new KffDataObjectHandler();
77          try (InputStream doc = new ResourceReader().getResourceAsStream(resource)) {
78              byte[] data = IOUtils.toByteArray(doc);
79              String defaultCurrentForm = "test";
80              payload = DataObjectFactory.getInstance(data, resource, defaultCurrentForm);
81          } catch (IOException e) {
82              fail("Error getting resource file");
83          }
84      }
85  
86      @Override
87      @AfterEach
88      public void tearDown() throws Exception {
89          super.tearDown();
90          kff = null;
91          payload = null;
92      }
93  
94      @Test
95      void testMapWithEmptyPrefix() {
96          Map<String, String> m = kff.hashData(DATA, "junk");
97          assertNotNull(m.get(KffDataObjectHandler.KFF_PARAM_MD5), "Empty prefix returns normal values");
98  
99          m.clear();
100 
101         m = kff.hashData(SBC_DATA, "junk");
102         assertNotNull(m.get(KffDataObjectHandler.KFF_PARAM_MD5), "Empty prefix returns normal values");
103     }
104 
105     @Test
106     void testMapWithNullPrefix() {
107         Map<String, String> m = kff.hashData(DATA, "junk", null);
108         assertNotNull(m.get(KffDataObjectHandler.KFF_PARAM_MD5), "Null prefix returns normal values");
109 
110         m.clear();
111 
112         m = kff.hashData(SBC_DATA, "junk", null);
113         assertNotNull(m.get(KffDataObjectHandler.KFF_PARAM_MD5), "Null prefix returns normal values");
114     }
115 
116     @Test
117     void testMapWithPrefix() {
118         Map<String, String> m = kff.hashData(DATA, "name", "foo");
119         assertNotNull(m.get("foo" + KffDataObjectHandler.KFF_PARAM_MD5), "Prefix prepends on normal key names but we got " + m.keySet());
120 
121         m.clear();
122 
123         m = kff.hashData(SBC_DATA, "name", "foo");
124         assertNotNull(m.get("foo" + KffDataObjectHandler.KFF_PARAM_MD5), "Prefix prepends on normal key names but we got " + m.keySet());
125     }
126 
127     @Test
128     void testHashMethod() {
129         kff = new KffDataObjectHandler(true, true, true);
130         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
131         kff.hash(payload);
132         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
133         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
134         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
135         assertTrue(KffDataObjectHandler.hashPresent(payload));
136         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
137         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
138         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
139         assertEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_CRC32));
140         assertEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_CRC32));
141         assertEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_CRC32));
142         assertEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
143         assertEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
144         assertEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
145         assertEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
146         assertEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
147         assertEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
148         assertEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
149         assertEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
150         assertEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
151         assertEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
152         assertArrayEquals(new byte[0], payload.data());
153     }
154 
155     @Test
156     void testHashMethodCalledTwice() {
157         // don't truncate known data or the second call will be made with an empty payload
158         kff = new KffDataObjectHandler(KffDataObjectHandler.KEEP_KNOWN_DATA, true, true);
159         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
160         kff.hash(payload);
161 
162         assertNull(payload.getStringParameter(KffDataObjectHandler.MD5_ORIGINAL),
163                 "MD5_ORIGINAL should only be populated if hashing more than once");
164         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.MD5_ORIGINAL),
165                 "MD5_ORIGINAL should only be populated if hashing more than once");
166         assertNull(payload.getParameterAsString(KffDataObjectHandler.MD5_ORIGINAL),
167                 "MD5_ORIGINAL should only be populated if hashing more than once");
168 
169         // hash again, to see the effect on the hash-related params.
170         // none of the parameters should have a duplicated value
171 
172         kff.hash(payload);
173         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
174         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
175         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
176         assertTrue(KffDataObjectHandler.hashPresent(payload));
177         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
178         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
179         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
180         assertEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_CRC32));
181         assertEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_CRC32));
182         assertEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_CRC32));
183         assertEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
184         assertEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
185         assertEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
186         assertEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
187         assertEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
188         assertEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
189         assertEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
190         assertEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
191         assertEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
192         assertEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
193         assertNull(payload.getStringParameter(KffDataObjectHandler.MD5_ORIGINAL),
194                 "MD5_ORIGINAL should not be populated if hash called more than once but data hasn't changed");
195         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.MD5_ORIGINAL),
196                 "MD5_ORIGINAL should not be populated if hash called more than once but data hasn't changed");
197         assertNull(payload.getParameterAsString(KffDataObjectHandler.MD5_ORIGINAL),
198                 "MD5_ORIGINAL should not be populated if hash called more than once but data hasn't changed");
199     }
200 
201     @Test
202     void testHashMethodAgainAfterModifyingData() {
203         // don't truncate known data or the second call will be made with an empty payload
204         kff = new KffDataObjectHandler(KffDataObjectHandler.KEEP_KNOWN_DATA, true, true);
205         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
206         kff.hash(payload);
207 
208         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
209         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
210         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
211         assertTrue(KffDataObjectHandler.hashPresent(payload));
212         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
213         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
214         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
215         assertEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_CRC32));
216         assertEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_CRC32));
217         assertEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_CRC32));
218         assertEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
219         assertEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
220         assertEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
221         assertEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
222         assertEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
223         assertEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
224         assertEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
225         assertEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
226         assertEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
227         assertNull(payload.getStringParameter(KffDataObjectHandler.MD5_ORIGINAL),
228                 "MD5_ORIGINAL should only be populated if hashing more than once and data has changed");
229         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.MD5_ORIGINAL),
230                 "MD5_ORIGINAL should only be populated if hashing more than once and data has changed");
231         assertNull(payload.getParameterAsString(KffDataObjectHandler.MD5_ORIGINAL),
232                 "MD5_ORIGINAL should only be populated if hashing more than once and data has changed");
233 
234         payload.setData("This is a changed data".getBytes());
235         // hash again, to see the effect on the hash-related params.
236         // none of the parameters should have a duplicated value
237 
238         kff.hash(payload);
239         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
240         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
241         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME));
242         assertTrue(KffDataObjectHandler.hashPresent(payload));
243         assertNotNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
244         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
245         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
246         assertNotNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_CRC32));
247         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_CRC32));
248         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_CRC32));
249         assertNotNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
250         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
251         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
252         assertNotNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
253         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
254         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
255         assertNotNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
256         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
257         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
258         assertNotEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
259         assertNotEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
260         assertNotEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
261         assertNotEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_CRC32));
262         assertNotEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_CRC32));
263         assertNotEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_CRC32));
264         assertNotEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
265         assertNotEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
266         assertNotEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
267         assertNotEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
268         assertNotEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
269         assertNotEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
270         assertNotEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
271         assertNotEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
272         assertNotEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
273         assertEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
274 
275         // make sure we've correctly populated MD5_ORIGINAL
276         assertNotNull(payload.getStringParameter(KffDataObjectHandler.MD5_ORIGINAL),
277                 "MD5_ORIGINAL should be populated if hash called more than once");
278         assertNotNull(payload.getParameterAsConcatString(KffDataObjectHandler.MD5_ORIGINAL),
279                 "MD5_ORIGINAL should be populated if hash called more than once");
280         assertNotNull(payload.getParameterAsString(KffDataObjectHandler.MD5_ORIGINAL),
281                 "MD5_ORIGINAL should be populated if hash called more than once");
282         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.MD5_ORIGINAL));
283         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.MD5_ORIGINAL));
284         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.MD5_ORIGINAL));
285     }
286 
287     @Test
288     void testParentToChildMethod() {
289         payload.setParameter(KffDataObjectHandler.KFF_PARAM_DUPE_HIT, payload);
290         KffDataObjectHandler.parentToChild(payload);
291         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_DUPE_HIT));
292         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_DUPE_HIT));
293         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_DUPE_HIT));
294     }
295 
296     @Test
297     void testSetAndGetHash() {
298         KffDataObjectHandler.setHashValue(payload, DATA_MD5);
299         assertEquals(DATA_MD5, KffDataObjectHandler.getMd5Value(payload));
300         KffDataObjectHandler.setHashValue(payload, DATA_SHA1);
301         assertEquals(DATA_SHA1, KffDataObjectHandler.getHashValue(payload));
302         KffDataObjectHandler.setHashValue(payload, DATA_SSDEEP);
303         assertEquals(DATA_SSDEEP, KffDataObjectHandler.getSsdeepValue(payload));
304         KffDataObjectHandler.setHashValue(payload, DATA_SHA256);
305         assertEquals(DATA_SHA256, KffDataObjectHandler.getSha256Value(payload));
306         KffDataObjectHandler.setHashValue(payload, DATA_SHA384);
307         assertEquals(DATA_SHA384, KffDataObjectHandler.getSha384Value(payload));
308         KffDataObjectHandler.setHashValue(payload, DATA_SHA512);
309         assertEquals(DATA_SHA512, KffDataObjectHandler.getSha512Value(payload));
310 
311         assertEquals(DATA_SHA512, KffDataObjectHandler.getBestAvailableHash(payload));
312         payload.deleteParameter(KffDataObjectHandler.KFF_PARAM_SHA512);
313         assertEquals(DATA_SHA384, KffDataObjectHandler.getBestAvailableHash(payload));
314     }
315 
316     @Test
317     void testWithChannelFactory() {
318         kff = new KffDataObjectHandler(true, true, true);
319         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
320         payload.setChannelFactory(SBC_DATA);
321         kff.hash(payload);
322         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
323         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
324         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
325         assertTrue(KffDataObjectHandler.hashPresent(payload));
326         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
327         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
328         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
329         assertEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
330         assertEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
331         assertEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
332         assertEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
333         assertEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
334         assertEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
335         assertEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
336         assertEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
337         assertEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
338         assertEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
339         assertEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
340         assertEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
341         assertEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
342         assertArrayEquals(new byte[0], payload.data());
343     }
344 
345     @Test
346     void testWithEmptyChannelFactory() {
347         kff = new KffDataObjectHandler(true, true, true);
348         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
349         payload.setChannelFactory(SeekableByteChannelHelper.EMPTY_CHANNEL_FACTORY);
350         kff.hash(payload);
351         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
352         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
353         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
354         assertFalse(KffDataObjectHandler.hashPresent(payload));
355         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
356         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
357         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
358         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
359         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
360         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
361         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
362         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
363         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
364         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
365         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
366         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
367         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
368         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
369         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
370         assertEquals("test", payload.getFileType());
371         assertArrayEquals(new byte[0], payload.data());
372         assertEquals(SeekableByteChannelHelper.EMPTY_CHANNEL_FACTORY, payload.getChannelFactory());
373     }
374 
375     @Test
376     void testNullPayload() {
377         assertDoesNotThrow(() -> kff.hash(null));
378     }
379 
380     @Test
381     void testRemovingHash() {
382         final SeekableByteChannelFactory exceptionSbcf = () -> new AbstractSeekableByteChannel() {
383             @Override
384             protected void closeImpl() {
385                 // Do nothing
386             }
387 
388             @Override
389             protected int readImpl(ByteBuffer byteBuffer) throws IOException {
390                 throw new IOException("Test exception");
391             }
392 
393             @Override
394             protected long sizeImpl() throws IOException {
395                 throw new IOException("Test exception");
396             }
397         };
398 
399         payload.setChannelFactory(exceptionSbcf);
400         kff.hash(payload);
401         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
402         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
403         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
404         assertFalse(KffDataObjectHandler.hashPresent(payload));
405         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
406         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
407         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
408         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
409         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
410         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
411         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
412         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
413         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
414         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
415         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
416         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
417         assertNull(payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
418         assertNull(payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
419         assertNull(payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
420         assertNotEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
421 
422         payload.setParameter(KffDataObjectHandler.KFF_PARAM_KNOWN_FILTER_NAME, "test.filter");
423         payload.setChannelFactory(SBC_DATA);
424         kff.hash(payload);
425         assertEquals("test.filter", payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
426         assertEquals("test.filter", payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
427         assertEquals("test.filter", payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "FILTERED_BY"));
428         assertTrue(KffDataObjectHandler.hashPresent(payload));
429         assertEquals(DATA_MD5, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_MD5));
430         assertEquals(DATA_MD5, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_MD5));
431         assertEquals(DATA_MD5, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_MD5));
432         assertEquals(DATA_CRC32, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
433         assertEquals(DATA_CRC32, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
434         assertEquals(DATA_CRC32, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_BASE + "CRC32"));
435         assertEquals(DATA_SSDEEP, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SSDEEP));
436         assertEquals(DATA_SSDEEP, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
437         assertEquals(DATA_SSDEEP, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SSDEEP));
438         assertEquals(DATA_SHA1, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA1));
439         assertEquals(DATA_SHA1, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA1));
440         assertEquals(DATA_SHA1, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA1));
441         assertEquals(DATA_SHA256, payload.getStringParameter(KffDataObjectHandler.KFF_PARAM_SHA256));
442         assertEquals(DATA_SHA256, payload.getParameterAsConcatString(KffDataObjectHandler.KFF_PARAM_SHA256));
443         assertEquals(DATA_SHA256, payload.getParameterAsString(KffDataObjectHandler.KFF_PARAM_SHA256));
444         assertEquals(KffDataObjectHandler.KFF_DUPE_CURRENT_FORM, payload.getFileType());
445 
446     }
447 
448     @Test
449     void testNullHashData() {
450         assertEquals(new HashMap<>(), kff.hashData((SeekableByteChannelFactory) null, null));
451     }
452 
453     @Test
454     void testEmptySbcf() {
455         assertEquals(new HashMap<>(), kff.hashData(SeekableByteChannelHelper.EMPTY_CHANNEL_FACTORY, null));
456     }
457 
458     @Test
459     void testMurmurHashCreation() {
460         payload.setParameter(KffDataObjectHandler.KFF_PARAM_MD5, DATA_MD5);
461         payload.setParameter(KffDataObjectHandler.KFF_PARAM_SHA1, DATA_SHA1);
462         payload.setParameter(KffDataObjectHandler.KFF_PARAM_SHA256, DATA_SHA256);
463 
464         String murmurHash = KffDataObjectHandler.createMurmurHash(payload);
465 
466         assertNotNull(murmurHash, "murmur hash should not be null when all hashes are set");
467         assertFalse(murmurHash.isEmpty(), "murmur hash should not be empty");
468         assertEquals(DATA_HASH_ID, murmurHash);
469     }
470 
471     @Test
472     void testMurmurHashWithoutInputHashes() {
473         payload.deleteParameter(KffDataObjectHandler.KFF_PARAM_MD5);
474         payload.deleteParameter(KffDataObjectHandler.KFF_PARAM_SHA1);
475         payload.deleteParameter(KffDataObjectHandler.KFF_PARAM_SHA256);
476 
477         String murmurHash = KffDataObjectHandler.createMurmurHash(payload);
478 
479         assertNull(murmurHash, "murmur hash should be null when no hashes are set");
480     }
481 
482     @Test
483     void testMurmurHashNotCreatedWhenMissingAnInputHash() {
484         payload.setParameter(KffDataObjectHandler.KFF_PARAM_MD5, DATA_MD5);
485         payload.deleteParameter(KffDataObjectHandler.KFF_PARAM_SHA1);
486         payload.setParameter(KffDataObjectHandler.KFF_PARAM_SHA256, DATA_SHA256);
487 
488         String murmurHash = KffDataObjectHandler.createMurmurHash(payload);
489 
490         assertNull(murmurHash, "murmur hash should be null when when one of the input hashes is missing");
491     }
492 
493 }