2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util.security;
21 import java.io.IOException;
22 import java.nio.charset.StandardCharsets;
23 import java.util.Arrays;
24 import java.util.Locale;
26 import org.eclipse.jetty.util.log.Log;
27 import org.eclipse.jetty.util.log.Logger;
29 /* ------------------------------------------------------------ */
31 * Password utility class.
33 * This utility class gets a password or pass phrase either by:
36 * + Password is set as a system property.
37 * + The password is prompted for and read from standard input
38 * + A program is run to get the password.
41 * Passwords that begin with OBF: are de obfuscated. Passwords can be obfuscated
42 * by run org.eclipse.util.Password as a main class. Obfuscated password are
43 * required if a system needs to recover the full password (eg. so that it may
44 * be passed to another system). They are not secure, but prevent casual
47 * Passwords that begin with CRYPT: are oneway encrypted with UnixCrypt. The
48 * real password cannot be retrieved, but comparisons can be made to other
49 * passwords. A Crypt can be generated by running org.eclipse.util.UnixCrypt as
50 * a main class, passing password and then the username. Checksum passwords are
51 * a secure(ish) way to store passwords that only need to be checked rather than
52 * recovered. Note that it is not strong security - specially if simple
57 public class Password extends Credential
59 private static final Logger LOG = Log.getLogger(Password.class);
61 private static final long serialVersionUID = 5062906681431569445L;
63 public static final String __OBFUSCATE = "OBF:";
67 /* ------------------------------------------------------------ */
71 * @param password The String password.
73 public Password(String password)
78 while (_pw != null && _pw.startsWith(__OBFUSCATE))
79 _pw = deobfuscate(_pw);
82 /* ------------------------------------------------------------ */
84 public String toString()
89 /* ------------------------------------------------------------ */
90 public String toStarString()
92 return "*****************************************************".substring(0, _pw.length());
95 /* ------------------------------------------------------------ */
97 public boolean check(Object credentials)
99 if (this == credentials) return true;
101 if (credentials instanceof Password) return credentials.equals(_pw);
103 if (credentials instanceof String) return credentials.equals(_pw);
105 if (credentials instanceof char[]) return Arrays.equals(_pw.toCharArray(), (char[]) credentials);
107 if (credentials instanceof Credential) return ((Credential) credentials).check(_pw);
112 /* ------------------------------------------------------------ */
114 public boolean equals(Object o)
122 if (o instanceof Password)
124 Password p = (Password) o;
125 //noinspection StringEquality
126 return p._pw == _pw || (null != _pw && _pw.equals(p._pw));
129 if (o instanceof String)
130 return o.equals(_pw);
135 /* ------------------------------------------------------------ */
137 public int hashCode()
139 return null == _pw ? super.hashCode() : _pw.hashCode();
142 /* ------------------------------------------------------------ */
143 public static String obfuscate(String s)
145 StringBuilder buf = new StringBuilder();
146 byte[] b = s.getBytes(StandardCharsets.UTF_8);
148 buf.append(__OBFUSCATE);
149 for (int i = 0; i < b.length; i++)
152 byte b2 = b[b.length - (i + 1)];
155 int i0 = (0xff&b1)*256 + (0xff&b2);
156 String x = Integer.toString(i0, 36).toLowerCase(Locale.ENGLISH);
157 buf.append("U0000",0,5-x.length());
162 int i1 = 127 + b1 + b2;
163 int i2 = 127 + b1 - b2;
164 int i0 = i1 * 256 + i2;
165 String x = Integer.toString(i0, 36).toLowerCase(Locale.ENGLISH);
167 int j0 = Integer.parseInt(x, 36);
170 byte bx = (byte) ((j1 + j2 - 254) / 2);
172 buf.append("000",0,4-x.length());
177 return buf.toString();
181 /* ------------------------------------------------------------ */
182 public static String deobfuscate(String s)
184 if (s.startsWith(__OBFUSCATE)) s = s.substring(4);
186 byte[] b = new byte[s.length() / 2];
188 for (int i = 0; i < s.length(); i += 4)
190 if (s.charAt(i)=='U')
193 String x = s.substring(i, i + 4);
194 int i0 = Integer.parseInt(x, 36);
195 byte bx = (byte)(i0>>8);
200 String x = s.substring(i, i + 4);
201 int i0 = Integer.parseInt(x, 36);
204 byte bx = (byte) ((i1 + i2 - 254) / 2);
209 return new String(b, 0, l,StandardCharsets.UTF_8);
212 /* ------------------------------------------------------------ */
214 * Get a password. A password is obtained by trying
216 * <LI>Calling <Code>System.getProperty(realm,dft)</Code>
217 * <LI>Prompting for a password
218 * <LI>Using promptDft if nothing was entered.
221 * @param realm The realm name for the password, used as a SystemProperty
223 * @param dft The default password.
224 * @param promptDft The default to use if prompting for the password.
227 public static Password getPassword(String realm, String dft, String promptDft)
229 String passwd = System.getProperty(realm, dft);
230 if (passwd == null || passwd.length() == 0)
234 System.out.print(realm + ((promptDft != null && promptDft.length() > 0) ? " [dft]" : "") + " : ");
236 byte[] buf = new byte[512];
237 int len = System.in.read(buf);
238 if (len > 0) passwd = new String(buf, 0, len).trim();
240 catch (IOException e)
242 LOG.warn(Log.EXCEPTION, e);
244 if (passwd == null || passwd.length() == 0) passwd = promptDft;
246 return new Password(passwd);
249 /* ------------------------------------------------------------ */
253 public static void main(String[] arg)
255 if (arg.length != 1 && arg.length != 2)
257 System.err.println("Usage - java org.eclipse.jetty.security.Password [<user>] <password>");
258 System.err.println("If the password is ?, the user will be prompted for the password");
261 String p = arg[arg.length == 1 ? 0 : 1];
262 Password pw = new Password(p);
263 System.err.println(pw.toString());
264 System.err.println(obfuscate(pw.toString()));
265 System.err.println(Credential.MD5.digest(p));
266 if (arg.length == 2) System.err.println(Credential.Crypt.crypt(arg[0], pw.toString()));