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.InvalidKeyException;
31import javax.crypto.SecretKey;
32import javax.crypto.spec.DESKeySpec;
33
34import jdk.internal.ref.CleanerFactory;
35
36/**
37 * This class represents a DES key.
38 *
39 * @author Jan Luehe
40 *
41 */
42
43final class DESKey implements SecretKey {
44
45    static final long serialVersionUID = 7724971015953279128L;
46
47    private byte[] key;
48
49    /**
50     * Uses the first 8 bytes of the given key as the DES key.
51     *
52     * @param key the buffer with the DES key bytes.
53     *
54     * @exception InvalidKeyException if less than 8 bytes are available for
55     * the key.
56     */
57    DESKey(byte[] key) throws InvalidKeyException {
58        this(key, 0);
59    }
60
61    /**
62     * Uses the first 8 bytes in <code>key</code>, beginning at
63     * <code>offset</code>, as the DES key
64     *
65     * @param key the buffer with the DES key bytes.
66     * @param offset the offset in <code>key</code>, where the DES key bytes
67     * start.
68     *
69     * @exception InvalidKeyException if less than 8 bytes are available for
70     * the key.
71     */
72    DESKey(byte[] key, int offset) throws InvalidKeyException {
73        if (key == null || key.length - offset < DESKeySpec.DES_KEY_LEN) {
74            throw new InvalidKeyException("Wrong key size");
75        }
76        this.key = new byte[DESKeySpec.DES_KEY_LEN];
77        System.arraycopy(key, offset, this.key, 0, DESKeySpec.DES_KEY_LEN);
78        DESKeyGenerator.setParityBit(this.key, 0);
79
80        // Use the cleaner to zero the key when no longer referenced
81        final byte[] k = this.key;
82        CleanerFactory.cleaner().register(this,
83                () -> java.util.Arrays.fill(k, (byte)0x00));
84    }
85
86    public byte[] getEncoded() {
87        // Return a copy of the key, rather than a reference,
88        // so that the key data cannot be modified from outside
89        return this.key.clone();
90    }
91
92    public String getAlgorithm() {
93        return "DES";
94    }
95
96    public String getFormat() {
97        return "RAW";
98    }
99
100    /**
101     * Calculates a hash code value for the object.
102     * Objects that are equal will also have the same hashcode.
103     */
104    public int hashCode() {
105        int retval = 0;
106        for (int i = 1; i < this.key.length; i++) {
107            retval += this.key[i] * i;
108        }
109        return(retval ^= "des".hashCode());
110    }
111
112    public boolean equals(Object obj) {
113        if (this == obj)
114            return true;
115
116        if (!(obj instanceof SecretKey))
117            return false;
118
119        String thatAlg = ((SecretKey)obj).getAlgorithm();
120        if (!(thatAlg.equalsIgnoreCase("DES")))
121            return false;
122
123        byte[] thatKey = ((SecretKey)obj).getEncoded();
124        boolean ret = MessageDigest.isEqual(this.key, thatKey);
125        java.util.Arrays.fill(thatKey, (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     * Replace the DES key to be serialized.
142     *
143     * @return the standard KeyRep object to be serialized
144     *
145     * @throws java.io.ObjectStreamException if a new object representing
146     * this DES key could not be created
147     */
148    private Object writeReplace() throws java.io.ObjectStreamException {
149        return new KeyRep(KeyRep.Type.SECRET,
150                        getAlgorithm(),
151                        getFormat(),
152                        getEncoded());
153    }
154}
155