blob: 61a03c02a94b83eec1e8fa6bc23899d4a8a53520 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25/*
26 *
27 * (C) Copyright IBM Corp. 1999 All Rights Reserved.
28 * Copyright 1997 The Open Group Research Institute. All rights reserved.
29 */
30
31package sun.security.krb5.internal.crypto;
32
33import javax.crypto.Cipher;
34import javax.crypto.spec.SecretKeySpec;
35import javax.crypto.SecretKeyFactory;
36import javax.crypto.SecretKey;
37import java.security.Security;
38import java.security.Provider;
39import java.security.GeneralSecurityException;
40import javax.crypto.spec.IvParameterSpec;
41import sun.security.krb5.KrbCryptoException;
42import sun.security.krb5.internal.Krb5;
43import java.io.UnsupportedEncodingException;
44import java.util.Arrays;
45
46public final class Des {
47
48 private static final long[] bad_keys = {
49 0x0101010101010101L, 0xfefefefefefefefeL,
50 0x1f1f1f1f1f1f1f1fL, 0xe0e0e0e0e0e0e0e0L,
51 0x01fe01fe01fe01feL, 0xfe01fe01fe01fe01L,
52 0x1fe01fe00ef10ef1L, 0xe01fe01ff10ef10eL,
53 0x01e001e001f101f1L, 0xe001e001f101f101L,
54 0x1ffe1ffe0efe0efeL, 0xfe1ffe1ffe0efe0eL,
55 0x011f011f010e010eL, 0x1f011f010e010e01L,
56 0xe0fee0fef1fef1feL, 0xfee0fee0fef1fef1L
57 };
58
59 private static final byte[] good_parity = {
60 1, 1, 2, 2, 4, 4, 7, 7,
61 8, 8, 11, 11, 13, 13, 14, 14,
62 16, 16, 19, 19, 21, 21, 22, 22,
63 25, 25, 26, 26, 28, 28, 31, 31,
64 32, 32, 35, 35, 37, 37, 38, 38,
65 41, 41, 42, 42, 44, 44, 47, 47,
66 49, 49, 50, 50, 52, 52, 55, 55,
67 56, 56, 59, 59, 61, 61, 62, 62,
68 64, 64, 67, 67, 69, 69, 70, 70,
69 73, 73, 74, 74, 76, 76, 79, 79,
70 81, 81, 82, 82, 84, 84, 87, 87,
71 88, 88, 91, 91, 93, 93, 94, 94,
72 97, 97, 98, 98, 100, 100, 103, 103,
73 104, 104, 107, 107, 109, 109, 110, 110,
74 112, 112, 115, 115, 117, 117, 118, 118,
75 121, 121, 122, 122, 124, 124, 127, 127,
76 (byte)128, (byte)128, (byte)131, (byte)131,
77 (byte)133, (byte)133, (byte)134, (byte)134,
78 (byte)137, (byte)137, (byte)138, (byte)138,
79 (byte)140, (byte)140, (byte)143, (byte)143,
80 (byte)145, (byte)145, (byte)146, (byte)146,
81 (byte)148, (byte)148, (byte)151, (byte)151,
82 (byte)152, (byte)152, (byte)155, (byte)155,
83 (byte)157, (byte)157, (byte)158, (byte)158,
84 (byte)161, (byte)161, (byte)162, (byte)162,
85 (byte)164, (byte)164, (byte)167, (byte)167,
86 (byte)168, (byte)168, (byte)171, (byte)171,
87 (byte)173, (byte)173, (byte)174, (byte)174,
88 (byte)176, (byte)176, (byte)179, (byte)179,
89 (byte)181, (byte)181, (byte)182, (byte)182,
90 (byte)185, (byte)185, (byte)186, (byte)186,
91 (byte)188, (byte)188, (byte)191, (byte)191,
92 (byte)193, (byte)193, (byte)194, (byte)194,
93 (byte)196, (byte)196, (byte)199, (byte)199,
94 (byte)200, (byte)200, (byte)203, (byte)203,
95 (byte)205, (byte)205, (byte)206, (byte)206,
96 (byte)208, (byte)208, (byte)211, (byte)211,
97 (byte)213, (byte)213, (byte)214, (byte)214,
98 (byte)217, (byte)217, (byte)218, (byte)218,
99 (byte)220, (byte)220, (byte)223, (byte)223,
100 (byte)224, (byte)224, (byte)227, (byte)227,
101 (byte)229, (byte)229, (byte)230, (byte)230,
102 (byte)233, (byte)233, (byte)234, (byte)234,
103 (byte)236, (byte)236, (byte)239, (byte)239,
104 (byte)241, (byte)241, (byte)242, (byte)242,
105 (byte)244, (byte)244, (byte)247, (byte)247,
106 (byte)248, (byte)248, (byte)251, (byte)251,
107 (byte)253, (byte)253, (byte)254, (byte)254
108 };
109
110 public static final byte[] set_parity(byte[] key) {
111 for (int i=0; i < 8; i++) {
112 key[i] = good_parity[key[i] & 0xff];
113 }
114 return key;
115 }
116
117 public static final long set_parity(long key) {
118 return octet2long(set_parity(long2octet(key)));
119 }
120
121 public static final boolean bad_key(long key) {
122 for (int i = 0; i < bad_keys.length; i++) {
123 if (bad_keys[i] == key) {
124 return true;
125 }
126 }
127 return false;
128 }
129
130 public static final boolean bad_key(byte[] key) {
131 return bad_key(octet2long(key));
132 }
133
134 public static long octet2long(byte[] input) {
135 return octet2long(input, 0);
136 }
137
138 public static long octet2long(byte[] input, int offset) { //convert a 8-byte to a long
139 long result = 0;
140 for (int i = 0; i < 8; i++) {
141 if (i + offset < input.length) {
142 result |= (((long)input[i + offset]) & 0xffL) << ((7 - i) * 8);
143 }
144 }
145 return result;
146 }
147
148 public static byte[] long2octet(long input) {
149 byte[] output = new byte[8];
150 for (int i = 0; i < 8; i++) {
151 output[i] = (byte)((input >>> ((7 - i) * 8)) & 0xffL);
152 }
153 return output;
154 }
155
156 public static void long2octet(long input, byte[] output) {
157 long2octet(input, output, 0);
158 }
159
160 public static void long2octet(long input, byte[] output, int offset) {
161 for (int i = 0; i < 8; i++) {
162 if (i + offset < output.length) {
163 output[i + offset] =
164 (byte)((input >>> ((7 - i) * 8)) & 0xffL);
165 }
166 }
167 }
168
169 /**
170 * Creates a DES cipher in Electronic Codebook mode, with no padding.
171 * @param input plain text.
172 * @param output the buffer for the result.
173 * @param key DES the key to encrypt the text.
174 * @param ivec initialization vector.
175 *
176 * @created by Yanni Zhang, Dec 6 99.
177 */
178 public static void cbc_encrypt (
179 byte[] input,
180 byte[] output,
181 byte[] key,
182 byte[] ivec,
183 boolean encrypt) throws KrbCryptoException {
184
185 Cipher cipher = null;
186
187 try {
188 cipher = Cipher.getInstance("DES/CBC/NoPadding");
189 } catch (GeneralSecurityException e) {
190 KrbCryptoException ke = new KrbCryptoException("JCE provider may not be installed. "
191 + e.getMessage());
192 ke.initCause(e);
193 throw ke;
194 }
195 IvParameterSpec params = new IvParameterSpec(ivec);
196 SecretKeySpec skSpec = new SecretKeySpec(key, "DES");
197 try {
198 SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
199 // SecretKey sk = skf.generateSecret(skSpec);
200 SecretKey sk = (SecretKey) skSpec;
201 if (encrypt)
202 cipher.init(Cipher.ENCRYPT_MODE, sk, params);
203 else
204 cipher.init(Cipher.DECRYPT_MODE, sk, params);
205 byte[] result;
206 result = cipher.doFinal(input);
207 System.arraycopy(result, 0, output, 0, result.length);
208 } catch (GeneralSecurityException e) {
209 KrbCryptoException ke = new KrbCryptoException(e.getMessage());
210 ke.initCause(e);
211 throw ke;
212 }
213 }
214
215 /**
216 * Generates DES key from the password.
217 * @param password a char[] used to create the key.
218 * @return DES key.
219 *
220 * @modified by Yanni Zhang, Dec 6, 99
221 */
222 public static long char_to_key(char[] passwdChars) throws KrbCryptoException {
223 long key = 0;
224 long octet, octet1, octet2 = 0;
225 byte[] cbytes = null;
226
227 // Convert password to byte array
228 try {
229 cbytes = (new String(passwdChars)).getBytes();
230 } catch (Exception e) {
231 // clear-up sensitive information
232 if (cbytes != null) {
233 Arrays.fill(cbytes, 0, cbytes.length, (byte) 0);
234 }
235 KrbCryptoException ce =
236 new KrbCryptoException("Unable to convert passwd, " + e);
237 ce.initCause(e);
238 throw ce;
239 }
240
241 // pad data
242 byte[] passwdBytes = pad(cbytes);
243
244 byte[] newkey = new byte[8];
245 int length = (passwdBytes.length / 8) + (passwdBytes.length % 8 == 0 ? 0 : 1);
246 for (int i = 0; i < length; i++) {
247 octet = octet2long(passwdBytes, i * 8) & 0x7f7f7f7f7f7f7f7fL;
248 if (i % 2 == 1) {
249 octet1 = 0;
250 for (int j = 0; j < 64; j++) {
251 octet1 |= ((octet & (1L << j)) >>> j) << (63 - j);
252 }
253 octet = octet1 >>> 1;
254 }
255 key ^= (octet << 1);
256 }
257 key = set_parity(key);
258 if (bad_key(key)) {
259 byte [] temp = long2octet(key);
260 temp[7] ^= 0xf0;
261 key = octet2long(temp);
262 }
263
264 newkey = des_cksum(long2octet(key), passwdBytes, long2octet(key));
265 key = octet2long(set_parity(newkey));
266 if (bad_key(key)) {
267 byte [] temp = long2octet(key);
268 temp[7] ^= 0xf0;
269 key = octet2long(temp);
270 }
271
272 // clear-up sensitive information
273 if (cbytes != null) {
274 Arrays.fill(cbytes, 0, cbytes.length, (byte) 0);
275 }
276 if (passwdBytes != null) {
277 Arrays.fill(passwdBytes, 0, passwdBytes.length, (byte) 0);
278 }
279
280 return key;
281 }
282
283 /**
284 * Encrypts the message blocks using DES CBC and output the
285 * final block of 8-byte ciphertext.
286 * @param ivec Initialization vector.
287 * @param msg Input message as an byte array.
288 * @param key DES key to encrypt the message.
289 * @return the last block of ciphertext.
290 *
291 * @created by Yanni Zhang, Dec 6, 99.
292 */
293 public static byte[] des_cksum(byte[] ivec, byte[] msg, byte[] key) throws KrbCryptoException {
294 Cipher cipher = null;
295
296 byte[] result = new byte[8];
297 try{
298 cipher = Cipher.getInstance("DES/CBC/NoPadding");
299 } catch (Exception e) {
300 KrbCryptoException ke = new KrbCryptoException("JCE provider may not be installed. "
301 + e.getMessage());
302 ke.initCause(e);
303 throw ke;
304 }
305 IvParameterSpec params = new IvParameterSpec(ivec);
306 SecretKeySpec skSpec = new SecretKeySpec(key, "DES");
307 try {
308 SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
309 // SecretKey sk = skf.generateSecret(skSpec);
310 SecretKey sk = (SecretKey) skSpec;
311 cipher.init(Cipher.ENCRYPT_MODE, sk, params);
312 for (int i = 0; i < msg.length / 8; i++) {
313 result = cipher.doFinal(msg, i * 8, 8);
314 cipher.init(Cipher.ENCRYPT_MODE, sk, (new IvParameterSpec(result)));
315 }
316 }
317 catch (GeneralSecurityException e) {
318 KrbCryptoException ke = new KrbCryptoException(e.getMessage());
319 ke.initCause(e);
320 throw ke;
321 }
322 return result;
323 }
324
325 /**
326 * Pads the data so that its length is a multiple of 8 bytes.
327 * @param data the raw data.
328 * @return the data being padded.
329 *
330 * @created by Yanni Zhang, Dec 6 99. //Kerberos does not use PKCS5 padding.
331 */
332 static byte[] pad(byte[] data) {
333 int len;
334 if (data.length < 8) len = data.length;
335 else len = data.length % 8;
336 if (len == 0) return data;
337 else {
338 byte[] padding = new byte[ 8 - len + data.length];
339 for (int i = padding.length - 1; i > data.length - 1; i--) {
340 padding[i] = 0;
341 }
342 System.arraycopy(data, 0, padding, 0, data.length);
343 return padding;
344 }
345 }
346
347 // Caller is responsible for clearing password
348 public static byte[] string_to_key_bytes(char[] passwdChars)
349 throws KrbCryptoException {
350 return long2octet(char_to_key(passwdChars));
351 }
352}