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 */ 16 package tests.security; 17 18 import java.io.IOException; 19 import java.io.InputStream; 20 import java.security.MessageDigest; 21 import java.security.NoSuchAlgorithmException; 22 import junit.framework.TestCase; 23 24 public 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 = getMessageDigest(); 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 MessageDigest getMessageDigest() { 72 try { 73 return MessageDigest.getInstance(digestAlgorithmName); 74 } catch (NoSuchAlgorithmException e) { 75 fail("failed to get digest instance: " + e); 76 return null; 77 } 78 } 79 80 InputStream getSourceData() { 81 InputStream sourceStream = getClass().getResourceAsStream(digestAlgorithmName + ".data"); 82 assertNotNull("digest source data not found: " + digestAlgorithmName, sourceStream); 83 return sourceStream; 84 } 85 86 byte[] getCheckDigest() { 87 InputStream checkDigestStream = 88 getClass().getResourceAsStream(digestAlgorithmName + ".check"); 89 byte[] checkDigest = new byte[digest.getDigestLength()]; 90 int read = 0; 91 int index = 0; 92 try { 93 while ((read = checkDigestStream.read()) != -1) { 94 checkDigest[index++] = (byte)read; 95 } 96 checkDigestStream.close(); 97 } catch (IOException e) { 98 fail("failed to read digest golden data: " + digestAlgorithmName); 99 } 100 return checkDigest; 101 } 102 103 public void testMessageDigest1() { 104 byte[] buf = new byte[128]; 105 int read = 0; 106 try { 107 while ((read = sourceData.read(buf)) != -1) { 108 digest.update(buf, 0, read); 109 } 110 sourceData.close(); 111 } catch (IOException e) { 112 fail("failed to read digest data"); 113 } 114 115 byte[] computedDigest = digest.digest(); 116 117 assertNotNull("computed digest is is null", computedDigest); 118 assertEquals("digest length mismatch", checkDigest.length, computedDigest.length); 119 120 for (int i = 0; i < checkDigest.length; i++) { 121 assertEquals("byte " + i + " of computed and check digest differ", 122 checkDigest[i], computedDigest[i]); 123 } 124 125 } 126 127 public void testMessageDigest2() { 128 int val; 129 try { 130 while ((val = sourceData.read()) != -1) { 131 digest.update((byte)val); 132 } 133 sourceData.close(); 134 } catch (IOException e) { 135 fail("failed to read digest data"); 136 } 137 138 byte[] computedDigest = digest.digest(); 139 140 assertNotNull("computed digest is is null", computedDigest); 141 assertEquals("digest length mismatch", checkDigest.length, computedDigest.length); 142 for (int i = 0; i < checkDigest.length; i++) { 143 assertEquals("byte " + i + " of computed and check digest differ", 144 checkDigest[i], computedDigest[i]); 145 } 146 147 } 148 149 150 /** 151 * Official FIPS180-2 testcases 152 */ 153 154 protected String source1; 155 protected String source2; 156 protected String source3; 157 protected String expected1; 158 protected String expected2; 159 protected String expected3; 160 161 String getLongMessage(int length) { 162 StringBuilder sourceBuilder = new StringBuilder(length); 163 for (int i = 0; i < length / 10; i++) { 164 sourceBuilder.append("aaaaaaaaaa"); 165 } 166 return sourceBuilder.toString(); 167 } 168 169 public void testfips180_2_singleblock() { 170 171 digest.update(source1.getBytes(), 0, source1.length()); 172 173 byte[] computedDigest = digest.digest(); 174 175 assertNotNull("computed digest is null", computedDigest); 176 177 StringBuilder sb = new StringBuilder(); 178 for (int i = 0; i < computedDigest.length; i++) { 179 String res = Integer.toHexString(computedDigest[i] & 0xFF); 180 sb.append((res.length() == 1 ? "0" : "") + res); 181 } 182 assertEquals("computed and check digest differ", expected1, sb.toString()); 183 } 184 185 public void testfips180_2_multiblock() { 186 187 digest.update(source2.getBytes(), 0, source2.length()); 188 189 byte[] computedDigest = digest.digest(); 190 191 assertNotNull("computed digest is null", computedDigest); 192 193 StringBuilder sb = new StringBuilder(); 194 for (int i = 0; i < computedDigest.length; i++) { 195 String res = Integer.toHexString(computedDigest[i] & 0xFF); 196 sb.append((res.length() == 1 ? "0" : "") + res); 197 } 198 assertEquals("computed and check digest differ", expected2, sb.toString()); 199 } 200 201 public void testfips180_2_longMessage() { 202 203 digest.update(source3.getBytes(), 0, source3.length()); 204 205 byte[] computedDigest = digest.digest(); 206 207 assertNotNull("computed digest is null", computedDigest); 208 209 StringBuilder sb = new StringBuilder(); 210 for (int i = 0; i < computedDigest.length; i++) { 211 String res = Integer.toHexString(computedDigest[i] & 0xFF); 212 sb.append((res.length() == 1 ? "0" : "") + res); 213 } 214 assertEquals("computed and check digest differ", expected3, sb.toString()); 215 } 216 } 217