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+
32+package sun.security.krb5;
33+
34+import sun.security.util.*;
35+import sun.security.krb5.internal.*;
36+import sun.security.krb5.internal.crypto.*;
37+import java.io.IOException;
38+import java.security.GeneralSecurityException;
39+import java.util.Arrays;
40+import sun.security.krb5.internal.ktab.KeyTab;
41+import sun.security.krb5.internal.ccache.CCacheOutputStream;
42+import javax.crypto.spec.DESKeySpec;
43+import 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+
67+public 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+}