/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Alexander Y. Kleymenov
* @version $Revision$
*/
package javax.crypto.spec;
import java.io.Serializable;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.SecretKey;
/**
* A key specification for a <code>SecretKey</code> and also a secret key
* implementation that is provider-independent. It can be used for raw secret
* keys that can be specified as <code>byte[]</code>.
*/
public class SecretKeySpec implements SecretKey, KeySpec, Serializable {
// The 5.0 spec. doesn't declare this serialVersionUID field
// In order to be compatible it is explicitly declared here
// for details see HARMONY-233
private static final long serialVersionUID = 6577238317307289933L;
private final byte[] key;
private final String algorithm;
/**
* Creates a new <code>SecretKeySpec</code> for the specified key data and
* algorithm name.
*
* @param key
* the key data.
* @param algorithm
* the algorithm name.
* @throws IllegalArgumentException
* if the key data or the algorithm name is null or if the key
* data is empty.
*/
public SecretKeySpec(byte[] key, String algorithm) {
if (key == null) {
throw new IllegalArgumentException("key == null");
}
if (key.length == 0) {
throw new IllegalArgumentException("key.length == 0");
}
if (algorithm == null) {
throw new IllegalArgumentException("algorithm == null");
}
this.algorithm = algorithm;
this.key = new byte[key.length];
System.arraycopy(key, 0, this.key, 0, key.length);
}
/**
* Creates a new <code>SecretKeySpec</code> for the key data from the
* specified buffer <code>key</code> starting at <code>offset</code> with
* length <code>len</code> and the specified <code>algorithm</code> name.
*
* @param key
* the key data.
* @param offset
* the offset.
* @param len
* the size of the key data.
* @param algorithm
* the algorithm name.
* @throws IllegalArgumentException
* if the key data or the algorithm name is null, the key data
* is empty or <code>offset</code> and <code>len</code> do not
* specify a valid chunk in the buffer <code>key</code>.
* @throws ArrayIndexOutOfBoundsException
* if <code>offset</code> or <code>len</code> is negative.
*/
public SecretKeySpec(byte[] key, int offset, int len, String algorithm) {
if (key == null) {
throw new IllegalArgumentException("key == null");
}
if (key.length == 0) {
throw new IllegalArgumentException("key.length == 0");
}
if (len < 0 || offset < 0) {
throw new ArrayIndexOutOfBoundsException("len < 0 || offset < 0");
}
if (key.length - offset < len) {
throw new IllegalArgumentException("key too short");
}
if (algorithm == null) {
throw new IllegalArgumentException("algorithm == null");
}
this.algorithm = algorithm;
this.key = new byte[len];
System.arraycopy(key, offset, this.key, 0, len);
}
/**
* Returns the algorithm name.
*
* @return the algorithm name.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* Returns the name of the format used to encode the key.
*
* @return the format name "RAW".
*/
public String getFormat() {
return "RAW";
}
/**
* Returns the encoded form of this secret key.
*
* @return the encoded form of this secret key.
*/
public byte[] getEncoded() {
byte[] result = new byte[key.length];
System.arraycopy(key, 0, result, 0, key.length);
return result;
}
/**
* Returns the hash code of this <code>SecretKeySpec</code> object.
*
* @return the hash code.
*/
@Override
public int hashCode() {
int result = algorithm.length();
for (byte element : key) {
result += element;
}
return result;
}
/**
* Compares the specified object with this <code>SecretKeySpec</code>
* instance.
*
* @param obj
* the object to compare.
* @return true if the algorithm name and key of both object are equal,
* otherwise false.
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof SecretKeySpec)) {
return false;
}
SecretKeySpec ks = (SecretKeySpec) obj;
return (algorithm.equalsIgnoreCase(ks.algorithm))
&& (Arrays.equals(key, ks.key));
}
}