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