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