1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.harmony.security.tests.java.security;
19
20import java.io.ByteArrayOutputStream;
21import java.io.DataOutputStream;
22import java.security.DigestException;
23import java.security.MessageDigest;
24import java.security.NoSuchAlgorithmException;
25import java.security.NoSuchProviderException;
26import java.security.Provider;
27import java.security.Security;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.HashMap;
31import java.util.List;
32import java.util.Map;
33import java.util.Map.Entry;
34
35public class MessageDigest2Test extends junit.framework.TestCase {
36
37    private static final String MESSAGEDIGEST_ID = "MessageDigest.";
38
39    private Map<Provider, List<String>> digestAlgs = new HashMap<Provider, List<String>>();
40
41    private static final byte[] AR1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
42
43    private static final byte[] AR2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
44
45    private static final String MESSAGE = "abc";
46
47    private static final byte[] MESSAGE_DIGEST = { -87, -103, 62, 54, 71, 6,
48            -127, 106, -70, 62, 37, 113, 120, 80, -62, 108, -100, -48, -40,
49            -99, };
50
51    private static final byte[] MESSAGE_DIGEST_63_As = { 3, -16, -97, 91, 21,
52            -118, 122, -116, -38, -39, 32, -67, -36, 41, -72, 28, 24, -91, 81,
53            -11, };
54
55    private static final byte[] MESSAGE_DIGEST_64_As = { 0, -104, -70, -126,
56            75, 92, 22, 66, 123, -41, -95, 18, 42, 90, 68, 42, 37, -20, 100,
57            77, };
58
59    private static final byte[] MESSAGE_DIGEST_65_As = { 17, 101, 83, 38, -57,
60            8, -41, 3, 25, -66, 38, 16, -24, -91, 125, -102, 91, -107, -99, 59, };
61
62    /**
63     * java.security.MessageDigest#MessageDigest(java.lang.String)
64     */
65    public void test_constructor() {
66        for (List<String> algorithms : digestAlgs.values()) {
67            for (String algorithm : algorithms) {
68                MessageDigestStub md = new MessageDigestStub(algorithm);
69                assertEquals(algorithm, md.getAlgorithm());
70                assertEquals(0, md.getDigestLength());
71                assertNull(md.getProvider());
72            }
73        }
74    }
75
76    /**
77     * java.security.MessageDigest#clone()
78     */
79    public void test_clone() throws Exception {
80        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
81            for (String algorithm : e.getValue()) {
82                MessageDigest d1 = MessageDigest.getInstance(algorithm, e.getKey().getName());
83                for (byte b = 0; b < 84; b++) {
84                    d1.update(b);
85                }
86
87                MessageDigest d2 = (MessageDigest) d1.clone();
88                d1.update((byte) 1);
89                d2.update((byte) 1);
90
91                assertTrue("cloned hash differs from original for algorithm " + algorithm,
92                           MessageDigest.isEqual(d1.digest(), d2.digest()));
93            }
94        }
95    }
96
97    private static final byte[] SHA_DATA_2 = { 70, -54, 124, 120, -29, 57, 56,
98            119, -108, -54, -97, -76, -97, -50, -63, -73, 2, 85, -53, -79, };
99
100    private void testSerializationSHA_DATA_2(MessageDigest sha) throws Exception {
101        sha.reset();
102        ByteArrayOutputStream out = new ByteArrayOutputStream();
103        DataOutputStream output = new DataOutputStream(out);
104
105        // Made up data
106        output.writeUTF("tests.api.java.security.MessageDigestTest$InitializerFieldsTest3");
107        output.writeInt(0); // class modifiers
108        output.writeUTF("java.io.Serializable"); // interfaces
109
110        // Fields
111        output.writeUTF("sub_toBeNotSerialized"); // name
112        output.writeInt(9); // modifiers
113        output.writeUTF("Ljava/lang/String;"); // signature
114
115        output.writeUTF("sub_toBeNotSerialized2"); // name
116        output.writeInt(9); // modifiers
117        output.writeUTF("Ljava/lang/String;"); // signature
118
119        output.writeUTF("sub_toBeSerialized"); // name
120        output.writeInt(1); // modifiers
121        output.writeUTF("Ljava/lang/String;"); // signature
122
123        output.writeUTF("sub_toBeSerialized3"); // name
124        output.writeInt(1); // modifiers
125        output.writeUTF("Ljava/lang/String;"); // signature
126
127        output.writeUTF("sub_toBeSerialized4"); // name
128        output.writeInt(1); // modifiers
129        output.writeUTF("Ljava/lang/String;"); // signature
130
131        output.writeUTF("sub_toBeSerialized5"); // name
132        output.writeInt(1); // modifiers
133        output.writeUTF("Ljava/lang/String;"); // signature
134
135        // clinit
136        output.writeUTF("<clinit>"); // name
137        output.writeInt(8); // modifiers
138        output.writeUTF("()V"); // signature
139
140        // constructors
141        output.writeUTF("<init>"); // name
142        output.writeInt(0); // modifiers
143        output.writeUTF("()V"); // signature
144
145        // methods
146        output.writeUTF("equals"); // name
147        output.writeInt(1); // modifiers
148        output.writeUTF("(Ljava.lang.Object;)Z"); // signature
149
150        output.flush();
151
152        byte[] data = out.toByteArray();
153        byte[] hash = sha.digest(data);
154        assertTrue("SHA_DATA_2 NOT ok", Arrays.equals(hash, SHA_DATA_2));
155    }
156
157    private static final byte[] SHA_DATA_1 = { 90, 36, 111, 106, -32, 38, 4,
158            126, 21, -51, 107, 45, -64, -68, -109, 112, -31, -46, 34, 115, };
159
160    private void testSerializationSHA_DATA_1(MessageDigest sha) throws Exception {
161        sha.reset();
162        ByteArrayOutputStream out = new ByteArrayOutputStream();
163        DataOutputStream output = new DataOutputStream(out);
164
165        // Made up data
166        output.writeUTF("tests.api.java.security.MessageDigestTest$OptionalDataNotRead");
167        // name
168        output.writeInt(0); // class modifiers
169        output.writeUTF("java.io.Serializable"); // interfaces
170
171        // Fields
172        output.writeUTF("class$0"); // name
173        output.writeInt(8); // modifiers
174        output.writeUTF("Ljava/lang/Class;"); // signature
175
176        output.writeUTF("field1"); // name
177        output.writeInt(2); // modifiers
178        output.writeUTF("I"); // signature
179
180        output.writeUTF("field2"); // name
181        output.writeInt(2); // modifiers
182        output.writeUTF("I"); // signature
183
184        // clinit
185        output.writeUTF("<clinit>"); // name
186        output.writeInt(8); // modifiers
187        output.writeUTF("()V"); // signature
188
189        // constructors
190        output.writeUTF("<init>"); // name
191        output.writeInt(1); // modifiers
192        output.writeUTF("()V"); // signature
193
194        output.flush();
195        byte[] data = out.toByteArray();
196        byte[] hash = sha.digest(data);
197        assertTrue("SHA_DATA_1 NOT ok", Arrays.equals(hash, SHA_DATA_1));
198    }
199
200    /**
201     * java.security.MessageDigest#digest()
202     */
203    public void test_digest() throws Exception {
204        MessageDigest sha = MessageDigest.getInstance("SHA");
205        assertNotNull(sha);
206        sha.update(MESSAGE.getBytes());
207        byte[] digest = sha.digest();
208        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST));
209
210        sha.reset();
211        for (int i = 0; i < 63; i++) {
212            // just under buffer capacity
213            sha.update((byte) 'a');
214        }
215        digest = sha.digest();
216        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST_63_As));
217
218        sha.reset();
219        for (int i = 0; i < 64; i++) {
220            // exact SHA buffer capacity
221            sha.update((byte) 'a');
222        }
223        digest = sha.digest();
224        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST_64_As));
225
226        sha.reset();
227        for (int i = 0; i < 65; i++) {
228            // just above SHA buffer capacity
229            sha.update((byte) 'a');
230        }
231        digest = sha.digest();
232        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST_65_As));
233
234        testSerializationSHA_DATA_1(sha);
235        testSerializationSHA_DATA_2(sha);
236    }
237
238    /**
239     * java.security.MessageDigest#digest(byte[])
240     */
241    public void test_digest$B() throws Exception {
242        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
243            for (String algorithm : e.getValue()) {
244                MessageDigest digest = MessageDigest.getInstance(algorithm, e.getKey().getName());
245                assertNotNull(digest);
246                digest.digest(AR1);
247            }
248        }
249    }
250
251    /**
252     * java.security.MessageDigest#digest(byte[], int, int)
253     */
254    public void test_digest$BII() throws Exception {
255        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
256            for (String algorithm : e.getValue()) {
257                MessageDigest digest = MessageDigest.getInstance(algorithm, e.getKey().getName());
258                assertNotNull(digest);
259                int len = digest.getDigestLength();
260                byte[] digestBytes = new byte[len];
261                digest.digest(digestBytes, 0, digestBytes.length);
262            }
263            try {
264                MessageDigest.getInstance("SHA").digest(new byte[] {}, Integer.MAX_VALUE, 755);
265                fail();
266            } catch (IllegalArgumentException expected) {
267            }
268        }
269    }
270
271    /**
272     * java.security.MessageDigest#update(byte[], int, int)
273     */
274    public void test_update$BII() throws Exception {
275        try {
276            MessageDigest.getInstance("SHA").update(new byte[] {},
277                                                    Integer.MAX_VALUE, Integer.MAX_VALUE);
278            fail();
279        } catch (IllegalArgumentException expected) {
280        }
281    }
282
283    /**
284     * java.security.MessageDigest#getAlgorithm()
285     */
286    public void test_getAlgorithm() throws Exception {
287        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
288            for (String algorithm : e.getValue()) {
289                MessageDigest md = MessageDigest.getInstance(algorithm, e.getKey().getName());
290                assertEquals(algorithm, md.getAlgorithm());
291            }
292        }
293    }
294
295    /**
296     * java.security.MessageDigest#getDigestLength()
297     */
298    public void test_getDigestLength() throws Exception {
299        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
300            for (String algorithm : e.getValue()) {
301                MessageDigest md = MessageDigest.getInstance(algorithm, e.getKey().getName());
302                assertTrue("length not ok", md.getDigestLength() > 0);
303            }
304        }
305    }
306
307    /**
308     * java.security.MessageDigest#getInstance(java.lang.String)
309     */
310    public void test_getInstanceLjava_lang_String() throws Exception {
311        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
312            for (String algorithm : e.getValue()) {
313                MessageDigest md = MessageDigest.getInstance(algorithm);
314                assertNotNull(md);
315            }
316        }
317
318        try {
319            MessageDigest.getInstance("UnknownDigest");
320            fail("expected NoSuchAlgorithmException");
321        } catch (NoSuchAlgorithmException expected) {
322        }
323    }
324
325    /**
326     * java.security.MessageDigest#getInstance(java.lang.String,
327     *        java.lang.String)
328     */
329    public void test_getInstanceLjava_lang_StringLjava_lang_String() throws Exception {
330        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
331            for (String algorithm : e.getValue()) {
332                MessageDigest md = MessageDigest.getInstance(algorithm, e.getKey().getName());
333                assertNotNull(md);
334            }
335        }
336
337        for (List<String> algorithms : digestAlgs.values()) {
338            for (String algorithm : algorithms) {
339                try {
340                    MessageDigest.getInstance(algorithm, "UnknownProvider");
341                    fail("expected NoSuchProviderException");
342                } catch (NoSuchProviderException expected) {
343                }
344            }
345        }
346
347        for (Provider provider : digestAlgs.keySet()) {
348            try {
349                MessageDigest.getInstance("UnknownDigest", provider.getName());
350                fail("expected NoSuchAlgorithmException");
351            } catch (NoSuchAlgorithmException expected) {
352            }
353        }
354
355        for (Provider provider : digestAlgs.keySet()) {
356            try {
357                MessageDigest.getInstance(null, provider.getName());
358                fail("expected NullPointerException");
359            } catch (NullPointerException expected) {
360            }
361        }
362
363        try {
364            MessageDigest.getInstance("AnyDigest", (String)null);
365            fail("expected IllegalArgumentException");
366        } catch (IllegalArgumentException expected) {
367        }
368    }
369
370    /**
371     * java.security.MessageDigest#getInstance(java.lang.String,
372     *        java.security.Provider)
373     */
374    public void test_getInstanceLjava_lang_StringLjava_security_Provider() throws Exception {
375        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
376            for (String algorithm : e.getValue()) {
377                MessageDigest md = MessageDigest.getInstance(algorithm, e.getKey().getName());
378                assertNotNull(md);
379            }
380        }
381
382        try {
383            MessageDigest.getInstance(null, new TestProvider());
384            fail("expected NullPointerException");
385        } catch (NullPointerException expected) {
386        }
387
388        try {
389            MessageDigest.getInstance("UnknownDigest", new TestProvider());
390            fail("expected NoSuchAlgorithmException");
391        } catch (NoSuchAlgorithmException expected) {
392        }
393
394        try {
395            MessageDigest.getInstance("AnyDigest", (Provider)null);
396            fail("expected IllegalArgumentException");
397        } catch (IllegalArgumentException expected) {
398        }
399    }
400
401    /**
402     * java.security.MessageDigest#getProvider()
403     */
404    public void test_getProvider() throws Exception {
405        for (Entry<Provider, List<String>> e : digestAlgs.entrySet()) {
406            for (String algorithm : e.getValue()) {
407                MessageDigest md = MessageDigest.getInstance(algorithm, e.getKey().getName());
408                assertNotNull("provider is null", md.getProvider());
409            }
410        }
411    }
412
413    /**
414     * java.security.MessageDigest#isEqual(byte[], byte[])
415     */
416    public void test_isEqual$B$B() {
417        assertTrue("isEqual is not correct", MessageDigest.isEqual(AR1, AR2));
418    }
419
420    /**
421     * java.security.MessageDigest#toString()
422     */
423    public void test_toString() throws Exception {
424        String str = MessageDigest.getInstance("SHA").toString();
425        assertNotNull("toString is null", str);
426    }
427
428    protected void setUp() {
429        Provider[] providers = Security.getProviders("MessageDigest.SHA");
430        for (Provider provider : providers) {
431            digestAlgs.put(provider, getDigestAlgorithms(provider));
432        }
433    }
434
435    /*
436     * Returns the digest algorithms that the given provider supports.
437     */
438    private List<String> getDigestAlgorithms(Provider provider) {
439        if (provider == null) {
440            fail("No digest algorithms were found");
441        }
442
443        List<String> algs = new ArrayList<String>();
444        for (Object key : provider.keySet()) {
445            String algorithm = (String) key;
446            if (algorithm.startsWith(MESSAGEDIGEST_ID) && !algorithm.contains(" ")) {
447                algs.add(algorithm.substring(MESSAGEDIGEST_ID.length()));
448            }
449        }
450
451        if (algs.size() == 0) {
452            fail("No digest algorithms were found");
453        }
454        return algs;
455    }
456
457    private class MessageDigestStub extends MessageDigest {
458        public MessageDigestStub(String algorithm) {
459            super(algorithm);
460        }
461
462        public byte[] engineDigest() {
463            return null;
464        }
465
466        public void engineReset() {
467
468        }
469
470        public void engineUpdate(byte input) {
471
472        }
473
474        public void engineUpdate(byte[] input, int offset, int len) {
475
476        }
477
478    }
479
480    private static class TestProvider extends Provider {
481
482        protected TestProvider() {
483            super("TestProvider", 1.0, "INFO");
484
485        }
486
487    }
488}
489