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 26 package com.sun.crypto.provider; 27 28 import java.lang.ref.Reference; 29 import java.security.MessageDigest; 30 import java.security.KeyRep; 31 import java.security.spec.InvalidKeySpecException; 32 import java.util.Locale; 33 import javax.crypto.SecretKey; 34 import javax.crypto.spec.PBEKeySpec; 35 36 import jdk.internal.ref.CleanerFactory; 37 38 /** 39 * This class represents a PBE key. 40 * 41 * @author Jan Luehe 42 * 43 */ 44 final class PBEKey implements SecretKey { 45 46 static final long serialVersionUID = -2234768909660948176L; 47 48 private byte[] key; 49 50 private String type; 51 52 /** 53 * Creates a PBE key from a given PBE key specification. 54 * 55 * @param keytype the given PBE key specification 56 */ 57 PBEKey(PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException { 58 char[] passwd = keySpec.getPassword(); 59 if (passwd == null) { 60 // Should allow an empty password. 61 passwd = new char[0]; 62 } 63 // Accept "\0" to signify "zero-length password with no terminator". 64 if (!(passwd.length == 1 && passwd[0] == 0)) { 65 for (int i=0; i<passwd.length; i++) { 66 if ((passwd[i] < '\u0020') || (passwd[i] > '\u007E')) { 67 throw new InvalidKeySpecException("Password is not ASCII"); 68 } 69 } 70 } 71 this.key = new byte[passwd.length]; 72 for (int i=0; i<passwd.length; i++) 73 this.key[i] = (byte) (passwd[i] & 0x7f); 74 java.util.Arrays.fill(passwd, ' '); 75 type = keytype; 76 77 // Use the cleaner to zero the key when no longer referenced 78 final byte[] k = this.key; 79 CleanerFactory.cleaner().register(this, 80 () -> java.util.Arrays.fill(k, (byte)0x00)); 81 } 82 83 public byte[] getEncoded() { 84 // The key is zeroized by finalize() 85 // The reachability fence ensures finalize() isn't called early 86 byte[] result = key.clone(); 87 Reference.reachabilityFence(this); 88 return result; 89 } 90 91 public String getAlgorithm() { 92 return type; 93 } 94 95 public String getFormat() { 96 return "RAW"; 97 } 98 99 /** 100 * Calculates a hash code value for the object. 101 * Objects that are equal will also have the same hashcode. 102 */ 103 public int hashCode() { 104 int retval = 0; 105 for (int i = 1; i < this.key.length; i++) { 106 retval += this.key[i] * i; 107 } 108 return(retval ^= getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode()); 109 } 110 111 public boolean equals(Object obj) { 112 if (obj == this) 113 return true; 114 115 if (!(obj instanceof SecretKey)) 116 return false; 117 118 SecretKey that = (SecretKey)obj; 119 120 if (!(that.getAlgorithm().equalsIgnoreCase(type))) 121 return false; 122 123 byte[] thatEncoded = that.getEncoded(); 124 boolean ret = MessageDigest.isEqual(this.key, thatEncoded); 125 java.util.Arrays.fill(thatEncoded, (byte)0x00); 126 return ret; 127 } 128 129 /** 130 * readObject is called to restore the state of this key from 131 * a stream. 132 */ 133 private void readObject(java.io.ObjectInputStream s) 134 throws java.io.IOException, ClassNotFoundException 135 { 136 s.defaultReadObject(); 137 key = key.clone(); 138 } 139 140 141 /** 142 * Replace the PBE key to be serialized. 143 * 144 * @return the standard KeyRep object to be serialized 145 * 146 * @throws java.io.ObjectStreamException if a new object representing 147 * this PBE key could not be created 148 */ 149 private Object writeReplace() throws java.io.ObjectStreamException { 150 return new KeyRep(KeyRep.Type.SECRET, 151 getAlgorithm(), 152 getFormat(), 153 getEncoded()); 154 } 155 }