History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/krb5/EncryptionKey.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/krb5/EncryptionKey.java+567−0
@@ -0,0 +1,567 @@
1/*
2 * Copyright (c) 2000, 2011, 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/*
27 *
28 * (C) Copyright IBM Corp. 1999 All Rights Reserved.
29 * Copyright 1997 The Open Group Research Institute. All rights reserved.
30 */
31
32package sun.security.krb5;
33
34import sun.security.util.*;
35import sun.security.krb5.internal.*;
36import sun.security.krb5.internal.crypto.*;
37import java.io.IOException;
38import java.security.GeneralSecurityException;
39import java.util.Arrays;
40import sun.security.krb5.internal.ktab.KeyTab;
41import sun.security.krb5.internal.ccache.CCacheOutputStream;
42import javax.crypto.spec.DESKeySpec;
43import javax.crypto.spec.DESedeKeySpec;
44
45/**
46 * This class encapsulates the concept of an EncryptionKey. An encryption
47 * key is defined in RFC 4120 as:
48 *
49 * EncryptionKey ::= SEQUENCE {
50 * keytype [0] Int32 -- actually encryption type --,
51 * keyvalue [1] OCTET STRING
52 * }
53 *
54 * keytype
55 * This field specifies the encryption type of the encryption key
56 * that follows in the keyvalue field. Although its name is
57 * "keytype", it actually specifies an encryption type. Previously,
58 * multiple cryptosystems that performed encryption differently but
59 * were capable of using keys with the same characteristics were
60 * permitted to share an assigned number to designate the type of
61 * key; this usage is now deprecated.
62 *
63 * keyvalue
64 * This field contains the key itself, encoded as an octet string.
65 */
66
67public class EncryptionKey
68 implements Cloneable {
69
70 public static final EncryptionKey NULL_KEY =
71 new EncryptionKey(new byte[] {}, EncryptedData.ETYPE_NULL, null);
72
73 private int keyType;
74 private byte[] keyValue;
75 private Integer kvno; // not part of ASN1 encoding;
76
77 private static final boolean DEBUG = Krb5.DEBUG;
78
79 public synchronized int getEType() {
80 return keyType;
81 }
82
83 public final Integer getKeyVersionNumber() {
84 return kvno;
85 }
86
87 /**
88 * Returns the raw key bytes, not in any ASN.1 encoding.
89 */
90 public final byte[] getBytes() {
91 // This method cannot be called outside sun.security, hence no
92 // cloning. getEncoded() calls this method.
93 return keyValue;
94 }
95
96 public synchronized Object clone() {
97 return new EncryptionKey(keyValue, keyType, kvno);
98 }
99
100 /**
101 * Obtains the latest version of the secret key of
102 * the principal from a keytab.
103 *
104 * @param princ the principal whose secret key is desired
105 * @param keytab the path to the keytab file. A value of null
106 * will be accepted to indicate that the default path should be
107 * searched.
108 * @returns the secret key or null if none was found.
109 */
110 /*
111 // Replaced by acquireSecretKeys
112 public static EncryptionKey acquireSecretKey(PrincipalName princ,
113 String keytab)
114 throws KrbException, IOException {
115
116 if (princ == null) {
117 throw new IllegalArgumentException(
118 "Cannot have null pricipal name to look in keytab.");
119 }
120
121 KeyTab ktab = KeyTab.getInstance(keytab);
122
123 if (ktab == null)
124 return null;
125
126 return ktab.readServiceKey(princ);
127 }
128 */
129
130 /**
131 * Obtains all versions of the secret key of the principal from a
132 * keytab.
133 *
134 * @Param princ the principal whose secret key is desired
135 * @param keytab the path to the keytab file. A value of null
136 * will be accepted to indicate that the default path should be
137 * searched.
138 * @returns an array of secret keys or null if none were found.
139 */
140 public static EncryptionKey[] acquireSecretKeys(PrincipalName princ,
141 String keytab) {
142
143 if (princ == null)
144 throw new IllegalArgumentException(
145 "Cannot have null pricipal name to look in keytab.");
146
147 // KeyTab getInstance(keytab) will call KeyTab.getInstance()
148 // if keytab is null
149 KeyTab ktab = KeyTab.getInstance(keytab);
150 return ktab.readServiceKeys(princ);
151 }
152
153 /**
154 * Obtains a key for a given etype with salt and optional s2kparams
155 * @param password NOT null
156 * @param salt NOT null
157 * @param etype
158 * @param s2kparams can be NULL
159 */
160 public static EncryptionKey acquireSecretKey(char[] password,
161 String salt, int etype, byte[] s2kparams)
162 throws KrbException {
163
164 return new EncryptionKey(
165 stringToKey(password, salt, s2kparams, etype),
166 etype, null);
167 }
168
169 /**
170 * Generate a list of keys using the given principal and password.
171 * Construct a key for each configured etype.
172 * Caller is responsible for clearing password.
173 */
174 /*
175 * Usually, when keyType is decoded from ASN.1 it will contain a
176 * value indicating what the algorithm to be used is. However, when
177 * converting from a password to a key for the AS-EXCHANGE, this
178 * keyType will not be available. Use builtin list of default etypes
179 * as the default in that case. If default_tkt_enctypes was set in
180 * the libdefaults of krb5.conf, then use that sequence.
181 */
182 public static EncryptionKey[] acquireSecretKeys(char[] password,
183 String salt) throws KrbException {
184
185 int[] etypes = EType.getDefaults("default_tkt_enctypes");
186 if (etypes == null) {
187 etypes = EType.getBuiltInDefaults();
188 }
189
190 EncryptionKey[] encKeys = new EncryptionKey[etypes.length];
191 for (int i = 0; i < etypes.length; i++) {
192 if (EType.isSupported(etypes[i])) {
193 encKeys[i] = new EncryptionKey(
194 stringToKey(password, salt, null, etypes[i]),
195 etypes[i], null);
196 } else {
197 if (DEBUG) {
198 System.out.println("Encryption Type " +
199 EType.toString(etypes[i]) +
200 " is not supported/enabled");
201 }
202 }
203 }
204 return encKeys;
205 }
206
207 // Used in Krb5AcceptCredential, self
208 public EncryptionKey(byte[] keyValue,
209 int keyType,
210 Integer kvno) {
211
212 if (keyValue != null) {
213 this.keyValue = new byte[keyValue.length];
214 System.arraycopy(keyValue, 0, this.keyValue, 0, keyValue.length);
215 } else {
216 throw new IllegalArgumentException("EncryptionKey: " +
217 "Key bytes cannot be null!");
218 }
219 this.keyType = keyType;
220 this.kvno = kvno;
221 }
222
223 /**
224 * Constructs an EncryptionKey by using the specified key type and key
225 * value. It is used to recover the key when retrieving data from
226 * credential cache file.
227 *
228 */
229 // Used in JSSE (KerberosWrapper), Credentials,
230 // javax.security.auth.kerberos.KeyImpl
231 public EncryptionKey(int keyType,
232 byte[] keyValue) {
233 this(keyValue, keyType, null);
234 }
235
236 private static byte[] stringToKey(char[] password, String salt,
237 byte[] s2kparams, int keyType) throws KrbCryptoException {
238
239 char[] slt = salt.toCharArray();
240 char[] pwsalt = new char[password.length + slt.length];
241 System.arraycopy(password, 0, pwsalt, 0, password.length);
242 System.arraycopy(slt, 0, pwsalt, password.length, slt.length);
243 Arrays.fill(slt, '0');
244
245 try {
246 switch (keyType) {
247 case EncryptedData.ETYPE_DES_CBC_CRC:
248 case EncryptedData.ETYPE_DES_CBC_MD5:
249 return Des.string_to_key_bytes(pwsalt);
250
251 case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
252 return Des3.stringToKey(pwsalt);
253
254 case EncryptedData.ETYPE_ARCFOUR_HMAC:
255 return ArcFourHmac.stringToKey(password);
256
257 case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
258 return Aes128.stringToKey(password, salt, s2kparams);
259
260 case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
261 return Aes256.stringToKey(password, salt, s2kparams);
262
263 default:
264 throw new IllegalArgumentException("encryption type " +
265 EType.toString(keyType) + " not supported");
266 }
267
268 } catch (GeneralSecurityException e) {
269 KrbCryptoException ke = new KrbCryptoException(e.getMessage());
270 ke.initCause(e);
271 throw ke;
272 } finally {
273 Arrays.fill(pwsalt, '0');
274 }
275 }
276
277 // Used in javax.security.auth.kerberos.KeyImpl
278 public EncryptionKey(char[] password,
279 String salt,
280 String algorithm) throws KrbCryptoException {
281
282 if (algorithm == null || algorithm.equalsIgnoreCase("DES")) {
283 keyType = EncryptedData.ETYPE_DES_CBC_MD5;
284 } else if (algorithm.equalsIgnoreCase("DESede")) {
285 keyType = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
286 } else if (algorithm.equalsIgnoreCase("AES128")) {
287 keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
288 } else if (algorithm.equalsIgnoreCase("ArcFourHmac")) {
289 keyType = EncryptedData.ETYPE_ARCFOUR_HMAC;
290 } else if (algorithm.equalsIgnoreCase("AES256")) {
291 keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
292 // validate if AES256 is enabled
293 if (!EType.isSupported(keyType)) {
294 throw new IllegalArgumentException("Algorithm " + algorithm +
295 " not enabled");
296 }
297 } else {
298 throw new IllegalArgumentException("Algorithm " + algorithm +
299 " not supported");
300 }
301
302 keyValue = stringToKey(password, salt, null, keyType);
303 kvno = null;
304 }
305
306 /**
307 * Generates a sub-sessionkey from a given session key.
308 */
309 // Used in KrbApRep, KrbApReq
310 EncryptionKey(EncryptionKey key) throws KrbCryptoException {
311 // generate random sub-session key
312 keyValue = Confounder.bytes(key.keyValue.length);
313 for (int i = 0; i < keyValue.length; i++) {
314 keyValue[i] ^= key.keyValue[i];
315 }
316 keyType = key.keyType;
317
318 // check for key parity and weak keys
319 try {
320 // check for DES key
321 if ((keyType == EncryptedData.ETYPE_DES_CBC_MD5) ||
322 (keyType == EncryptedData.ETYPE_DES_CBC_CRC)) {
323 // fix DES key parity
324 if (!DESKeySpec.isParityAdjusted(keyValue, 0)) {
325 keyValue = Des.set_parity(keyValue);
326 }
327 // check for weak key
328 if (DESKeySpec.isWeak(keyValue, 0)) {
329 keyValue[7] = (byte)(keyValue[7] ^ 0xF0);
330 }
331 }
332 // check for 3DES key
333 if (keyType == EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
334 // fix 3DES key parity
335 if (!DESedeKeySpec.isParityAdjusted(keyValue, 0)) {
336 keyValue = Des3.parityFix(keyValue);
337 }
338 // check for weak keys
339 byte[] oneKey = new byte[8];
340 for (int i=0; i<keyValue.length; i+=8) {
341 System.arraycopy(keyValue, i, oneKey, 0, 8);
342 if (DESKeySpec.isWeak(oneKey, 0)) {
343 keyValue[i+7] = (byte)(keyValue[i+7] ^ 0xF0);
344 }
345 }
346 }
347 } catch (GeneralSecurityException e) {
348 KrbCryptoException ke = new KrbCryptoException(e.getMessage());
349 ke.initCause(e);
350 throw ke;
351 }
352 }
353
354 /**
355 * Constructs an instance of EncryptionKey type.
356 * @param encoding a single DER-encoded value.
357 * @exception Asn1Exception if an error occurs while decoding an ASN1
358 * encoded data.
359 * @exception IOException if an I/O error occurs while reading encoded
360 * data.
361 *
362 *
363 */
364 // Used in javax.security.auth.kerberos.KeyImpl
365 public EncryptionKey(DerValue encoding) throws Asn1Exception, IOException {
366 DerValue der;
367 if (encoding.getTag() != DerValue.tag_Sequence) {
368 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
369 }
370 der = encoding.getData().getDerValue();
371 if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
372 keyType = der.getData().getBigInteger().intValue();
373 }
374 else
375 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
376 der = encoding.getData().getDerValue();
377 if ((der.getTag() & (byte)0x1F) == (byte)0x01) {
378 keyValue = der.getData().getOctetString();
379 }
380 else
381 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
382 if (der.getData().available() > 0) {
383 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
384 }
385 }
386
387 /**
388 * Returns the ASN.1 encoding of this EncryptionKey.
389 *
390 * <xmp>
391 * EncryptionKey ::= SEQUENCE {
392 * keytype[0] INTEGER,
393 * keyvalue[1] OCTET STRING }
394 * </xmp>
395 *
396 * <p>
397 * This definition reflects the Network Working Group RFC 4120
398 * specification available at
399 * <a href="http://www.ietf.org/rfc/rfc4120.txt">
400 * http://www.ietf.org/rfc/rfc4120.txt</a>.
401 *
402 * @return byte array of encoded EncryptionKey object.
403 * @exception Asn1Exception if an error occurs while decoding an ASN1
404 * encoded data.
405 * @exception IOException if an I/O error occurs while reading encoded
406 * data.
407 *
408 */
409 public synchronized byte[] asn1Encode() throws Asn1Exception, IOException {
410 DerOutputStream bytes = new DerOutputStream();
411 DerOutputStream temp = new DerOutputStream();
412 temp.putInteger(keyType);
413 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
414 (byte)0x00), temp);
415 temp = new DerOutputStream();
416 temp.putOctetString(keyValue);
417 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
418 (byte)0x01), temp);
419 temp = new DerOutputStream();
420 temp.write(DerValue.tag_Sequence, bytes);
421 return temp.toByteArray();
422 }
423
424 public synchronized void destroy() {
425 if (keyValue != null)
426 for (int i = 0; i < keyValue.length; i++)
427 keyValue[i] = 0;
428 }
429
430
431 /**
432 * Parse (unmarshal) an Encryption key from a DER input stream. This form
433 * parsing might be used when expanding a value which is part of
434 * a constructed sequence and uses explicitly tagged type.
435 *
436 * @param data the Der input stream value, which contains one or more
437 * marshaled value.
438 * @param explicitTag tag number.
439 * @param optional indicate if this data field is optional
440 * @exception Asn1Exception if an error occurs while decoding an ASN1
441 * encoded data.
442 * @exception IOException if an I/O error occurs while reading encoded
443 * data.
444 * @return an instance of EncryptionKey.
445 *
446 */
447 public static EncryptionKey parse(DerInputStream data, byte
448 explicitTag, boolean optional) throws
449 Asn1Exception, IOException {
450 if ((optional) && (((byte)data.peekByte() & (byte)0x1F) !=
451 explicitTag)) {
452 return null;
453 }
454 DerValue der = data.getDerValue();
455 if (explicitTag != (der.getTag() & (byte)0x1F)) {
456 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
457 } else {
458 DerValue subDer = der.getData().getDerValue();
459 return new EncryptionKey(subDer);
460 }
461 }
462
463 /**
464 * Writes key value in FCC format to a <code>CCacheOutputStream</code>.
465 *
466 * @param cos a <code>CCacheOutputStream</code> to be written to.
467 * @exception IOException if an I/O exception occurs.
468 * @see sun.security.krb5.internal.ccache.CCacheOutputStream
469 *
470 */
471 public synchronized void writeKey(CCacheOutputStream cos)
472 throws IOException {
473
474 cos.write16(keyType);
475 // we use KRB5_FCC_FVNO_3
476 cos.write16(keyType); // key type is recorded twice.
477 cos.write32(keyValue.length);
478 for (int i = 0; i < keyValue.length; i++) {
479 cos.write8(keyValue[i]);
480 }
481 }
482
483 public String toString() {
484 return new String("EncryptionKey: keyType=" + keyType
485 + " kvno=" + kvno
486 + " keyValue (hex dump)="
487 + (keyValue == null || keyValue.length == 0 ?
488 " Empty Key" : '\n'
489 + Krb5.hexDumper.encodeBuffer(keyValue)
490 + '\n'));
491 }
492
493 /**
494 * Find a key with given etype
495 */
496 public static EncryptionKey findKey(int etype, EncryptionKey[] keys)
497 throws KrbException {
498 return findKey(etype, null, keys);
499 }
500
501 /**
502 * Determines if a kvno matches another kvno. Used in the method
503 * findKey(type, kvno, keys). Always returns true if either input
504 * is null or zero, in case any side does not have kvno info available.
505 *
506 * Note: zero is included because N/A is not a legal value for kvno
507 * in javax.security.auth.kerberos.KerberosKey. Therefore, the info
508 * that the kvno is N/A might be lost when converting between this
509 * class and KerberosKey.
510 */
511 private static boolean versionMatches(Integer v1, Integer v2) {
512 if (v1 == null || v1 == 0 || v2 == null || v2 == 0) {
513 return true;
514 }
515 return v1.equals(v2);
516 }
517
518 /**
519 * Find a key with given etype and kvno
520 * @param kvno if null, return any (first?) key
521 */
522 public static EncryptionKey findKey(int etype, Integer kvno, EncryptionKey[] keys)
523 throws KrbException {
524
525 // check if encryption type is supported
526 if (!EType.isSupported(etype)) {
527 throw new KrbException("Encryption type " +
528 EType.toString(etype) + " is not supported/enabled");
529 }
530
531 int ktype;
532 boolean etypeFound = false;
533 for (int i = 0; i < keys.length; i++) {
534 ktype = keys[i].getEType();
535 if (EType.isSupported(ktype)) {
536 Integer kv = keys[i].getKeyVersionNumber();
537 if (etype == ktype) {
538 etypeFound = true;
539 if (versionMatches(kvno, kv)) {
540 return keys[i];
541 }
542 }
543 }
544 }
545
546 // Key not found.
547 // allow DES key to be used for the DES etypes
548 if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
549 etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
550 for (int i = 0; i < keys.length; i++) {
551 ktype = keys[i].getEType();
552 if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
553 ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
554 Integer kv = keys[i].getKeyVersionNumber();
555 etypeFound = true;
556 if (versionMatches(kvno, kv)) {
557 return new EncryptionKey(etype, keys[i].getBytes());
558 }
559 }
560 }
561 }
562 if (etypeFound) {
563 throw new KrbException(Krb5.KRB_AP_ERR_BADKEYVER);
564 }
565 return null;
566 }
567}