1/* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.crypto.provider; 27 28import java.security.MessageDigest; 29import java.security.KeyRep; 30import java.security.spec.InvalidKeySpecException; 31import java.util.Locale; 32import javax.crypto.SecretKey; 33import javax.crypto.spec.PBEKeySpec; 34 35import jdk.internal.ref.CleanerFactory; 36 37/** 38 * This class represents a PBE key. 39 * 40 * @author Jan Luehe 41 * 42 */ 43final class PBEKey implements SecretKey { 44 45 static final long serialVersionUID = -2234768909660948176L; 46 47 private byte[] key; 48 49 private String type; 50 51 /** 52 * Creates a PBE key from a given PBE key specification. 53 * 54 * @param keytype the given PBE key specification 55 */ 56 PBEKey(PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException { 57 char[] passwd = keySpec.getPassword(); 58 if (passwd == null) { 59 // Should allow an empty password. 60 passwd = new char[0]; 61 } 62 // Accept "\0" to signify "zero-length password with no terminator". 63 if (!(passwd.length == 1 && passwd[0] == 0)) { 64 for (int i=0; i<passwd.length; i++) { 65 if ((passwd[i] < '\u0020') || (passwd[i] > '\u007E')) { 66 throw new InvalidKeySpecException("Password is not ASCII"); 67 } 68 } 69 } 70 this.key = new byte[passwd.length]; 71 for (int i=0; i<passwd.length; i++) 72 this.key[i] = (byte) (passwd[i] & 0x7f); 73 java.util.Arrays.fill(passwd, ' '); 74 type = keytype; 75 76 // Use the cleaner to zero the key when no longer referenced 77 final byte[] k = this.key; 78 CleanerFactory.cleaner().register(this, 79 () -> java.util.Arrays.fill(k, (byte)0x00)); 80 } 81 82 public byte[] getEncoded() { 83 return this.key.clone(); 84 } 85 86 public String getAlgorithm() { 87 return type; 88 } 89 90 public String getFormat() { 91 return "RAW"; 92 } 93 94 /** 95 * Calculates a hash code value for the object. 96 * Objects that are equal will also have the same hashcode. 97 */ 98 public int hashCode() { 99 int retval = 0; 100 for (int i = 1; i < this.key.length; i++) { 101 retval += this.key[i] * i; 102 } 103 return(retval ^= getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode()); 104 } 105 106 public boolean equals(Object obj) { 107 if (obj == this) 108 return true; 109 110 if (!(obj instanceof SecretKey)) 111 return false; 112 113 SecretKey that = (SecretKey)obj; 114 115 if (!(that.getAlgorithm().equalsIgnoreCase(type))) 116 return false; 117 118 byte[] thatEncoded = that.getEncoded(); 119 boolean ret = MessageDigest.isEqual(this.key, thatEncoded); 120 java.util.Arrays.fill(thatEncoded, (byte)0x00); 121 return ret; 122 } 123 124 /** 125 * readObject is called to restore the state of this key from 126 * a stream. 127 */ 128 private void readObject(java.io.ObjectInputStream s) 129 throws java.io.IOException, ClassNotFoundException 130 { 131 s.defaultReadObject(); 132 key = key.clone(); 133 } 134 135 136 /** 137 * Replace the PBE key to be serialized. 138 * 139 * @return the standard KeyRep object to be serialized 140 * 141 * @throws java.io.ObjectStreamException if a new object representing 142 * this PBE key could not be created 143 */ 144 private Object writeReplace() throws java.io.ObjectStreamException { 145 return new KeyRep(KeyRep.Type.SECRET, 146 getAlgorithm(), 147 getFormat(), 148 getEncoded()); 149 } 150} 151