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 18 package javax.crypto.spec; 19 20 import java.security.spec.KeySpec; 21 import java.util.Arrays; 22 23 /** 24 * The key specification for a <i>password based encryption</i> key. 25 * <p> 26 * Password based encryption is described in <a 27 * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>. 28 */ 29 public class PBEKeySpec implements KeySpec { 30 31 private char[] password; 32 private final byte[] salt; 33 private final int iterationCount; 34 private final int keyLength; 35 36 /** 37 * Creates a new <code>PBEKeySpec</code> with the specified password. 38 * 39 * @param password 40 * the password. 41 */ 42 public PBEKeySpec(char[] password) { 43 if (password == null) { 44 this.password = new char[0]; 45 } else { 46 this.password = new char[password.length]; 47 System.arraycopy(password, 0, this.password, 0, password.length); 48 } 49 salt = null; 50 iterationCount = 0; 51 keyLength = 0; 52 } 53 54 /** 55 * Creates a new <code>PBEKeySpec</code> with the specified password, salt, 56 * iteration count and the desired length of the derived key. 57 * 58 * @param password 59 * the password. 60 * @param salt 61 * the salt. 62 * @param iterationCount 63 * the iteration count. 64 * @param keyLength 65 * the desired key length of the derived key, 66 * @throws NullPointerException 67 * if the salt is null. 68 * @throws IllegalArgumentException 69 * if the salt is empty, iteration count is zero or negative or 70 * the key length is zero or negative. 71 */ 72 public PBEKeySpec(char[] password, byte[] salt, int iterationCount, 73 int keyLength) { 74 if (salt == null) { 75 throw new NullPointerException("salt == null"); 76 } 77 if (salt.length == 0) { 78 throw new IllegalArgumentException("salt.length == 0"); 79 } 80 if (iterationCount <= 0) { 81 throw new IllegalArgumentException("iterationCount <= 0"); 82 } 83 if (keyLength <= 0) { 84 throw new IllegalArgumentException("keyLength <= 0"); 85 } 86 87 if (password == null) { 88 this.password = new char[0]; 89 } else { 90 this.password = new char[password.length]; 91 System.arraycopy(password, 0, this.password, 0, password.length); 92 } 93 this.salt = new byte[salt.length]; 94 System.arraycopy(salt, 0, this.salt, 0, salt.length); 95 this.iterationCount = iterationCount; 96 this.keyLength = keyLength; 97 } 98 99 /** 100 * Creates a new <code>PBEKeySpec</code> with the specified password, salt 101 * and iteration count. 102 * 103 * @param password 104 * the password. 105 * @param salt 106 * the salt. 107 * @param iterationCount 108 * the iteration count. 109 * @throws NullPointerException 110 * if salt is null. 111 * @throws IllegalArgumentException 112 * if the salt is empty or iteration count is zero or negative. 113 */ 114 public PBEKeySpec(char[] password, byte[] salt, int iterationCount) { 115 if (salt == null) { 116 throw new NullPointerException("salt == null"); 117 } 118 if (salt.length == 0) { 119 throw new IllegalArgumentException("salt.length == 0"); 120 } 121 if (iterationCount <= 0) { 122 throw new IllegalArgumentException("iterationCount <= 0"); 123 } 124 125 if (password == null) { 126 this.password = new char[0]; 127 } else { 128 this.password = new char[password.length]; 129 System.arraycopy(password, 0, this.password, 0, password.length); 130 } 131 this.salt = new byte[salt.length]; 132 System.arraycopy(salt, 0, this.salt, 0, salt.length); 133 this.iterationCount = iterationCount; 134 this.keyLength = 0; 135 } 136 137 /** 138 * Clears the password by overwriting it. 139 */ 140 public final void clearPassword() { 141 Arrays.fill(password, '?'); 142 password = null; 143 } 144 145 /** 146 * Returns a copy of the password of this key specification. 147 * 148 * @return a copy of the password of this key specification. 149 * @throws IllegalStateException 150 * if the password has been cleared before. 151 */ 152 public final char[] getPassword() { 153 if (password == null) { 154 throw new IllegalStateException("The password has been cleared"); 155 } 156 char[] result = new char[password.length]; 157 System.arraycopy(password, 0, result, 0, password.length); 158 return result; 159 } 160 161 /** 162 * Returns a copy of the salt of this key specification. 163 * 164 * @return a copy of the salt of this key specification or null if none is 165 * specified. 166 */ 167 public final byte[] getSalt() { 168 if (salt == null) { 169 return null; 170 } 171 byte[] result = new byte[salt.length]; 172 System.arraycopy(salt, 0, result, 0, salt.length); 173 return result; 174 } 175 176 /** 177 * Returns the iteration count of this key specification. 178 * 179 * @return the iteration count of this key specification. 180 */ 181 public final int getIterationCount() { 182 return iterationCount; 183 } 184 185 /** 186 * Returns the desired key length of the derived key. 187 * 188 * @return the desired key length of the derived key. 189 */ 190 public final int getKeyLength() { 191 return keyLength; 192 } 193 } 194