Home | History | Annotate | Download | only in crypto
      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