package org.safehaus.penrose.password; import org.apache.log4j.Level; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.PatternLayout; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.xml.DOMConfigurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.vps.crypt.Crypt; import org.safehaus.penrose.util.BinaryUtil; import org.safehaus.penrose.samba.SambaUtil; import gnu.getopt.LongOpt; import gnu.getopt.Getopt; import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; import java.io.File; import java.security.MessageDigest; import arlut.csd.crypto.MD5Crypt; import arlut.csd.crypto.Sha256Crypt; import arlut.csd.crypto.Sha512Crypt; /** * @author Endi Sukma Dewata */ public class Password { public static Logger log = LoggerFactory.getLogger(Password.class); public final static String CRYPT = "crypt"; public final static String CRYPT_MD5 = "crypt-md5"; public final static String CRYPT_SHA256 = "crypt-sha256"; public final static String CRYPT_SHA512 = "crypt-sha512"; public final static String NT = "nt"; public final static String LM = "lm"; public static String SALT_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; String encryption; String password; String salt; int rounds; public Password(String encryption, String password) throws Exception { this.encryption = encryption; this.password = password; } public Password(String encryption, String password, String salt, int rounds) throws Exception { this.encryption = encryption; this.password = password; this.salt = salt; this.rounds = rounds; } public String encrypt() throws Exception { boolean debug = log.isDebugEnabled(); if (debug) { log.debug("Encrypting password:"); log.debug(" - encryption: ["+encryption+"]"); log.debug(" - password : ["+password+"]"); log.debug(" - salt : ["+salt+"]"); log.debug(" - rounds : ["+rounds+"]"); } String result; if (password == null) { result = null; } else if (encryption == null) { result = password; } else if (CRYPT.equalsIgnoreCase(encryption)) { salt = salt == null ? createSalt(2) : salt; result = Crypt.crypt(salt, password); } else if (CRYPT_MD5.equalsIgnoreCase(encryption)) { salt = salt == null ? createSalt(8) : salt; result = MD5Crypt.crypt(password, salt); } else if (CRYPT_SHA256.equalsIgnoreCase(encryption)) { salt = salt == null ? createSalt(16) : salt; result = Sha256Crypt.Sha256_crypt(password, salt, rounds); } else if (CRYPT_SHA512.equalsIgnoreCase(encryption)) { salt = salt == null ? createSalt(16) : salt; result = Sha512Crypt.Sha512_crypt(password, salt, rounds); } else if (NT.equalsIgnoreCase(encryption)) { result = SambaUtil.encryptNTPassword(password); } else if (LM.equalsIgnoreCase(encryption)) { result = SambaUtil.encryptLMPassword(password); } else { MessageDigest md = MessageDigest.getInstance(encryption); md.update(password.getBytes()); result = BinaryUtil.encode(BinaryUtil.BASE64, md.digest()); } if (debug) log.debug("Result: "+result); return result; } public String createSalt(int length) { StringBuilder sb = new StringBuilder(); for (int i=0; i<length; i++) { int r = (int)(Math.random() * SALT_CHARACTERS.length()); sb.append(SALT_CHARACTERS.charAt(r)); } return sb.toString(); } public static boolean validate(String encryption, String password, String hash) throws Exception { boolean debug = log.isDebugEnabled(); if (CRYPT.equalsIgnoreCase(encryption)) { if (hash.startsWith("$1$")) { encryption = CRYPT_MD5; } else if (hash.startsWith("$5$")) { encryption = CRYPT_SHA256; } else if (hash.startsWith("$6$")) { encryption = CRYPT_SHA512; } } String newHash = new Password(encryption, password, hash, 0).encrypt(); if (debug) { log.debug("Validating passwords:"); log.debug(" - supplied : ["+newHash+"]"); log.debug(" - stored : ["+hash+"]"); } boolean result = newHash.equals(hash); if (debug) log.debug("Result: "+result); return result; } public static void showUsage() { System.out.println("Usage: org.safehaus.penrose.password.Password [OPTION]... <command> [arguments]..."); System.out.println(); System.out.println("Options:"); System.out.println(" -?, --help display this help and exit"); System.out.println(" -d run in debug mode"); System.out.println(" -v run in verbose mode"); System.out.println(); System.out.println("Commands:"); System.out.println(" crypt <password> [salt]"); System.out.println(" crypt-md5 <password> [salt]"); System.out.println(" crypt-sha256 <password> [salt [rounds]]"); System.out.println(" crypt-sha512 <password> [salt [rounds]]"); System.out.println(" md5 <password>"); System.out.println(" sha <password>"); System.out.println(" <encryption> <password>"); } public static void main(String args[]) throws Exception { Level level = Level.WARN; LongOpt[] longopts = new LongOpt[1]; longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, '?'); Getopt getopt = new Getopt("Password", args, "-:?dv", longopts); Collection<String> parameters = new ArrayList<String>(); int c; while ((c = getopt.getopt()) != -1) { switch (c) { case ':': case '?': showUsage(); System.exit(0); break; case 1: parameters.add(getopt.getOptarg()); break; case 'd': level = Level.DEBUG; break; case 'v': level = Level.INFO; break; } } if (parameters.size() == 0) { showUsage(); System.exit(0); } File clientHome = new File(System.getProperty("org.safehaus.penrose.client.home")); org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger("org.safehaus.penrose"); File log4jXml = new File(clientHome, "conf"+File.separator+"log4j.xml"); if (level.equals(Level.DEBUG)) { logger.setLevel(level); ConsoleAppender appender = new ConsoleAppender(new PatternLayout("%-20C{1} [%4L] %m%n")); BasicConfigurator.configure(appender); } else if (level.equals(Level.INFO)) { logger.setLevel(level); ConsoleAppender appender = new ConsoleAppender(new PatternLayout("[%d{MM/dd/yyyy HH:mm:ss}] %m%n")); BasicConfigurator.configure(appender); } else if (log4jXml.exists()) { DOMConfigurator.configure(log4jXml.getAbsolutePath()); } else { logger.setLevel(level); ConsoleAppender appender = new ConsoleAppender(new PatternLayout("[%d{MM/dd/yyyy HH:mm:ss}] %m%n")); BasicConfigurator.configure(appender); } Iterator<String> iterator = parameters.iterator(); String method = iterator.next(); log.debug("Method: "+method); String password = iterator.next(); log.debug("Password: "+password); String salt = null; String rounds = null; if (iterator.hasNext()) { salt = iterator.next(); log.debug("Salt: "+salt); if (iterator.hasNext()) { rounds = iterator.next(); log.debug("Rounds: "+rounds); } } Password p = new Password( method, password, salt == null || "".equals(salt) ? null : salt, rounds == null || "".equals(rounds) ? 0 : Integer.parseInt(rounds) ); System.out.println(p.encrypt()); } }