1/*
2 * Copyright (C) 2009 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 */
16package tests.security;
17
18import java.io.IOException;
19import java.io.InputStream;
20import java.security.MessageDigest;
21import java.security.NoSuchAlgorithmException;
22import junit.framework.TestCase;
23
24public abstract class MessageDigestTest extends TestCase {
25
26    private String digestAlgorithmName;
27
28    protected MessageDigestTest(String digestAlgorithmName) {
29        super();
30        this.digestAlgorithmName = digestAlgorithmName;
31    }
32
33    private MessageDigest digest;
34    private InputStream sourceData;
35    private byte[] checkDigest;
36
37    @Override
38    protected void setUp() throws Exception {
39        super.setUp();
40
41        this.source3 = getLongMessage(1000000);
42        this.digest = MessageDigest.getInstance(digestAlgorithmName);
43        this.sourceData = getSourceData();
44        this.checkDigest = getCheckDigest();
45    }
46
47    @Override
48    public void tearDown() throws Exception {
49        super.tearDown();
50
51        // This is critical. The MessageDigest tests consume a lot of memory due
52        // to the 1 MB buffers being allocated. We need to make sure all data is
53        // freed after each test. Otherwise the Android runtime simply dies at
54        // some point.
55        source1 = null;
56        source2 = null;
57        source3 = null;
58
59        expected1 = null;
60        expected2 = null;
61        expected3 = null;
62
63        digest = null;
64        sourceData.close();
65        sourceData = null;
66        checkDigest = null;
67
68        System.gc();
69    }
70
71    InputStream getSourceData() {
72        InputStream sourceStream = getClass().getResourceAsStream(digestAlgorithmName + ".data");
73        assertNotNull("digest source data not found: " + digestAlgorithmName, sourceStream);
74        return sourceStream;
75    }
76
77    byte[] getCheckDigest() throws Exception {
78        InputStream checkDigestStream =
79                getClass().getResourceAsStream(digestAlgorithmName + ".check");
80        byte[] checkDigest = new byte[digest.getDigestLength()];
81        int read = 0;
82        int index = 0;
83        while ((read = checkDigestStream.read()) != -1) {
84            checkDigest[index++] = (byte)read;
85        }
86        checkDigestStream.close();
87        return checkDigest;
88    }
89
90    public void testMessageDigest1() throws Exception {
91        byte[] buf = new byte[128];
92        int read = 0;
93        while ((read = sourceData.read(buf)) != -1) {
94            digest.update(buf, 0, read);
95        }
96        sourceData.close();
97
98        byte[] computedDigest = digest.digest();
99
100        assertNotNull("computed digest is is null", computedDigest);
101        assertEquals("digest length mismatch", checkDigest.length, computedDigest.length);
102
103        for (int i = 0; i < checkDigest.length; i++) {
104            assertEquals("byte " + i + " of computed and check digest differ",
105                         checkDigest[i], computedDigest[i]);
106        }
107    }
108
109    public void testMessageDigest2() throws Exception {
110        int val;
111        while ((val = sourceData.read()) != -1) {
112            digest.update((byte)val);
113        }
114        sourceData.close();
115
116        byte[] computedDigest = digest.digest();
117
118        assertNotNull("computed digest is is null", computedDigest);
119        assertEquals("digest length mismatch", checkDigest.length, computedDigest.length);
120
121        for (int i = 0; i < checkDigest.length; i++) {
122            assertEquals("byte " + i + " of computed and check digest differ",
123                         checkDigest[i], computedDigest[i]);
124        }
125    }
126
127
128    /**
129     * Official FIPS180-2 testcases
130     */
131
132    protected String source1;
133    protected String source2;
134    protected String source3;
135    protected String expected1;
136    protected String expected2;
137    protected String expected3;
138
139    String getLongMessage(int length) {
140        StringBuilder sourceBuilder = new StringBuilder(length);
141        for (int i = 0; i < length / 10; i++) {
142            sourceBuilder.append("aaaaaaaaaa");
143        }
144        return sourceBuilder.toString();
145    }
146
147    public void testfips180_2_singleblock() throws Exception {
148
149        digest.update(source1.getBytes(), 0, source1.length());
150
151        byte[] computedDigest = digest.digest();
152
153        assertNotNull("computed digest is null", computedDigest);
154
155        StringBuilder sb = new StringBuilder();
156        for (int i = 0; i < computedDigest.length; i++) {
157            String res = Integer.toHexString(computedDigest[i] & 0xFF);
158            sb.append((res.length() == 1 ? "0" : "") + res);
159        }
160        assertEquals("computed and check digest differ", expected1, sb.toString());
161    }
162
163    public void testfips180_2_multiblock() throws Exception {
164
165        digest.update(source2.getBytes(), 0, source2.length());
166
167        byte[] computedDigest = digest.digest();
168
169        assertNotNull("computed digest is null", computedDigest);
170
171        StringBuilder sb = new StringBuilder();
172        for (int i = 0; i < computedDigest.length; i++) {
173            String res = Integer.toHexString(computedDigest[i] & 0xFF);
174            sb.append((res.length() == 1 ? "0" : "") + res);
175        }
176        assertEquals("computed and check digest differ", expected2, sb.toString());
177    }
178
179    public void testfips180_2_longMessage() throws Exception {
180
181        digest.update(source3.getBytes(), 0, source3.length());
182
183        byte[] computedDigest = digest.digest();
184
185        assertNotNull("computed digest is null", computedDigest);
186
187        StringBuilder sb = new StringBuilder();
188        for (int i = 0; i < computedDigest.length; i++) {
189            String res = Integer.toHexString(computedDigest[i] & 0xFF);
190            sb.append((res.length() == 1 ? "0" : "") + res);
191        }
192        assertEquals("computed and check digest differ", expected3, sb.toString());
193    }
194}
195