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 /** 19 * @author Alexander Y. Kleymenov 20 * @version $Revision$ 21 */ 22 23 package javax.crypto.spec; 24 25 import java.io.Serializable; 26 import java.security.spec.KeySpec; 27 import java.util.Arrays; 28 import javax.crypto.SecretKey; 29 30 /** 31 * A key specification for a <code>SecretKey</code> and also a secret key 32 * implementation that is provider-independent. It can be used for raw secret 33 * keys that can be specified as <code>byte[]</code>. 34 */ 35 public class SecretKeySpec implements SecretKey, KeySpec, Serializable { 36 37 // The 5.0 spec. doesn't declare this serialVersionUID field 38 // In order to be compatible it is explicitly declared here 39 // for details see HARMONY-233 40 private static final long serialVersionUID = 6577238317307289933L; 41 42 private final byte[] key; 43 private final String algorithm; 44 private final String format = "RAW"; 45 46 /** 47 * Creates a new <code>SecretKeySpec</code> for the specified key data and 48 * algorithm name. 49 * 50 * @param key 51 * the key data. 52 * @param algorithm 53 * the algorithm name. 54 * @throws IllegalArgumentException 55 * if the key data or the algorithm name is null or if the key 56 * data is empty. 57 */ 58 public SecretKeySpec(byte[] key, String algorithm) { 59 if (key == null) { 60 throw new IllegalArgumentException("key == null"); 61 } 62 if (key.length == 0) { 63 throw new IllegalArgumentException("key.length == 0"); 64 } 65 if (algorithm == null) { 66 throw new IllegalArgumentException("algorithm == null"); 67 } 68 69 this.algorithm = algorithm; 70 this.key = new byte[key.length]; 71 System.arraycopy(key, 0, this.key, 0, key.length); 72 } 73 74 /** 75 * Creates a new <code>SecretKeySpec</code> for the key data from the 76 * specified buffer <code>key</code> starting at <code>offset</code> with 77 * length <code>len</code> and the specified <code>algorithm</code> name. 78 * 79 * @param key 80 * the key data. 81 * @param offset 82 * the offset. 83 * @param len 84 * the size of the key data. 85 * @param algorithm 86 * the algorithm name. 87 * @throws IllegalArgumentException 88 * if the key data or the algorithm name is null, the key data 89 * is empty or <code>offset</code> and <code>len</code> do not 90 * specify a valid chunk in the buffer <code>key</code>. 91 * @throws ArrayIndexOutOfBoundsException 92 * if <code>offset</code> or <code>len</code> is negative. 93 */ 94 public SecretKeySpec(byte[] key, int offset, int len, String algorithm) { 95 if (key == null) { 96 throw new IllegalArgumentException("key == null"); 97 } 98 if (key.length == 0) { 99 throw new IllegalArgumentException("key.length == 0"); 100 } 101 // BEGIN android-changed 102 if (len < 0 || offset < 0) { 103 throw new ArrayIndexOutOfBoundsException("len < 0 || offset < 0"); 104 } 105 // END android-changed 106 if (key.length - offset < len) { 107 throw new IllegalArgumentException("key too short"); 108 } 109 if (algorithm == null) { 110 throw new IllegalArgumentException("algorithm == null"); 111 } 112 this.algorithm = algorithm; 113 this.key = new byte[len]; 114 System.arraycopy(key, offset, this.key, 0, len); 115 } 116 117 /** 118 * Returns the algorithm name. 119 * 120 * @return the algorithm name. 121 */ 122 public String getAlgorithm() { 123 return algorithm; 124 } 125 126 /** 127 * Returns the name of the format used to encode the key. 128 * 129 * @return the format name "RAW". 130 */ 131 public String getFormat() { 132 return format; 133 } 134 135 /** 136 * Returns the encoded form of this secret key. 137 * 138 * @return the encoded form of this secret key. 139 */ 140 public byte[] getEncoded() { 141 byte[] result = new byte[key.length]; 142 System.arraycopy(key, 0, result, 0, key.length); 143 return result; 144 } 145 146 /** 147 * Returns the hash code of this <code>SecretKeySpec</code> object. 148 * 149 * @return the hash code. 150 */ 151 @Override 152 public int hashCode() { 153 int result = algorithm.length(); 154 for (byte element : key) { 155 result += element; 156 } 157 return result; 158 } 159 160 /** 161 * Compares the specified object with this <code>SecretKeySpec</code> 162 * instance. 163 * 164 * @param obj 165 * the object to compare. 166 * @return true if the algorithm name and key of both object are equal, 167 * otherwise false. 168 */ 169 @Override 170 public boolean equals(Object obj) { 171 if (obj == this) { 172 return true; 173 } 174 if (!(obj instanceof SecretKeySpec)) { 175 return false; 176 } 177 SecretKeySpec ks = (SecretKeySpec) obj; 178 return (algorithm.equalsIgnoreCase(ks.algorithm)) 179 && (Arrays.equals(key, ks.key)); 180 } 181 } 182