Path: blob/master/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
41159 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto.spec;2627import jdk.internal.access.JavaxCryptoSpecAccess;28import jdk.internal.access.SharedSecrets;2930import java.security.MessageDigest;31import java.security.spec.KeySpec;32import java.util.Arrays;33import java.util.Locale;34import javax.crypto.SecretKey;3536/**37* This class specifies a secret key in a provider-independent fashion.38*39* <p>It can be used to construct a <code>SecretKey</code> from a byte array,40* without having to go through a (provider-based)41* <code>SecretKeyFactory</code>.42*43* <p>This class is only useful for raw secret keys that can be represented as44* a byte array and have no key parameters associated with them, e.g., DES or45* Triple DES keys.46*47* @author Jan Luehe48*49* @see javax.crypto.SecretKey50* @see javax.crypto.SecretKeyFactory51* @since 1.452*/53public class SecretKeySpec implements KeySpec, SecretKey {5455@java.io.Serial56private static final long serialVersionUID = 6577238317307289933L;5758/**59* The secret key.60*61* @serial62*/63private byte[] key;6465/**66* The name of the algorithm associated with this key.67*68* @serial69*/70private String algorithm;7172static {73SharedSecrets.setJavaxCryptoSpecAccess(74new JavaxCryptoSpecAccess() {75@Override76public void clearSecretKeySpec(SecretKeySpec keySpec) {77keySpec.clear();78}79});80}8182/**83* Constructs a secret key from the given byte array.84*85* <p>This constructor does not check if the given bytes indeed specify a86* secret key of the specified algorithm. For example, if the algorithm is87* DES, this constructor does not check if <code>key</code> is 8 bytes88* long, and also does not check for weak or semi-weak keys.89* In order for those checks to be performed, an algorithm-specific90* <i>key specification</i> class (in this case:91* {@link DESKeySpec DESKeySpec})92* should be used.93*94* @param key the key material of the secret key. The contents of95* the array are copied to protect against subsequent modification.96* @param algorithm the name of the secret-key algorithm to be associated97* with the given key material.98* See the <a href="{@docRoot}/../specs/security/standard-names.html">99* Java Security Standard Algorithm Names</a> document100* for information about standard algorithm names.101* @exception IllegalArgumentException if <code>algorithm</code>102* is null or <code>key</code> is null or empty.103*/104public SecretKeySpec(byte[] key, String algorithm) {105if (key == null || algorithm == null) {106throw new IllegalArgumentException("Missing argument");107}108if (key.length == 0) {109throw new IllegalArgumentException("Empty key");110}111this.key = key.clone();112this.algorithm = algorithm;113}114115/**116* Constructs a secret key from the given byte array, using the first117* <code>len</code> bytes of <code>key</code>, starting at118* <code>offset</code> inclusive.119*120* <p> The bytes that constitute the secret key are121* those between <code>key[offset]</code> and122* <code>key[offset+len-1]</code> inclusive.123*124* <p>This constructor does not check if the given bytes indeed specify a125* secret key of the specified algorithm. For example, if the algorithm is126* DES, this constructor does not check if <code>key</code> is 8 bytes127* long, and also does not check for weak or semi-weak keys.128* In order for those checks to be performed, an algorithm-specific key129* specification class (in this case:130* {@link DESKeySpec DESKeySpec})131* must be used.132*133* @param key the key material of the secret key. The first134* <code>len</code> bytes of the array beginning at135* <code>offset</code> inclusive are copied to protect136* against subsequent modification.137* @param offset the offset in <code>key</code> where the key material138* starts.139* @param len the length of the key material.140* @param algorithm the name of the secret-key algorithm to be associated141* with the given key material.142* See the <a href="{@docRoot}/../specs/security/standard-names.html">143* Java Security Standard Algorithm Names</a> document144* for information about standard algorithm names.145* @exception IllegalArgumentException if <code>algorithm</code>146* is null or <code>key</code> is null, empty, or too short,147* i.e. {@code key.length-offset<len}.148* @exception ArrayIndexOutOfBoundsException is thrown if149* <code>offset</code> or <code>len</code> index bytes outside the150* <code>key</code>.151*/152public SecretKeySpec(byte[] key, int offset, int len, String algorithm) {153if (key == null || algorithm == null) {154throw new IllegalArgumentException("Missing argument");155}156if (key.length == 0) {157throw new IllegalArgumentException("Empty key");158}159if (key.length-offset < len) {160throw new IllegalArgumentException161("Invalid offset/length combination");162}163if (len < 0) {164throw new ArrayIndexOutOfBoundsException("len is negative");165}166this.key = new byte[len];167System.arraycopy(key, offset, this.key, 0, len);168this.algorithm = algorithm;169}170171/**172* Returns the name of the algorithm associated with this secret key.173*174* @return the secret key algorithm.175*/176public String getAlgorithm() {177return this.algorithm;178}179180/**181* Returns the name of the encoding format for this secret key.182*183* @return the string "RAW".184*/185public String getFormat() {186return "RAW";187}188189/**190* Returns the key material of this secret key.191*192* @return the key material. Returns a new array193* each time this method is called.194*/195public byte[] getEncoded() {196return this.key.clone();197}198199/**200* Calculates a hash code value for the object.201* Objects that are equal will also have the same hashcode.202*/203public int hashCode() {204int retval = 0;205for (int i = 1; i < this.key.length; i++) {206retval += this.key[i] * i;207}208if (this.algorithm.equalsIgnoreCase("TripleDES"))209return (retval ^= "desede".hashCode());210else211return (retval ^=212this.algorithm.toLowerCase(Locale.ENGLISH).hashCode());213}214215/**216* Tests for equality between the specified object and this217* object. Two SecretKeySpec objects are considered equal if218* they are both SecretKey instances which have the219* same case-insensitive algorithm name and key encoding.220*221* @param obj the object to test for equality with this object.222*223* @return true if the objects are considered equal, false if224* <code>obj</code> is null or otherwise.225*/226public boolean equals(Object obj) {227if (this == obj)228return true;229230if (!(obj instanceof SecretKey))231return false;232233String thatAlg = ((SecretKey)obj).getAlgorithm();234if (!(thatAlg.equalsIgnoreCase(this.algorithm))) {235if ((!(thatAlg.equalsIgnoreCase("DESede"))236|| !(this.algorithm.equalsIgnoreCase("TripleDES")))237&& (!(thatAlg.equalsIgnoreCase("TripleDES"))238|| !(this.algorithm.equalsIgnoreCase("DESede"))))239return false;240}241242byte[] thatKey = ((SecretKey)obj).getEncoded();243try {244return MessageDigest.isEqual(this.key, thatKey);245} finally {246if (thatKey != null) {247Arrays.fill(thatKey, (byte)0);248}249}250}251252/**253* Clear the key bytes inside.254*/255void clear() {256Arrays.fill(key, (byte)0);257}258}259260261