blob: 1fac510b4fb8b62365c65d8454730f971037563d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Portions Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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.crypto.*;
36import sun.security.krb5.internal.*;
37import java.io.IOException;
38import java.math.BigInteger;
39
40/**
41 * This class encapsulates Kerberos encrypted data. It allows
42 * callers access to both the ASN.1 encoded form of the EncryptedData
43 * type as well as the raw cipher text.
44 */
45
46public class EncryptedData implements Cloneable {
47 int eType;
48 Integer kvno; // optional
49 byte[] cipher;
50 byte[] plain; // not part of ASN.1 encoding
51
52 // ----------------+-----------+----------+----------------+---------------
53 // Encryption type |etype value|block size|minimum pad size|confounder size
54 // ----------------+-----------+----------+----------------+---------------
55 public static final int
56 ETYPE_NULL = 0; // 1 0 0
57 public static final int
58 ETYPE_DES_CBC_CRC = 1; // 8 4 8
59 public static final int
60 ETYPE_DES_CBC_MD4 = 2; // 8 0 8
61 public static final int
62 ETYPE_DES_CBC_MD5 = 3; // 8 0 8
63
64 // draft-brezak-win2k-krb-rc4-hmac-04.txt
65 public static final int
66 ETYPE_ARCFOUR_HMAC = 23; // 1
67 // NOTE: the exportable RC4-HMAC is not supported;
68 // it is no longer a usable encryption type
69 public static final int
70 ETYPE_ARCFOUR_HMAC_EXP = 24; // 1
71
72 // draft-ietf-krb-wg-crypto-07.txt
73 public static final int
74 ETYPE_DES3_CBC_HMAC_SHA1_KD = 16; // 8 0 8
75
76 // draft-raeburn-krb-rijndael-krb-07.txt
77 public static final int
78 ETYPE_AES128_CTS_HMAC_SHA1_96 = 17; // 16 0 16
79 public static final int
80 ETYPE_AES256_CTS_HMAC_SHA1_96 = 18; // 16 0 16
81
82 /* used by self */
83 private EncryptedData() {
84 }
85
86 public Object clone() {
87 EncryptedData new_encryptedData = new EncryptedData();
88 new_encryptedData.eType = eType;
89 if (kvno != null) {
90 new_encryptedData.kvno = new Integer(kvno.intValue());
91 }
92 if (cipher != null) {
93 new_encryptedData.cipher = new byte[cipher.length];
94 System.arraycopy(cipher, 0, new_encryptedData.cipher,
95 0, cipher.length);
96 }
97 return new_encryptedData;
98 }
99
100 // Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
101 public EncryptedData(
102 int new_eType,
103 Integer new_kvno,
104 byte[] new_cipher) {
105 eType = new_eType;
106 kvno = new_kvno;
107 cipher = new_cipher;
108 }
109
110 /*
111 // Not used.
112 public EncryptedData(
113 EncryptionKey key,
114 byte[] plaintext)
115 throws KdcErrException, KrbCryptoException {
116 EType etypeEngine = EType.getInstance(key.getEType());
117 cipher = etypeEngine.encrypt(plaintext, key.getBytes());
118 eType = key.getEType();
119 kvno = key.getKeyVersionNumber();
120 }
121 */
122
123 // used in KrbApRep, KrbApReq, KrbAsReq, KrbCred, KrbPriv
124 // Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
125 public EncryptedData(
126 EncryptionKey key,
127 byte[] plaintext,
128 int usage)
129 throws KdcErrException, KrbCryptoException {
130 EType etypeEngine = EType.getInstance(key.getEType());
131 cipher = etypeEngine.encrypt(plaintext, key.getBytes(), usage);
132 eType = key.getEType();
133 kvno = key.getKeyVersionNumber();
134 }
135
136 /*
137 // Not used.
138 public EncryptedData(
139 EncryptionKey key,
140 byte[] ivec,
141 byte[] plaintext)
142 throws KdcErrException, KrbCryptoException {
143 EType etypeEngine = EType.getInstance(key.getEType());
144 cipher = etypeEngine.encrypt(plaintext, key.getBytes(), ivec);
145 eType = key.getEType();
146 kvno = key.getKeyVersionNumber();
147 }
148 */
149
150 /*
151 // Not used.
152 EncryptedData(
153 StringBuffer password,
154 byte[] plaintext)
155 throws KdcErrException, KrbCryptoException {
156 EncryptionKey key = new EncryptionKey(password);
157 EType etypeEngine = EType.getInstance(key.getEType());
158 cipher = etypeEngine.encrypt(plaintext, key.getBytes());
159 eType = key.getEType();
160 kvno = key.getKeyVersionNumber();
161 }
162 */
163
164 // currently destructive on cipher
165 public byte[] decrypt(
166 EncryptionKey key, int usage)
167 throws KdcErrException, KrbApErrException, KrbCryptoException {
168 if (eType != key.getEType()) {
169 throw new KrbCryptoException(
170 "EncryptedData is encrypted using keytype " +
171 EType.toString(eType) +
172 " but decryption key is of type " +
173 EType.toString(key.getEType()));
174 }
175
176 EType etypeEngine = EType.getInstance(eType);
177 plain = etypeEngine.decrypt(cipher, key.getBytes(), usage);
178 cipher = null;
179 return etypeEngine.decryptedData(plain);
180 }
181
182 /*
183 // currently destructive on cipher
184 // Not used.
185 public byte[] decrypt(
186 EncryptionKey key,
187 byte[] ivec, int usage)
188 throws KdcErrException, KrbApErrException, KrbCryptoException {
189 // XXX check for matching eType and kvno here
190 EType etypeEngine = EType.getInstance(eType);
191 plain = etypeEngine.decrypt(cipher, key.getBytes(), ivec, usage);
192 cipher = null;
193 return etypeEngine.decryptedData(plain);
194 }
195
196 // currently destructive on cipher
197 // Not used.
198 byte[] decrypt(StringBuffer password)
199 throws KdcErrException, KrbApErrException, KrbCryptoException {
200 EncryptionKey key = new EncryptionKey(password);
201 // XXX check for matching eType here
202 EType etypeEngine = EType.getInstance(eType);
203 plain = etypeEngine.decrypt(cipher, key.getBytes());
204 cipher = null;
205 return etypeEngine.decryptedData(plain);
206 }
207 */
208
209 private byte[] decryptedData() throws KdcErrException {
210 if (plain != null) {
211 EType etypeEngine = EType.getInstance(eType);
212 return etypeEngine.decryptedData(plain);
213 }
214 return null;
215 }
216
217 /**
218 * Constructs an instance of EncryptedData type.
219 * @param encoding a single DER-encoded value.
220 * @exception Asn1Exception if an error occurs while decoding an
221 * ASN1 encoded data.
222 * @exception IOException if an I/O error occurs while reading encoded
223 * data.
224 *
225 */
226 /* Used by self */
227 private EncryptedData(DerValue encoding)
228 throws Asn1Exception, IOException {
229
230 DerValue der = null;
231 if (encoding.getTag() != DerValue.tag_Sequence) {
232 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
233 }
234 der = encoding.getData().getDerValue();
235 if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
236 eType = (der.getData().getBigInteger()).intValue();
237 } else {
238 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
239 }
240
241 if ((encoding.getData().peekByte() & 0x1F) == 1) {
242 der = encoding.getData().getDerValue();
243 int i = (der.getData().getBigInteger()).intValue();
244 kvno = new Integer(i);
245 } else {
246 kvno = null;
247 }
248 der = encoding.getData().getDerValue();
249 if ((der.getTag() & (byte)0x1F) == (byte)0x02) {
250 cipher = der.getData().getOctetString();
251 } else {
252 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
253 }
254 if (encoding.getData().available() > 0) {
255 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
256 }
257 }
258
259 /**
260 * Returns an ASN.1 encoded EncryptedData type.
261 *
262 * <xmp>
263 * EncryptedData ::= SEQUENCE {
264 * etype [0] Int32 -- EncryptionType --,
265 * kvno [1] UInt32 OPTIONAL,
266 * cipher [2] OCTET STRING -- ciphertext
267 * }
268 * </xmp>
269 *
270 * <p>
271 * This definition reflects the Network Working Group RFC 4120
272 * specification available at
273 * <a href="http://www.ietf.org/rfc/rfc4120.txt">
274 * http://www.ietf.org/rfc/rfc4120.txt</a>.
275 * <p>
276 * @return byte array of encoded EncryptedData object.
277 * @exception Asn1Exception if an error occurs while decoding an
278 * ASN1 encoded data.
279 * @exception IOException if an I/O error occurs while reading
280 * encoded data.
281 *
282 */
283 public byte[] asn1Encode() throws Asn1Exception, IOException {
284 DerOutputStream bytes = new DerOutputStream();
285 DerOutputStream temp = new DerOutputStream();
286 temp.putInteger(BigInteger.valueOf(this.eType));
287 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
288 true, (byte)0x00), temp);
289 temp = new DerOutputStream();
290 if (kvno != null) {
291 // encode as an unsigned integer (UInt32)
292 temp.putInteger(BigInteger.valueOf(this.kvno.longValue()));
293 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
294 true, (byte)0x01), temp);
295 temp = new DerOutputStream();
296 }
297 temp.putOctetString(this.cipher);
298 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
299 (byte)0x02), temp);
300 temp = new DerOutputStream();
301 temp.write(DerValue.tag_Sequence, bytes);
302 return temp.toByteArray();
303 }
304
305
306 /**
307 * Parse (unmarshal) an EncryptedData from a DER input stream. This form
308 * parsing might be used when expanding a value which is part of
309 * a constructed sequence and uses explicitly tagged type.
310 *
311 * @param data the Der input stream value, which contains one or more
312 * marshaled value.
313 * @param explicitTag tag number.
314 * @param optional indicate if this data field is optional
315 * @exception Asn1Exception if an error occurs while decoding an
316 * ASN1 encoded data.
317 * @exception IOException if an I/O error occurs while reading
318 * encoded data.
319 * @return an instance of EncryptedData.
320 *
321 */
322 public static EncryptedData parse(DerInputStream data,
323 byte explicitTag,
324 boolean optional)
325 throws Asn1Exception, IOException {
326 if ((optional) &&
327 (((byte)data.peekByte() & (byte)0x1F) != explicitTag))
328 return null;
329 DerValue der = data.getDerValue();
330 if (explicitTag != (der.getTag() & (byte)0x1F)) {
331 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
332 } else {
333 DerValue subDer = der.getData().getDerValue();
334 return new EncryptedData(subDer);
335 }
336 }
337
338 /**
339 * Reset data stream after decryption, remove redundant bytes.
340 * @param data the decrypted data from decrypt().
341 * @param encoded true if the encrypted data is ASN1 encoded data,
342 * false if the encrypted data is not ASN1 encoded data.
343 * @return the reset byte array which holds exactly one asn1 datum
344 * including its tag and length.
345 *
346 */
347 public byte[] reset(byte[] data, boolean encoded) {
348 byte[] bytes = null;
349 // if it is encoded data, we use length field to
350 // determine the data length and remove redundant paddings.
351 if (encoded) {
352 if ((data[1] & 0xFF) < 128) {
353 bytes = new byte[data[1] + 2];
354 System.arraycopy(data, 0, bytes, 0, data[1] + 2);
355 } else
356 if ((data[1] & 0xFF) > 128) {
357 int len = data[1] & (byte)0x7F;
358 int result = 0;
359 for (int i = 0; i < len; i++) {
360 result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1));
361 }
362 bytes = new byte[result + len + 2];
363 System.arraycopy(data, 0, bytes, 0, result + len + 2);
364 }
365 } else {
366 // if it is not encoded, which happens in GSS tokens,
367 // we remove padding data according to padding pattern.
368 bytes = new byte[data.length - data[data.length - 1]];
369 System.arraycopy(data, 0, bytes, 0,
370 data.length - data[data.length - 1]);
371 }
372 return bytes;
373 }
374
375 public int getEType() {
376 return eType;
377 }
378
379 public Integer getKeyVersionNumber() {
380 return kvno;
381 }
382
383 /**
384 * Returns the raw cipher text bytes, not in ASN.1 encoding.
385 */
386 public byte[] getBytes() {
387 return cipher;
388 }
389}