1/*
2 * Copyright (c) 1997, 2007, 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 javax.crypto.spec;
27
28import java.security.InvalidKeyException;
29
30/**
31 * This class specifies a DES key.
32 *
33 * @author Jan Luehe
34 *
35 * @since 1.4
36 */
37public class DESKeySpec implements java.security.spec.KeySpec {
38
39    /**
40     * The constant which defines the length of a DES key in bytes.
41     */
42    public static final int DES_KEY_LEN = 8;
43
44    private byte[] key;
45
46    /*
47     * Weak/semi-weak keys copied from FIPS 74.
48     *
49     * "...The first 6 keys have duals different than themselves, hence
50     * each is both a key and a dual giving 12 keys with duals. The last
51     * four keys equal their duals, and are called self-dual keys..."
52     *
53     * 1.   E001E001F101F101    01E001E001F101F1
54     * 2.   FE1FFE1FFEOEFEOE    1FFE1FFEOEFEOEFE
55     * 3.   E01FE01FF10EF10E    1FE01FEOOEF10EF1
56     * 4.   01FE01FE01FE01FE    FE01FE01FE01FE01
57     * 5.   011F011F010E010E    1F011F010E010E01
58     * 6.   E0FEE0FEF1FEF1FE    FEE0FEE0FEF1FEF1
59     * 7.   0101010101010101    0101010101010101
60     * 8.   FEFEFEFEFEFEFEFE    FEFEFEFEFEFEFEFE
61     * 9.   E0E0E0E0F1F1F1F1    E0E0E0E0F1F1F1F1
62     * 10.  1F1F1F1F0E0E0E0E    1F1F1F1F0E0E0E0E
63     */
64    private static final byte[][] WEAK_KEYS = {
65
66        { (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
67          (byte)0x01, (byte)0x01, (byte)0x01 },
68
69        { (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE, (byte)0xFE,
70          (byte)0xFE, (byte)0xFE, (byte)0xFE },
71
72        { (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x1F, (byte)0x0E,
73          (byte)0x0E, (byte)0x0E, (byte)0x0E },
74
75        { (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xE0, (byte)0xF1,
76          (byte)0xF1, (byte)0xF1, (byte)0xF1 },
77
78        { (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01,
79          (byte)0xFE, (byte)0x01, (byte)0xFE },
80
81        { (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x0E,
82          (byte)0xF1, (byte)0x0E, (byte)0xF1 },
83
84        { (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01,
85          (byte)0xF1, (byte)0x01, (byte)0xF1 },
86
87        { (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x0E,
88          (byte)0xFE, (byte)0x0E, (byte)0xFE },
89
90        { (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01,
91          (byte)0x0E, (byte)0x01, (byte)0x0E },
92
93        { (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xF1,
94          (byte)0xFE, (byte)0xF1, (byte)0xFE },
95
96        { (byte)0xFE, (byte)0x01, (byte)0xFE, (byte)0x01, (byte)0xFE,
97          (byte)0x01, (byte)0xFE, (byte)0x01 },
98
99        { (byte)0xE0, (byte)0x1F, (byte)0xE0, (byte)0x1F, (byte)0xF1,
100          (byte)0x0E, (byte)0xF1, (byte)0x0E },
101
102        { (byte)0xE0, (byte)0x01, (byte)0xE0, (byte)0x01, (byte)0xF1,
103          (byte)0x01, (byte)0xF1, (byte)0x01 },
104
105        { (byte)0xFE, (byte)0x1F, (byte)0xFE, (byte)0x1F, (byte)0xFE,
106          (byte)0x0E, (byte)0xFE, (byte)0x0E },
107
108        { (byte)0x1F, (byte)0x01, (byte)0x1F, (byte)0x01, (byte)0x0E,
109          (byte)0x01, (byte)0x0E, (byte)0x01 },
110
111        { (byte)0xFE, (byte)0xE0, (byte)0xFE, (byte)0xE0, (byte)0xFE,
112          (byte)0xF1, (byte)0xFE, (byte)0xF1 }
113    };
114
115    /**
116     * Creates a DESKeySpec object using the first 8 bytes in
117     * <code>key</code> as the key material for the DES key.
118     *
119     * <p> The bytes that constitute the DES key are those between
120     * <code>key[0]</code> and <code>key[7]</code> inclusive.
121     *
122     * @param key the buffer with the DES key material. The first 8 bytes
123     * of the buffer are copied to protect against subsequent modification.
124     *
125     * @exception NullPointerException if the given key material is
126     * <code>null</code>
127     * @exception InvalidKeyException if the given key material is shorter
128     * than 8 bytes.
129     */
130    public DESKeySpec(byte[] key) throws InvalidKeyException {
131        this(key, 0);
132    }
133
134    /**
135     * Creates a DESKeySpec object using the first 8 bytes in
136     * <code>key</code>, beginning at <code>offset</code> inclusive,
137     * as the key material for the DES key.
138     *
139     * <p> The bytes that constitute the DES key are those between
140     * <code>key[offset]</code> and <code>key[offset+7]</code> inclusive.
141     *
142     * @param key the buffer with the DES key material. The first 8 bytes
143     * of the buffer beginning at <code>offset</code> inclusive are copied
144     * to protect against subsequent modification.
145     * @param offset the offset in <code>key</code>, where the DES key
146     * material starts.
147     *
148     * @exception NullPointerException if the given key material is
149     * <code>null</code>
150     * @exception InvalidKeyException if the given key material, starting at
151     * <code>offset</code> inclusive, is shorter than 8 bytes.
152     */
153    public DESKeySpec(byte[] key, int offset) throws InvalidKeyException {
154        if (key.length - offset < DES_KEY_LEN) {
155            throw new InvalidKeyException("Wrong key size");
156        }
157        this.key = new byte[DES_KEY_LEN];
158        System.arraycopy(key, offset, this.key, 0, DES_KEY_LEN);
159    }
160
161    /**
162     * Returns the DES key material.
163     *
164     * @return the DES key material. Returns a new array
165     * each time this method is called.
166     */
167    public byte[] getKey() {
168        return (byte[])this.key.clone();
169    }
170
171    /**
172     * Checks if the given DES key material, starting at <code>offset</code>
173     * inclusive, is parity-adjusted.
174     *
175     * @param key the buffer with the DES key material.
176     * @param offset the offset in <code>key</code>, where the DES key
177     * material starts.
178     *
179     * @return true if the given DES key material is parity-adjusted, false
180     * otherwise.
181     *
182     * @exception InvalidKeyException if the given key material is
183     * <code>null</code>, or starting at <code>offset</code> inclusive, is
184     * shorter than 8 bytes.
185     */
186    public static boolean isParityAdjusted(byte[] key, int offset)
187        throws InvalidKeyException {
188            if (key == null) {
189                throw new InvalidKeyException("null key");
190            }
191            if (key.length - offset < DES_KEY_LEN) {
192                throw new InvalidKeyException("Wrong key size");
193            }
194
195            for (int i = 0; i < DES_KEY_LEN; i++) {
196                int k = Integer.bitCount(key[offset++] & 0xff);
197                if ((k & 1) == 0) {
198                    return false;
199                }
200            }
201
202            return true;
203    }
204
205    /**
206     * Checks if the given DES key material is weak or semi-weak.
207     *
208     * @param key the buffer with the DES key material.
209     * @param offset the offset in <code>key</code>, where the DES key
210     * material starts.
211     *
212     * @return true if the given DES key material is weak or semi-weak, false
213     * otherwise.
214     *
215     * @exception InvalidKeyException if the given key material is
216     * <code>null</code>, or starting at <code>offset</code> inclusive, is
217     * shorter than 8 bytes.
218     */
219    public static boolean isWeak(byte[] key, int offset)
220        throws InvalidKeyException {
221        if (key == null) {
222            throw new InvalidKeyException("null key");
223        }
224        if (key.length - offset < DES_KEY_LEN) {
225            throw new InvalidKeyException("Wrong key size");
226        }
227        for (int i = 0; i < WEAK_KEYS.length; i++) {
228            boolean found = true;
229            for (int j = 0; j < DES_KEY_LEN && found == true; j++) {
230                if (WEAK_KEYS[i][j] != key[j+offset]) {
231                    found = false;
232                }
233            }
234            if (found == true) {
235                return found;
236            }
237        }
238        return false;
239    }
240}
241