001: /*
002: * Portions Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
003: */
004:
005: /*
006: * Copyright (C) 1998 by the FundsXpress, INC.
007: *
008: * All rights reserved.
009: *
010: * Export of this software from the United States of America may require
011: * a specific license from the United States Government. It is the
012: * responsibility of any person or organization contemplating export to
013: * obtain such a license before exporting.
014: *
015: * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
016: * distribute this software and its documentation for any purpose and
017: * without fee is hereby granted, provided that the above copyright
018: * notice appear in all copies and that both that copyright notice and
019: * this permission notice appear in supporting documentation, and that
020: * the name of FundsXpress. not be used in advertising or publicity pertaining
021: * to distribution of the software without specific, written prior
022: * permission. FundsXpress makes no representations about the suitability of
023: * this software for any purpose. It is provided "as is" without express
024: * or implied warranty.
025: *
026: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
027: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
028: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
029: */
030:
031: package sun.security.krb5.internal.crypto.dk;
032:
033: import javax.crypto.Cipher;
034: import javax.crypto.Mac;
035: import java.security.GeneralSecurityException;
036: import java.io.UnsupportedEncodingException;
037: import java.util.Arrays;
038: import java.io.ByteArrayInputStream;
039: import java.io.ByteArrayOutputStream;
040: import java.nio.charset.Charset;
041: import java.nio.CharBuffer;
042: import java.nio.ByteBuffer;
043: import sun.misc.HexDumpEncoder;
044: import sun.security.krb5.Confounder;
045: import sun.security.krb5.internal.crypto.KeyUsage;
046: import sun.security.krb5.KrbCryptoException;
047:
048: /**
049: * Implements Derive Key cryptography functionality as defined in RFC 3961.
050: * http://www.ietf.org/rfc/rfc3961.txt
051: *
052: * This is an abstract class. Concrete subclasses need to implement
053: * the abstract methods.
054: */
055:
056: public abstract class DkCrypto {
057:
058: protected static final boolean debug = false;
059:
060: // These values correspond to the ASCII encoding for the string "kerberos"
061: static final byte[] KERBEROS_CONSTANT = { 0x6b, 0x65, 0x72, 0x62,
062: 0x65, 0x72, 0x6f, 0x73 };
063:
064: protected abstract int getKeySeedLength(); // in bits
065:
066: protected abstract byte[] randomToKey(byte[] in);
067:
068: protected abstract Cipher getCipher(byte[] key, byte[] ivec,
069: int mode) throws GeneralSecurityException;
070:
071: public abstract int getChecksumLength(); // in bytes
072:
073: protected abstract byte[] getHmac(byte[] key, byte[] plaintext)
074: throws GeneralSecurityException;
075:
076: /**
077: * From RFC 3961.
078: *
079: * encryption function conf = random string of length c
080: * pad = shortest string to bring confounder
081: * and plaintext to a length that's a
082: * multiple of m
083: * (C1, newIV) = E(Ke, conf | plaintext | pad,
084: * oldstate.ivec)
085: * H1 = HMAC(Ki, conf | plaintext | pad)
086: * ciphertext = C1 | H1[1..h]
087: * newstate.ivec = newIV
088: *
089: * @param ivec initial vector to use when initializing the cipher; if null,
090: * then blocksize number of zeros are used,
091: * @param new_ivec if non-null, it is updated upon return to be the
092: * new ivec to use when calling encrypt next time
093: */
094: public byte[] encrypt(byte[] baseKey, int usage, byte[] ivec,
095: byte[] new_ivec, byte[] plaintext, int start, int len)
096: throws GeneralSecurityException, KrbCryptoException {
097:
098: if (!KeyUsage.isValid(usage)) {
099: throw new GeneralSecurityException(
100: "Invalid key usage number: " + usage);
101: }
102:
103: byte[] Ke = null;
104: byte[] Ki = null;
105:
106: try {
107: // Derive encryption key
108:
109: byte[] constant = new byte[5];
110: constant[0] = (byte) ((usage >> 24) & 0xff);
111: constant[1] = (byte) ((usage >> 16) & 0xff);
112: constant[2] = (byte) ((usage >> 8) & 0xff);
113: constant[3] = (byte) (usage & 0xff);
114:
115: constant[4] = (byte) 0xaa;
116:
117: Ke = dk(baseKey, constant);
118: if (debug) {
119: System.err.println("usage: " + usage);
120: if (ivec != null) {
121: traceOutput("old_state.ivec", ivec, 0, ivec.length);
122: }
123: traceOutput("plaintext", plaintext, start, Math.min(
124: len, 32));
125: traceOutput("constant", constant, 0, constant.length);
126: traceOutput("baseKey", baseKey, 0, baseKey.length);
127: traceOutput("Ke", Ke, 0, Ke.length);
128: }
129:
130: // Encrypt
131: // C1 = E(Ke, conf | plaintext | pad, oldivec)
132: Cipher encCipher = getCipher(Ke, ivec, Cipher.ENCRYPT_MODE);
133: int blockSize = encCipher.getBlockSize();
134: byte[] confounder = Confounder.bytes(blockSize);
135:
136: int plainSize = roundup(confounder.length + len, blockSize);
137: if (debug) {
138: System.err.println("confounder = " + confounder.length
139: + "; plaintext = " + len + "; padding = "
140: + (plainSize - confounder.length - len)
141: + "; total = " + plainSize);
142: traceOutput("confounder", confounder, 0,
143: confounder.length);
144: }
145:
146: byte[] toBeEncrypted = new byte[plainSize];
147: System.arraycopy(confounder, 0, toBeEncrypted, 0,
148: confounder.length);
149: System.arraycopy(plaintext, start, toBeEncrypted,
150: confounder.length, len);
151:
152: // Set padding bytes to zero
153: Arrays.fill(toBeEncrypted, confounder.length + len,
154: plainSize, (byte) 0);
155:
156: int cipherSize = encCipher.getOutputSize(plainSize);
157: int ccSize = cipherSize + getChecksumLength(); // cipher | hmac
158:
159: byte[] ciphertext = new byte[ccSize];
160:
161: encCipher.doFinal(toBeEncrypted, 0, plainSize, ciphertext,
162: 0);
163:
164: // Update ivec for next operation
165: // (last blockSize bytes of ciphertext)
166: // newstate.ivec = newIV
167: if (new_ivec != null && new_ivec.length == blockSize) {
168: System.arraycopy(ciphertext, cipherSize - blockSize,
169: new_ivec, 0, blockSize);
170: if (debug) {
171: traceOutput("new_ivec", new_ivec, 0,
172: new_ivec.length);
173: }
174: }
175:
176: // Derive integrity key
177: constant[4] = (byte) 0x55;
178: Ki = dk(baseKey, constant);
179: if (debug) {
180: traceOutput("constant", constant, 0, constant.length);
181: traceOutput("Ki", Ki, 0, Ke.length);
182: }
183:
184: // Generate checksum
185: // H1 = HMAC(Ki, conf | plaintext | pad)
186: byte[] hmac = getHmac(Ki, toBeEncrypted);
187:
188: if (debug) {
189: traceOutput("hmac", hmac, 0, hmac.length);
190: traceOutput("ciphertext", ciphertext, 0, Math.min(
191: ciphertext.length, 32));
192: }
193:
194: // C1 | H1[1..h]
195: System.arraycopy(hmac, 0, ciphertext, cipherSize,
196: getChecksumLength());
197: return ciphertext;
198: } finally {
199: if (Ke != null) {
200: Arrays.fill(Ke, 0, Ke.length, (byte) 0);
201: }
202: if (Ki != null) {
203: Arrays.fill(Ki, 0, Ki.length, (byte) 0);
204: }
205: }
206: }
207:
208: /**
209: * Performs encryption using given key only; does not add
210: * confounder, padding, or checksum. Incoming data to be encrypted
211: * assumed to have the correct blocksize.
212: * Ignore key usage.
213: */
214: public byte[] encryptRaw(byte[] baseKey, int usage, byte[] ivec,
215: byte[] plaintext, int start, int len)
216: throws GeneralSecurityException, KrbCryptoException {
217:
218: if (debug) {
219: System.err.println("usage: " + usage);
220: if (ivec != null) {
221: traceOutput("old_state.ivec", ivec, 0, ivec.length);
222: }
223: traceOutput("plaintext", plaintext, start, Math
224: .min(len, 32));
225: traceOutput("baseKey", baseKey, 0, baseKey.length);
226: }
227:
228: // Encrypt
229: Cipher encCipher = getCipher(baseKey, ivec, Cipher.ENCRYPT_MODE);
230: int blockSize = encCipher.getBlockSize();
231:
232: if ((len % blockSize) != 0) {
233: throw new GeneralSecurityException(
234: "length of data to be encrypted (" + len
235: + ") is not a multiple of the blocksize ("
236: + blockSize + ")");
237: }
238:
239: int cipherSize = encCipher.getOutputSize(len);
240: byte[] ciphertext = new byte[cipherSize];
241:
242: encCipher.doFinal(plaintext, 0, len, ciphertext, 0);
243: return ciphertext;
244: }
245:
246: /**
247: * Decrypts data using specified key and initial vector.
248: * @param baseKey encryption key to use
249: * @param ciphertext encrypted data to be decrypted
250: * @param usage ignored
251: */
252: public byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
253: byte[] ciphertext, int start, int len)
254: throws GeneralSecurityException {
255:
256: if (debug) {
257: System.err.println("usage: " + usage);
258: if (ivec != null) {
259: traceOutput("old_state.ivec", ivec, 0, ivec.length);
260: }
261: traceOutput("ciphertext", ciphertext, start, Math.min(len,
262: 32));
263: traceOutput("baseKey", baseKey, 0, baseKey.length);
264: }
265:
266: Cipher decCipher = getCipher(baseKey, ivec, Cipher.DECRYPT_MODE);
267:
268: int blockSize = decCipher.getBlockSize();
269:
270: if ((len % blockSize) != 0) {
271: throw new GeneralSecurityException(
272: "length of data to be decrypted (" + len
273: + ") is not a multiple of the blocksize ("
274: + blockSize + ")");
275: }
276:
277: byte[] decrypted = decCipher.doFinal(ciphertext, start, len);
278:
279: if (debug) {
280: traceOutput("decrypted", decrypted, 0, Math.min(
281: decrypted.length, 32));
282: }
283:
284: return decrypted;
285: }
286:
287: /**
288: * @param baseKey key from which keys are to be derived using usage
289: * @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
290: */
291: public byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
292: byte[] ciphertext, int start, int len)
293: throws GeneralSecurityException {
294:
295: if (!KeyUsage.isValid(usage)) {
296: throw new GeneralSecurityException(
297: "Invalid key usage number: " + usage);
298: }
299:
300: byte[] Ke = null;
301: byte[] Ki = null;
302:
303: try {
304: // Derive encryption key
305: byte[] constant = new byte[5];
306: constant[0] = (byte) ((usage >> 24) & 0xff);
307: constant[1] = (byte) ((usage >> 16) & 0xff);
308: constant[2] = (byte) ((usage >> 8) & 0xff);
309: constant[3] = (byte) (usage & 0xff);
310:
311: constant[4] = (byte) 0xaa;
312:
313: Ke = dk(baseKey, constant); // Encryption key
314:
315: if (debug) {
316: System.err.println("usage: " + usage);
317: if (ivec != null) {
318: traceOutput("old_state.ivec", ivec, 0, ivec.length);
319: }
320: traceOutput("ciphertext", ciphertext, start, Math.min(
321: len, 32));
322: traceOutput("constant", constant, 0, constant.length);
323: traceOutput("baseKey", baseKey, 0, baseKey.length);
324: traceOutput("Ke", Ke, 0, Ke.length);
325: }
326:
327: Cipher decCipher = getCipher(Ke, ivec, Cipher.DECRYPT_MODE);
328: int blockSize = decCipher.getBlockSize();
329:
330: // Decrypt [confounder | plaintext | padding] (without checksum)
331: int cksumSize = getChecksumLength();
332: int cipherSize = len - cksumSize;
333: byte[] decrypted = decCipher.doFinal(ciphertext, start,
334: cipherSize);
335:
336: if (debug) {
337: traceOutput("decrypted", decrypted, 0, Math.min(
338: decrypted.length, 32));
339: }
340:
341: // decrypted = [confounder | plaintext | padding]
342:
343: // Derive integrity key
344: constant[4] = (byte) 0x55;
345: Ki = dk(baseKey, constant); // Integrity key
346: if (debug) {
347: traceOutput("constant", constant, 0, constant.length);
348: traceOutput("Ki", Ki, 0, Ke.length);
349: }
350:
351: // Verify checksum
352: // H1 = HMAC(Ki, conf | plaintext | pad)
353: byte[] calculatedHmac = getHmac(Ki, decrypted);
354:
355: if (debug) {
356: traceOutput("calculated Hmac", calculatedHmac, 0,
357: calculatedHmac.length);
358: traceOutput("message Hmac", ciphertext, cipherSize,
359: cksumSize);
360: }
361:
362: boolean cksumFailed = false;
363: if (calculatedHmac.length >= cksumSize) {
364: for (int i = 0; i < cksumSize; i++) {
365: if (calculatedHmac[i] != ciphertext[cipherSize + i]) {
366: cksumFailed = true;
367: break;
368: }
369: }
370: }
371:
372: if (cksumFailed) {
373: throw new GeneralSecurityException("Checksum failed");
374: }
375:
376: // Prepare decrypted msg and ivec to be returned
377: // Last blockSize bytes of ciphertext without checksum
378: if (ivec != null && ivec.length == blockSize) {
379: System.arraycopy(ciphertext, start + cipherSize
380: - blockSize, ivec, 0, blockSize);
381: if (debug) {
382: traceOutput("new_state.ivec", ivec, 0, ivec.length);
383: }
384: }
385:
386: // Get rid of confounder
387: // [plaintext | padding]
388: byte[] plaintext = new byte[decrypted.length - blockSize];
389: System.arraycopy(decrypted, blockSize, plaintext, 0,
390: plaintext.length);
391: return plaintext; // padding still there
392: } finally {
393: if (Ke != null) {
394: Arrays.fill(Ke, 0, Ke.length, (byte) 0);
395: }
396: if (Ki != null) {
397: Arrays.fill(Ki, 0, Ki.length, (byte) 0);
398: }
399: }
400: }
401:
402: // Round up to the next blocksize
403: int roundup(int n, int blocksize) {
404: return (((n + blocksize - 1) / blocksize) * blocksize);
405: }
406:
407: public byte[] calculateChecksum(byte[] baseKey, int usage,
408: byte[] input, int start, int len)
409: throws GeneralSecurityException {
410:
411: if (!KeyUsage.isValid(usage)) {
412: throw new GeneralSecurityException(
413: "Invalid key usage number: " + usage);
414: }
415:
416: // Derive keys
417: byte[] constant = new byte[5];
418: constant[0] = (byte) ((usage >> 24) & 0xff);
419: constant[1] = (byte) ((usage >> 16) & 0xff);
420: constant[2] = (byte) ((usage >> 8) & 0xff);
421: constant[3] = (byte) (usage & 0xff);
422:
423: constant[4] = (byte) 0x99;
424:
425: byte[] Kc = dk(baseKey, constant); // Checksum key
426: if (debug) {
427: System.err.println("usage: " + usage);
428: traceOutput("input", input, start, Math.min(len, 32));
429: traceOutput("constant", constant, 0, constant.length);
430: traceOutput("baseKey", baseKey, 0, baseKey.length);
431: traceOutput("Kc", Kc, 0, Kc.length);
432: }
433:
434: try {
435: // Generate checksum
436: // H1 = HMAC(Kc, input)
437: byte[] hmac = getHmac(Kc, input);
438: if (debug) {
439: traceOutput("hmac", hmac, 0, hmac.length);
440: }
441: if (hmac.length == getChecksumLength()) {
442: return hmac;
443: } else if (hmac.length > getChecksumLength()) {
444: byte[] buf = new byte[getChecksumLength()];
445: System.arraycopy(hmac, 0, buf, 0, buf.length);
446: return buf;
447: } else {
448: throw new GeneralSecurityException(
449: "checksum size too short: " + hmac.length
450: + "; expecting : "
451: + getChecksumLength());
452: }
453: } finally {
454: Arrays.fill(Kc, 0, Kc.length, (byte) 0);
455: }
456: }
457:
458: // DK(Key, Constant) = random-to-key(DR(Key, Constant))
459: byte[] dk(byte[] key, byte[] constant)
460: throws GeneralSecurityException {
461: return randomToKey(dr(key, constant));
462: }
463:
464: /*
465: * From RFC 3961.
466: *
467: * DR(Key, Constant) = k-truncate(E(Key, Constant,
468: * initial-cipher-state))
469: *
470: * Here DR is the random-octet generation function described below, and
471: * DK is the key-derivation function produced from it. In this
472: * construction, E(Key, Plaintext, CipherState) is a cipher, Constant is
473: * a well-known constant determined by the specific usage of this
474: * function, and k-truncate truncates its argument by taking the first k
475: * bits. Here, k is the key generation seed length needed for the
476: * encryption system.
477: *
478: * The output of the DR function is a string of bits; the actual key is
479: * produced by applying the cryptosystem's random-to-key operation on
480: * this bitstring.
481: *
482: * If the Constant is smaller than the cipher block size of E, then it
483: * must be expanded with n-fold() so it can be encrypted. If the output
484: * of E is shorter than k bits it is fed back into the encryption as
485: * many times as necessary. The construct is as follows (where |
486: * indicates concatentation):
487: *
488: * K1 = E(Key, n-fold(Constant), initial-cipher-state)
489: * K2 = E(Key, K1, initial-cipher-state)
490: * K3 = E(Key, K2, initial-cipher-state)
491: * K4 = ...
492: *
493: * DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
494: */
495: private byte[] dr(byte[] key, byte[] constant)
496: throws GeneralSecurityException {
497:
498: Cipher encCipher = getCipher(key, null, Cipher.ENCRYPT_MODE);
499: int blocksize = encCipher.getBlockSize();
500:
501: if (constant.length != blocksize) {
502: constant = nfold(constant, blocksize * 8);
503: }
504: byte[] toBeEncrypted = constant;
505:
506: int keybytes = (getKeySeedLength() >> 3); // from bits to bytes
507: byte[] rawkey = new byte[keybytes];
508: int posn = 0;
509:
510: /* loop encrypting the blocks until enough key bytes are generated */
511: int n = 0, len;
512: while (n < keybytes) {
513: if (debug) {
514: System.err.println("Encrypting: "
515: + bytesToString(toBeEncrypted));
516: }
517:
518: byte[] cipherBlock = encCipher.doFinal(toBeEncrypted);
519: if (debug) {
520: System.err.println("K: " + ++posn + " = "
521: + bytesToString(cipherBlock));
522: }
523:
524: len = (keybytes - n <= cipherBlock.length ? (keybytes - n)
525: : cipherBlock.length);
526: if (debug) {
527: System.err.println("copying " + len + " key bytes");
528: }
529: System.arraycopy(cipherBlock, 0, rawkey, n, len);
530: n += len;
531: toBeEncrypted = cipherBlock;
532: }
533: return rawkey;
534: }
535:
536: // ---------------------------------
537:
538: // From MIT-1.3.1 distribution
539: /*
540: * n-fold(k-bits):
541: * l = lcm(n,k)
542: * r = l/k
543: * s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
544: * compute the 1's complement sum:
545: * n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
546: */
547:
548: /*
549: * representation: msb first, assume n and k are multiples of 8, and
550: * that k>=16. this is the case of all the cryptosystems which are
551: * likely to be used. this function can be replaced if that
552: * assumption ever fails.
553: */
554:
555: /* input length is in bits */
556: static byte[] nfold(byte[] in, int outbits) {
557:
558: int inbits = in.length;
559: outbits >>= 3; // count in bytes
560:
561: /* first compute lcm(n,k) */
562: int a, b, c, lcm;
563: a = outbits; // n
564: b = inbits; // k
565:
566: while (b != 0) {
567: c = b;
568: b = a % b;
569: a = c;
570: }
571: lcm = outbits * inbits / a;
572:
573: if (debug) {
574: System.err.println("k: " + inbits);
575: System.err.println("n: " + outbits);
576: System.err.println("lcm: " + lcm);
577: }
578:
579: /* now do the real work */
580: byte[] out = new byte[outbits];
581: Arrays.fill(out, (byte) 0);
582:
583: int this byte = 0;
584: int msbit, i, bval, oval;
585:
586: // this will end up cycling through k lcm(k,n)/k times, which
587: // is correct
588: for (i = lcm - 1; i >= 0; i--) {
589: /* compute the msbit in k which gets added into this byte */
590: msbit = (/* first, start with msbit in the first, unrotated byte */
591: ((inbits << 3) - 1)
592: /* then, for each byte, shift to right for each repetition */
593: + (((inbits << 3) + 13) * (i / inbits))
594: /* last, pick out correct byte within that shifted repetition */
595: + ((inbits - (i % inbits)) << 3)) % (inbits << 3);
596:
597: /* pull out the byte value itself */
598: // Mask off values using &0xff to get only the lower byte
599: // Use >>> to avoid sign extension
600: bval = ((((in[((inbits - 1) - (msbit >>> 3)) % inbits] & 0xff) << 8) | (in[((inbits) - (msbit >>> 3))
601: % inbits] & 0xff)) >>> ((msbit & 7) + 1)) & 0xff;
602:
603: /*
604: System.err.println("((" +
605: ((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)
606: + "|" + (in[((inbits)-(msbit>>>3))%inbits]&0xff) + ")"
607: + ">>>" + ((msbit&7)+1) + ")&0xff = " + bval);
608: */
609:
610: this byte += bval;
611:
612: /* do the addition */
613: // Mask off values using &0xff to get only the lower byte
614: oval = (out[i % outbits] & 0xff);
615: this byte += oval;
616: out[i % outbits] = (byte) (this byte & 0xff);
617:
618: if (debug) {
619: System.err.println("msbit[" + i + "] = " + msbit
620: + "\tbval=" + Integer.toHexString(bval)
621: + "\toval=" + Integer.toHexString(oval)
622: + "\tsum = " + Integer.toHexString(this byte));
623: }
624:
625: /* keep around the carry bit, if any */
626: this byte >>>= 8;
627:
628: if (debug) {
629: System.err.println("carry=" + this byte);
630: }
631: }
632:
633: /* if there's a carry bit left over, add it back in */
634: if (this byte != 0) {
635: for (i = outbits - 1; i >= 0; i--) {
636: /* do the addition */
637: this byte += (out[i] & 0xff);
638: out[i] = (byte) (this byte & 0xff);
639:
640: /* keep around the carry bit, if any */
641: this byte >>>= 8;
642: }
643: }
644:
645: return out;
646: }
647:
648: // Routines used for debugging
649: static String bytesToString(byte[] digest) {
650: // Get character representation of digest
651: StringBuffer digestString = new StringBuffer();
652:
653: for (int i = 0; i < digest.length; i++) {
654: if ((digest[i] & 0x000000ff) < 0x10) {
655: digestString.append("0"
656: + Integer.toHexString(digest[i] & 0x000000ff));
657: } else {
658: digestString.append(Integer
659: .toHexString(digest[i] & 0x000000ff));
660: }
661: }
662: return digestString.toString();
663: }
664:
665: private static byte[] binaryStringToBytes(String str) {
666: char[] usageStr = str.toCharArray();
667: byte[] usage = new byte[usageStr.length / 2];
668: for (int i = 0; i < usage.length; i++) {
669: byte a = Byte.parseByte(new String(usageStr, i * 2, 1), 16);
670: byte b = Byte.parseByte(new String(usageStr, i * 2 + 1, 1),
671: 16);
672: usage[i] = (byte) ((a << 4) | b);
673: }
674: return usage;
675: }
676:
677: static void traceOutput(String traceTag, byte[] output, int offset,
678: int len) {
679: try {
680: ByteArrayOutputStream out = new ByteArrayOutputStream(len);
681: new HexDumpEncoder().encodeBuffer(new ByteArrayInputStream(
682: output, offset, len), out);
683:
684: System.err.println(traceTag + ":" + out.toString());
685: } catch (Exception e) {
686: }
687: }
688:
689: // String.getBytes("UTF-8");
690: // Do this instead of using String to avoid making password immutable
691: static byte[] charToUtf8(char[] chars) {
692: Charset utf8 = Charset.forName("UTF-8");
693:
694: CharBuffer cb = CharBuffer.wrap(chars);
695: ByteBuffer bb = utf8.encode(cb);
696: int len = bb.limit();
697: byte[] answer = new byte[len];
698: bb.get(answer, 0, len);
699: return answer;
700: }
701:
702: static byte[] charToUtf16(char[] chars) {
703: Charset utf8 = Charset.forName("UTF-16LE");
704:
705: CharBuffer cb = CharBuffer.wrap(chars);
706: ByteBuffer bb = utf8.encode(cb);
707: int len = bb.limit();
708: byte[] answer = new byte[len];
709: bb.get(answer, 0, len);
710: return answer;
711: }
712: }
|