001: /*
002: * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.util;
027:
028: import java.io.*;
029: import java.nio.*;
030: import java.nio.charset.*;
031: import java.util.Arrays;
032:
033: /**
034: * A utility class for reading passwords
035: *
036: * @version 1.3
037: */
038: public class Password {
039: /** Reads user password from given input stream. */
040: public static char[] readPassword(InputStream in)
041: throws IOException {
042:
043: char[] consoleEntered = null;
044: byte[] consoleBytes = null;
045:
046: try {
047: // Use the new java.io.Console class
048: Console con = null;
049: if (in == System.in && ((con = System.console()) != null)) {
050: consoleEntered = con.readPassword();
051: // readPassword returns "" if you just print ENTER,
052: // to be compatible with old Password class, change to null
053: if (consoleEntered != null
054: && consoleEntered.length == 0) {
055: return null;
056: }
057: consoleBytes = convertToBytes(consoleEntered);
058: in = new ByteArrayInputStream(consoleBytes);
059: }
060:
061: // Rest of the lines still necessary for KeyStoreLoginModule
062: // and when there is no console.
063:
064: char[] lineBuffer;
065: char[] buf;
066: int i;
067:
068: buf = lineBuffer = new char[128];
069:
070: int room = buf.length;
071: int offset = 0;
072: int c;
073:
074: boolean done = false;
075: while (!done) {
076: switch (c = in.read()) {
077: case -1:
078: case '\n':
079: done = true;
080: break;
081:
082: case '\r':
083: int c2 = in.read();
084: if ((c2 != '\n') && (c2 != -1)) {
085: if (!(in instanceof PushbackInputStream)) {
086: in = new PushbackInputStream(in);
087: }
088: ((PushbackInputStream) in).unread(c2);
089: } else {
090: done = true;
091: break;
092: }
093:
094: default:
095: if (--room < 0) {
096: buf = new char[offset + 128];
097: room = buf.length - offset - 1;
098: System.arraycopy(lineBuffer, 0, buf, 0, offset);
099: Arrays.fill(lineBuffer, ' ');
100: lineBuffer = buf;
101: }
102: buf[offset++] = (char) c;
103: break;
104: }
105: }
106:
107: if (offset == 0) {
108: return null;
109: }
110:
111: char[] ret = new char[offset];
112: System.arraycopy(buf, 0, ret, 0, offset);
113: Arrays.fill(buf, ' ');
114:
115: return ret;
116: } finally {
117: if (consoleEntered != null) {
118: Arrays.fill(consoleEntered, ' ');
119: }
120: if (consoleBytes != null) {
121: Arrays.fill(consoleBytes, (byte) 0);
122: }
123: }
124: }
125:
126: /**
127: * Change a password read from Console.readPassword() into
128: * its original bytes.
129: *
130: * @param pass a char[]
131: * @return its byte[] format, similar to new String(pass).getBytes()
132: */
133: private static byte[] convertToBytes(char[] pass) {
134: if (enc == null) {
135: synchronized (Password.class) {
136: enc = sun.misc.SharedSecrets.getJavaIOAccess()
137: .charset().newEncoder().onMalformedInput(
138: CodingErrorAction.REPLACE)
139: .onUnmappableCharacter(
140: CodingErrorAction.REPLACE);
141: }
142: }
143: byte[] ba = new byte[(int) (enc.maxBytesPerChar() * pass.length)];
144: ByteBuffer bb = ByteBuffer.wrap(ba);
145: synchronized (enc) {
146: enc.reset().encode(CharBuffer.wrap(pass), bb, true);
147: }
148: if (bb.position() < ba.length) {
149: ba[bb.position()] = '\n';
150: }
151: return ba;
152: }
153:
154: private static volatile CharsetEncoder enc;
155: }
|