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