1 /* 2 * Copyright (C) 2010 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 17 package libcore.javax.crypto; 18 19 import java.security.spec.InvalidKeySpecException; 20 import java.security.spec.KeySpec; 21 import java.util.Arrays; 22 import javax.crypto.SecretKey; 23 import javax.crypto.SecretKeyFactory; 24 import javax.crypto.spec.PBEKeySpec; 25 import junit.framework.TestCase; 26 import libcore.java.security.StandardNames; 27 28 public class SecretKeyFactoryTest extends TestCase { 29 30 private static final char[] PASSWORD = "google".toCharArray(); 31 /** 32 * Salts should be random to reduce effectiveness of dictionary 33 * attacks, but need not be kept secret from attackers. For more 34 * information, see http://en.wikipedia.org/wiki/Salt_(cryptography) 35 */ 36 private static final byte[] SALT = {0, 1, 2, 3, 4, 5, 6, 7}; 37 /** 38 * The number of iterations should be higher for production 39 * strength protection. The tolerable value may vary from device 40 * to device, but 8192 should be acceptable for PBKDF2 on a Nexus One. 41 */ 42 private static final int ITERATIONS = 1024; 43 private static final int KEY_LENGTH = 128; 44 45 public void test_PBKDF2_required_parameters() throws Exception { 46 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 47 48 // PBEKeySpec validates arguments most to be non-null, non-empty, postive, etc. 49 // Focus on insufficient PBEKeySpecs 50 51 // PBEKeySpecs password only constructor 52 try { 53 KeySpec ks = new PBEKeySpec(null); 54 factory.generateSecret(ks); 55 fail(); 56 } catch (InvalidKeySpecException expected) { 57 } 58 try { 59 KeySpec ks = new PBEKeySpec(new char[0]); 60 factory.generateSecret(ks); 61 fail(); 62 } catch (InvalidKeySpecException expected) { 63 } 64 try { 65 KeySpec ks = new PBEKeySpec(PASSWORD); 66 factory.generateSecret(ks); 67 fail(); 68 } catch (InvalidKeySpecException expected) { 69 } 70 71 72 // PBEKeySpecs constructor without key length 73 try { 74 KeySpec ks = new PBEKeySpec(null, SALT, ITERATIONS); 75 factory.generateSecret(ks); 76 fail(); 77 } catch (InvalidKeySpecException expected) { 78 } 79 try { 80 KeySpec ks = new PBEKeySpec(new char[0], SALT, ITERATIONS); 81 factory.generateSecret(ks); 82 fail(); 83 } catch (InvalidKeySpecException expected) { 84 } 85 try { 86 KeySpec ks = new PBEKeySpec(PASSWORD, SALT, ITERATIONS); 87 factory.generateSecret(ks); 88 fail(); 89 } catch (InvalidKeySpecException expected) { 90 } 91 92 try { 93 KeySpec ks = new PBEKeySpec(null, SALT, ITERATIONS, KEY_LENGTH); 94 factory.generateSecret(ks); 95 fail(); 96 } catch (IllegalArgumentException expected) { 97 } 98 99 try { 100 KeySpec ks = new PBEKeySpec(new char[0], SALT, ITERATIONS, KEY_LENGTH); 101 factory.generateSecret(ks); 102 fail(); 103 } catch (IllegalArgumentException expected) { 104 } 105 106 KeySpec ks = new PBEKeySpec(PASSWORD, SALT, ITERATIONS, KEY_LENGTH); 107 factory.generateSecret(ks); 108 } 109 110 public void test_PBKDF2_b3059950() throws Exception { 111 byte[] expected = new byte[] { 112 (byte)0x70, (byte)0x74, (byte)0xdb, (byte)0x72, 113 (byte)0x35, (byte)0xd4, (byte)0x11, (byte)0x68, 114 (byte)0x83, (byte)0x7c, (byte)0x14, (byte)0x1f, 115 (byte)0xf6, (byte)0x4a, (byte)0xb0, (byte)0x54 116 }; 117 test_PBKDF2_UTF8(PASSWORD, SALT, ITERATIONS, KEY_LENGTH, expected); 118 test_PBKDF2_8BIT(PASSWORD, SALT, ITERATIONS, KEY_LENGTH, expected); 119 } 120 121 /** 122 * 64-bit Test vector from RFC 3211 123 * 124 * See also org.bouncycastle.crypto.test.PKCS5Test 125 */ 126 public void test_PBKDF2_rfc3211_64() throws Exception { 127 char[] password = "password".toCharArray(); 128 byte[] salt = new byte[] { 129 (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78, 130 (byte)0x78, (byte)0x56, (byte)0x34, (byte)0x12 131 }; 132 int iterations = 5; 133 int keyLength = 64; 134 byte[] expected = new byte[] { 135 (byte)0xD1, (byte)0xDA, (byte)0xA7, (byte)0x86, 136 (byte)0x15, (byte)0xF2, (byte)0x87, (byte)0xE6 137 }; 138 test_PBKDF2_UTF8(password, salt, iterations, keyLength, expected); 139 test_PBKDF2_8BIT(password, salt, iterations, keyLength, expected); 140 } 141 142 /** 143 * 192-bit Test vector from RFC 3211 144 * 145 * See also org.bouncycastle.crypto.test.PKCS5Test 146 */ 147 public void test_PBKDF2_rfc3211_192() throws Exception { 148 char[] password = ("All n-entities must communicate with other " 149 + "n-entities via n-1 entiteeheehees").toCharArray(); 150 byte[] salt = new byte[] { 151 (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78, 152 (byte)0x78, (byte)0x56, (byte)0x34, (byte)0x12 153 }; 154 int iterations = 500; 155 int keyLength = 192; 156 byte[] expected = new byte[] { 157 (byte)0x6a, (byte)0x89, (byte)0x70, (byte)0xbf, (byte)0x68, (byte)0xc9, 158 (byte)0x2c, (byte)0xae, (byte)0xa8, (byte)0x4a, (byte)0x8d, (byte)0xf2, 159 (byte)0x85, (byte)0x10, (byte)0x85, (byte)0x86, (byte)0x07, (byte)0x12, 160 (byte)0x63, (byte)0x80, (byte)0xcc, (byte)0x47, (byte)0xab, (byte)0x2d 161 }; 162 test_PBKDF2_UTF8(password, salt, iterations, keyLength, expected); 163 test_PBKDF2_8BIT(password, salt, iterations, keyLength, expected); 164 } 165 166 /** 167 * Unicode Test vector for b/8312059. 168 * 169 * See also https://code.google.com/p/android/issues/detail?id=40578 170 */ 171 public void test_PBKDF2_b8312059() throws Exception { 172 173 char[] password = "\u0141\u0142".toCharArray(); 174 byte[] salt = "salt".getBytes(); 175 int iterations = 4096; 176 int keyLength = 160; 177 byte[] expected_utf8 = new byte[] { 178 (byte)0x4c, (byte)0xe0, (byte)0x6a, (byte)0xb8, (byte)0x48, (byte)0x04, 179 (byte)0xb7, (byte)0xe7, (byte)0x72, (byte)0xf2, (byte)0xaf, (byte)0x5e, 180 (byte)0x54, (byte)0xe9, (byte)0x03, (byte)0xad, (byte)0x59, (byte)0x64, 181 (byte)0x8b, (byte)0xab 182 }; 183 byte[] expected_8bit = new byte[] { 184 (byte)0x6e, (byte)0x43, (byte)0xe0, (byte)0x18, (byte)0xc5, (byte)0x50, 185 (byte)0x0d, (byte)0xa7, (byte)0xfe, (byte)0x7a, (byte)0x44, (byte)0x4d, 186 (byte)0x99, (byte)0x5d, (byte)0x8c, (byte)0xae, (byte)0xc1, (byte)0xc9, 187 (byte)0x17, (byte)0xce 188 }; 189 test_PBKDF2_UTF8(password, salt, iterations, keyLength, expected_utf8); 190 test_PBKDF2_8BIT(password, salt, iterations, keyLength, expected_8bit); 191 } 192 193 private void test_PBKDF2_8BIT(char[] password, byte[] salt, int iterations, int keyLength, 194 byte[] expected) throws Exception { 195 if (!StandardNames.IS_RI) { 196 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1And8bit"); 197 KeySpec ks = new PBEKeySpec(password, salt, iterations, keyLength); 198 SecretKey key = factory.generateSecret(ks); 199 assertTrue(Arrays.equals(expected, key.getEncoded())); 200 } 201 202 } 203 204 private void test_PBKDF2_UTF8(char[] password, byte[] salt, int iterations, int keyLength, 205 byte[] expected) throws Exception { 206 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 207 KeySpec ks = new PBEKeySpec(password, salt, iterations, keyLength); 208 SecretKey key = factory.generateSecret(ks); 209 assertTrue(Arrays.equals(expected, key.getEncoded())); 210 211 } 212 } 213