1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage javax.crypto.spec;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.spec.KeySpec;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Arrays;
226186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.util.EmptyArray;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The key specification for a <i>password based encryption</i> key.
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Password based encryption is described in <a
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>.
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class PBEKeySpec implements KeySpec {
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private char[] password;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final byte[] salt;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final int iterationCount;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final int keyLength;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new <code>PBEKeySpec</code> with the specified password.
39ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param password
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the password.
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public PBEKeySpec(char[] password) {
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (password == null) {
45693eacca9fa67ad79d1b35dbaad61c5ac1ac457cElliott Hughes            this.password = EmptyArray.CHAR;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.password = new char[password.length];
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(password, 0, this.password, 0, password.length);
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        salt = null;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        iterationCount = 0;
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        keyLength = 0;
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new <code>PBEKeySpec</code> with the specified password, salt,
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * iteration count and the desired length of the derived key.
58ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param password
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the password.
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param salt
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the salt.
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param iterationCount
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the iteration count.
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param keyLength
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the desired key length of the derived key,
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the salt is null.
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the salt is empty, iteration count is zero or negative or
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             the key length is zero or negative.
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public PBEKeySpec(char[] password, byte[] salt, int iterationCount,
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                      int keyLength) {
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (salt == null) {
7680a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new NullPointerException("salt == null");
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (salt.length == 0) {
7980a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("salt.length == 0");
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (iterationCount <= 0) {
8280a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("iterationCount <= 0");
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (keyLength <= 0) {
8580a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("keyLength <= 0");
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (password == null) {
89693eacca9fa67ad79d1b35dbaad61c5ac1ac457cElliott Hughes            this.password = EmptyArray.CHAR;
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.password = new char[password.length];
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(password, 0, this.password, 0, password.length);
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.salt = new byte[salt.length];
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(salt, 0, this.salt, 0, salt.length);
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.iterationCount = iterationCount;
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.keyLength = keyLength;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new <code>PBEKeySpec</code> with the specified password, salt
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and iteration count.
103ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param password
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the password.
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param salt
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the salt.
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param iterationCount
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the iteration count.
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if salt is null.
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the salt is empty or iteration count is zero or negative.
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public PBEKeySpec(char[] password, byte[] salt, int iterationCount) {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (salt == null) {
11780a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new NullPointerException("salt == null");
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (salt.length == 0) {
12080a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("salt.length == 0");
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (iterationCount <= 0) {
12380a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalArgumentException("iterationCount <= 0");
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (password == null) {
127693eacca9fa67ad79d1b35dbaad61c5ac1ac457cElliott Hughes            this.password = EmptyArray.CHAR;
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.password = new char[password.length];
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(password, 0, this.password, 0, password.length);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.salt = new byte[salt.length];
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(salt, 0, this.salt, 0, salt.length);
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.iterationCount = iterationCount;
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.keyLength = 0;
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Clears the password by overwriting it.
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void clearPassword() {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Arrays.fill(password, '?');
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        password = null;
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a copy of the password of this key specification.
148ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a copy of the password of this key specification.
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the password has been cleared before.
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final char[] getPassword() {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (password == null) {
15580a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes            throw new IllegalStateException("The password has been cleared");
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        char[] result = new char[password.length];
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(password, 0, result, 0, password.length);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a copy of the salt of this key specification.
164ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a copy of the salt of this key specification or null if none is
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         specified.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] getSalt() {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (salt == null) {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] result = new byte[salt.length];
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(salt, 0, result, 0, salt.length);
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the iteration count of this key specification.
179ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the iteration count of this key specification.
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getIterationCount() {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return iterationCount;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the desired key length of the derived key.
188ce9ec01c0b6da3f3ba01e9c81cc3e5a461aabfb6Jesse Wilson     *
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the desired key length of the derived key.
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getKeyLength() {
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return keyLength;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
195