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.InvalidKeyException;
32 import javax.crypto.SecretKey;
33 import javax.crypto.spec.DESedeKeySpec;
34 
35 import jdk.internal.ref.CleanerFactory;
36 
37 /**
38  * This class represents a DES-EDE key.
39  *
40  * @author Jan Luehe
41  *
42  */
43 
44 final class DESedeKey implements SecretKey {
45 
46     static final long serialVersionUID = 2463986565756745178L;
47 
48     private byte[] key;
49 
50     /**
51      * Creates a DES-EDE key from a given key.
52      *
53      * @param key the given key
54      *
55      * @exception InvalidKeyException if the given key has a wrong size
56      */
DESedeKey(byte[] key)57     DESedeKey(byte[] key) throws InvalidKeyException {
58         this(key, 0);
59     }
60 
61     /**
62      * Uses the first 24 bytes in <code>key</code>, beginning at
63      * <code>offset</code>, as the DES-EDE key
64      *
65      * @param key the buffer with the DES-EDE key
66      * @param offset the offset in <code>key</code>, where the DES-EDE key
67      * starts
68      *
69      * @exception InvalidKeyException if the given key has a wrong size
70      */
DESedeKey(byte[] key, int offset)71     DESedeKey(byte[] key, int offset) throws InvalidKeyException {
72 
73         if (key==null || ((key.length-offset)<DESedeKeySpec.DES_EDE_KEY_LEN)) {
74             throw new InvalidKeyException("Wrong key size");
75         }
76         this.key = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
77         System.arraycopy(key, offset, this.key, 0,
78                          DESedeKeySpec.DES_EDE_KEY_LEN);
79         DESKeyGenerator.setParityBit(this.key, 0);
80         DESKeyGenerator.setParityBit(this.key, 8);
81         DESKeyGenerator.setParityBit(this.key, 16);
82 
83         // Use the cleaner to zero the key when no longer referenced
84         final byte[] k = this.key;
85         CleanerFactory.cleaner().register(this,
86                 () -> java.util.Arrays.fill(k, (byte)0x00));
87     }
88 
getEncoded()89     public byte[] getEncoded() {
90         // The key is zeroized by finalize()
91         // The reachability fence ensures finalize() isn't called early
92         byte[] result = key.clone();
93         Reference.reachabilityFence(this);
94         return result;
95     }
96 
getAlgorithm()97     public String getAlgorithm() {
98         return "DESede";
99     }
100 
getFormat()101     public String getFormat() {
102         return "RAW";
103     }
104 
105     /**
106      * Calculates a hash code value for the object.
107      * Objects that are equal will also have the same hashcode.
108      */
hashCode()109     public int hashCode() {
110         int retval = 0;
111         for (int i = 1; i < this.key.length; i++) {
112             retval += this.key[i] * i;
113         }
114         return(retval ^= "desede".hashCode());
115     }
116 
equals(Object obj)117     public boolean equals(Object obj) {
118         if (this == obj)
119             return true;
120 
121         if (!(obj instanceof SecretKey))
122             return false;
123 
124         String thatAlg = ((SecretKey)obj).getAlgorithm();
125         if (!(thatAlg.equalsIgnoreCase("DESede"))
126             && !(thatAlg.equalsIgnoreCase("TripleDES")))
127             return false;
128 
129         byte[] thatKey = ((SecretKey)obj).getEncoded();
130         boolean ret = MessageDigest.isEqual(this.key, thatKey);
131         java.util.Arrays.fill(thatKey, (byte)0x00);
132         return ret;
133     }
134 
135     /**
136      * readObject is called to restore the state of this key from
137      * a stream.
138      */
readObject(java.io.ObjectInputStream s)139     private void readObject(java.io.ObjectInputStream s)
140          throws java.io.IOException, ClassNotFoundException
141     {
142         s.defaultReadObject();
143         key = key.clone();
144     }
145 
146     /**
147      * Replace the DESede key to be serialized.
148      *
149      * @return the standard KeyRep object to be serialized
150      *
151      * @throws java.io.ObjectStreamException if a new object representing
152      * this DESede key could not be created
153      */
writeReplace()154     private Object writeReplace() throws java.io.ObjectStreamException {
155         return new KeyRep(KeyRep.Type.SECRET,
156                         getAlgorithm(),
157                         getFormat(),
158                         getEncoded());
159     }
160 }
161