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.io.IOException;
23import java.io.UnsupportedEncodingException;
24import java.security.DigestException;
25import java.security.MessageDigest;
26import java.security.NoSuchAlgorithmException;
27import java.security.NoSuchProviderException;
28import java.security.Provider;
29import java.security.Security;
30import java.util.Arrays;
31import java.util.Enumeration;
32import java.util.Vector;
33
34public class MessageDigest2Test extends junit.framework.TestCase {
35
36    private static final String MESSAGEDIGEST_ID = "MessageDigest.";
37
38    private String[] digestAlgs = null;
39
40    private String providerName = null;
41
42    private static final byte[] AR1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
43
44    private static final byte[] AR2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
45
46    private static final String MESSAGE = "abc";
47
48    private static final byte[] MESSAGE_DIGEST = { -87, -103, 62, 54, 71, 6,
49            -127, 106, -70, 62, 37, 113, 120, 80, -62, 108, -100, -48, -40,
50            -99, };
51
52    private static final byte[] MESSAGE_DIGEST_63_As = { 3, -16, -97, 91, 21,
53            -118, 122, -116, -38, -39, 32, -67, -36, 41, -72, 28, 24, -91, 81,
54            -11, };
55
56    private static final byte[] MESSAGE_DIGEST_64_As = { 0, -104, -70, -126,
57            75, 92, 22, 66, 123, -41, -95, 18, 42, 90, 68, 42, 37, -20, 100,
58            77, };
59
60    private static final byte[] MESSAGE_DIGEST_65_As = { 17, 101, 83, 38, -57,
61            8, -41, 3, 25, -66, 38, 16, -24, -91, 125, -102, 91, -107, -99, 59, };
62
63    /**
64     * @tests java.security.MessageDigest#clone()
65     */
66    public void test_clone() {
67        for (int i = 0; i < digestAlgs.length; i++) {
68            try {
69                MessageDigest d1 = MessageDigest.getInstance(digestAlgs[i],
70                        providerName);
71                for (byte b = 0; b < 84; b++) {
72                    d1.update(b);
73                }
74
75                MessageDigest d2 = (MessageDigest) d1.clone();
76                d1.update((byte) 1);
77                d2.update((byte) 1);
78
79                assertTrue("cloned hash differs from original for algorithm "
80                        + digestAlgs[i], MessageDigest.isEqual(d1.digest(), d2
81                        .digest()));
82            } catch (CloneNotSupportedException e) {
83                // Expected - a Signature may not be cloneable
84            } catch (NoSuchAlgorithmException e) {
85                fail("getInstance did not find algorithm " + digestAlgs[i]);
86            } catch (NoSuchProviderException e) {
87                fail("getInstance did not find provider " + providerName);
88            }
89        }
90    }
91
92    private static final byte[] SHA_DATA_2 = { 70, -54, 124, 120, -29, 57, 56,
93            119, -108, -54, -97, -76, -97, -50, -63, -73, 2, 85, -53, -79, };
94
95    private void testSerializationSHA_DATA_2(MessageDigest sha) {
96        try {
97            sha.reset();
98            ByteArrayOutputStream out = new ByteArrayOutputStream();
99            DataOutputStream output = new DataOutputStream(out);
100            // -----------------------------------------------------------------------
101
102            // Made up data
103            output
104                    .writeUTF("tests.api.java.security.MessageDigestTest$InitializerFieldsTest3");
105            output.writeInt(0); // class modifiers
106            output.writeUTF("java.io.Serializable"); // interfaces
107
108            // Fields
109            output.writeUTF("sub_toBeNotSerialized"); // name
110            output.writeInt(9); // modifiers
111            output.writeUTF("Ljava/lang/String;"); // signature
112
113            output.writeUTF("sub_toBeNotSerialized2"); // name
114            output.writeInt(9); // modifiers
115            output.writeUTF("Ljava/lang/String;"); // signature
116
117            output.writeUTF("sub_toBeSerialized"); // name
118            output.writeInt(1); // modifiers
119            output.writeUTF("Ljava/lang/String;"); // signature
120
121            output.writeUTF("sub_toBeSerialized3"); // name
122            output.writeInt(1); // modifiers
123            output.writeUTF("Ljava/lang/String;"); // signature
124
125            output.writeUTF("sub_toBeSerialized4"); // name
126            output.writeInt(1); // modifiers
127            output.writeUTF("Ljava/lang/String;"); // signature
128
129            output.writeUTF("sub_toBeSerialized5"); // name
130            output.writeInt(1); // modifiers
131            output.writeUTF("Ljava/lang/String;"); // signature
132
133            // clinit
134            output.writeUTF("<clinit>"); // name
135            output.writeInt(8); // modifiers
136            output.writeUTF("()V"); // signature
137
138            // constructors
139            output.writeUTF("<init>"); // name
140            output.writeInt(0); // modifiers
141            output.writeUTF("()V"); // signature
142
143            // methods
144            output.writeUTF("equals"); // name
145            output.writeInt(1); // modifiers
146            output.writeUTF("(Ljava.lang.Object;)Z"); // signature
147
148            // -----------------------------------------------------------------------
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        } catch (IOException e) {
156            fail("SHA_DATA_2 NOT ok");
157        }
158    }
159
160    private static final byte[] SHA_DATA_1 = { 90, 36, 111, 106, -32, 38, 4,
161            126, 21, -51, 107, 45, -64, -68, -109, 112, -31, -46, 34, 115, };
162
163    private void testSerializationSHA_DATA_1(MessageDigest sha) {
164        try {
165            sha.reset();
166            ByteArrayOutputStream out = new ByteArrayOutputStream();
167            DataOutputStream output = new DataOutputStream(out);
168            // -----------------------------------------------------------------------
169
170            // Made up data
171            output
172                    .writeUTF("tests.api.java.security.MessageDigestTest$OptionalDataNotRead");
173            // name
174            output.writeInt(0); // class modifiers
175            output.writeUTF("java.io.Serializable"); // interfaces
176
177            // Fields
178            output.writeUTF("class$0"); // name
179            output.writeInt(8); // modifiers
180            output.writeUTF("Ljava/lang/Class;"); // signature
181
182            output.writeUTF("field1"); // name
183            output.writeInt(2); // modifiers
184            output.writeUTF("I"); // signature
185
186            output.writeUTF("field2"); // name
187            output.writeInt(2); // modifiers
188            output.writeUTF("I"); // signature
189
190            // clinit
191            output.writeUTF("<clinit>"); // name
192            output.writeInt(8); // modifiers
193            output.writeUTF("()V"); // signature
194
195            // constructors
196            output.writeUTF("<init>"); // name
197            output.writeInt(1); // modifiers
198            output.writeUTF("()V"); // signature
199            // -----------------------------------------------------------------------
200
201            output.flush();
202            byte[] data = out.toByteArray();
203            byte[] hash = sha.digest(data);
204            assertTrue("SHA_DATA_1 NOT ok", Arrays.equals(hash, SHA_DATA_1));
205        } catch (IOException e) {
206            fail("SHA_DATA_1 NOT ok");
207        }
208    }
209
210    /**
211     * @throws UnsupportedEncodingException
212     * @tests java.security.MessageDigest#digest()
213     */
214    public void test_digest() throws UnsupportedEncodingException {
215        MessageDigest sha = null;
216        try {
217            sha = MessageDigest.getInstance("SHA");
218            assertNotNull(sha);
219        } catch (NoSuchAlgorithmException e) {
220            fail("getInstance did not find algorithm");
221        }
222        sha.update(MESSAGE.getBytes("UTF-8"));
223        byte[] digest = sha.digest();
224        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST));
225
226        sha.reset();
227        for (int i = 0; i < 63; i++) {
228            // just under buffer capacity
229            sha.update((byte) 'a');
230        }
231        digest = sha.digest();
232        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
233                MESSAGE_DIGEST_63_As));
234
235        sha.reset();
236        for (int i = 0; i < 64; i++) {
237            // exact SHA buffer capacity
238            sha.update((byte) 'a');
239        }
240        digest = sha.digest();
241        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
242                MESSAGE_DIGEST_64_As));
243
244        sha.reset();
245        for (int i = 0; i < 65; i++) {
246            // just above SHA buffer capacity
247            sha.update((byte) 'a');
248        }
249        digest = sha.digest();
250        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
251                MESSAGE_DIGEST_65_As));
252
253        testSerializationSHA_DATA_1(sha);
254        testSerializationSHA_DATA_2(sha);
255    }
256
257    /**
258     * @tests java.security.MessageDigest#digest(byte[])
259     */
260    public void test_digest$B() {
261        for (int i = 0; i < digestAlgs.length; i++) {
262            try {
263                MessageDigest digest = MessageDigest.getInstance(digestAlgs[i],
264                        providerName);
265                assertNotNull(digest);
266                digest.digest(AR1);
267            } catch (NoSuchAlgorithmException e) {
268                fail("getInstance did not find algorithm " + digestAlgs[i]);
269            } catch (NoSuchProviderException e) {
270                fail("getInstance did not find provider " + providerName);
271            }
272        }
273    }
274
275    /**
276     * @tests java.security.MessageDigest#digest(byte[], int, int)
277     */
278    public void test_digest$BII() {
279        for (int i = 0; i < digestAlgs.length; i++) {
280            try {
281                MessageDigest digest = MessageDigest.getInstance(digestAlgs[i],
282                        providerName);
283                assertNotNull(digest);
284                int len = digest.getDigestLength();
285                byte[] digestBytes = new byte[len];
286                digest.digest(digestBytes, 0, digestBytes.length);
287            } catch (NoSuchAlgorithmException e) {
288                fail("getInstance did not find algorithm " + digestAlgs[i]);
289            } catch (NoSuchProviderException e) {
290                fail("getInstance did not find provider " + providerName);
291            } catch (DigestException e) {
292                fail("digest caused exception for algorithm " + digestAlgs[i]
293                        + " : " + e);
294            }
295        }
296        try {
297            MessageDigest.getInstance("SHA").digest(new byte[] { }, Integer.MAX_VALUE, 755);
298        } catch (NoSuchAlgorithmException e) {
299            //allowed
300        } catch (DigestException e) {
301            //allowed
302        } catch (IllegalArgumentException e) {
303            //expected
304        }
305    }
306
307    /**
308     * @tests java.security.MessageDigest#update(byte[], int, int)
309     */
310    public void test_update$BII() {
311        try {
312            MessageDigest.getInstance("SHA").update(new byte[] { }, Integer.MAX_VALUE, Integer.MAX_VALUE);
313        } catch (NoSuchAlgorithmException e) {
314            //allowed
315        } catch (IllegalArgumentException e) {
316            //expected
317        }
318    }
319
320    /**
321     * @tests java.security.MessageDigest#getAlgorithm()
322     */
323    public void test_getAlgorithm() {
324        for (int i = 0; i < digestAlgs.length; i++) {
325            try {
326                String alg = MessageDigest.getInstance(digestAlgs[i],
327                        providerName).getAlgorithm();
328                assertTrue("getAlgorithm ok", alg.equals(digestAlgs[i]));
329            } catch (NoSuchAlgorithmException e) {
330                fail("getInstance did not find algorithm " + digestAlgs[i]);
331            } catch (NoSuchProviderException e) {
332                fail("getInstance did not find provider " + providerName);
333            }
334        }
335    }
336
337    /**
338     * @tests java.security.MessageDigest#getDigestLength()
339     */
340    public void test_getDigestLength() {
341        for (int i = 0; i < digestAlgs.length; i++) {
342            try {
343                int len = MessageDigest
344                        .getInstance(digestAlgs[i], providerName)
345                        .getDigestLength();
346                assertTrue("length not ok", len > 0);
347            } catch (NoSuchAlgorithmException e) {
348                fail("getInstance did not find algorithm " + digestAlgs[i]);
349            } catch (NoSuchProviderException e) {
350                fail("getInstance did not find provider " + providerName);
351            }
352        }// end for
353    }
354
355    /**
356     * @tests java.security.MessageDigest#getInstance(java.lang.String)
357     */
358    public void test_getInstanceLjava_lang_String() {
359        for (int i = 0; i < digestAlgs.length; i++) {
360            try {
361                MessageDigest.getInstance(digestAlgs[i]);
362            } catch (NoSuchAlgorithmException e) {
363                fail("getInstance did not find algorithm " + digestAlgs[i]);
364            }
365        }
366    }
367
368    /**
369     * @tests java.security.MessageDigest#getInstance(java.lang.String,
370     *java.lang.String)
371     */
372    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
373        for (int i = 0; i < digestAlgs.length; i++) {
374            try {
375                MessageDigest.getInstance(digestAlgs[i], providerName);
376            } catch (NoSuchAlgorithmException e) {
377                fail("getInstance did not find algorithm " + digestAlgs[i]);
378            } catch (NoSuchProviderException e) {
379                fail("getInstance did not find provider " + providerName);
380            }
381        }
382    }
383
384    /**
385     * @tests java.security.MessageDigest#getProvider()
386     */
387    public void test_getProvider() {
388        for (int i = 0; i < digestAlgs.length; i++) {
389            try {
390                Provider p = MessageDigest.getInstance(digestAlgs[i],
391                        providerName).getProvider();
392                assertNotNull("provider is null", p);
393            } catch (NoSuchAlgorithmException e) {
394                fail("getInstance did not find algorithm " + digestAlgs[i]);
395            } catch (NoSuchProviderException e) {
396                fail("getInstance did not find provider " + providerName);
397            }
398        }
399    }
400
401    /**
402     * @tests java.security.MessageDigest#isEqual(byte[], byte[])
403     */
404    public void test_isEqual$B$B() {
405        assertTrue("isEqual is not correct", MessageDigest.isEqual(AR1, AR2));
406    }
407
408    /**
409     * @tests java.security.MessageDigest#toString()
410     */
411    public void test_toString() {
412        try {
413            String str = MessageDigest.getInstance("SHA").toString();
414            assertNotNull("toString is null", str);
415        } catch (NoSuchAlgorithmException e) {
416            fail("getInstance did not find algorithm");
417        }
418    }
419
420    protected void setUp() {
421        if (digestAlgs == null) {
422            Provider[] providers = Security.getProviders("MessageDigest.SHA");
423            if (providers == null) {
424                fail("No providers available for test");
425            }
426
427            // Arbitrarily select the first available provider
428            providerName = providers[0].getName();
429            digestAlgs = getDigestAlgorithms(providerName);
430            if (digestAlgs == null || digestAlgs.length == 0) {
431                fail("No digest algorithms were found");
432            }
433        }
434    }
435
436    /*
437      * Returns the digest algorithms that the given provider supports.
438      */
439    private String[] getDigestAlgorithms(String providerName) {
440        Vector algs = new Vector();
441
442        Provider provider = Security.getProvider(providerName);
443        if (provider == null)
444            return new String[0];
445        Enumeration e = provider.keys();
446        while (e.hasMoreElements()) {
447            String algorithm = (String) e.nextElement();
448            if (algorithm.startsWith(MESSAGEDIGEST_ID) && !algorithm.contains(" ")) {
449                algs.addElement(algorithm.substring(MESSAGEDIGEST_ID.length()));
450            }
451        }// end while
452
453        return (String[]) algs.toArray(new String[algs.size()]);
454    }
455}