package org.javastack.sftpserver;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Arrays;

import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.codec.digest.Sha2Crypt;

public class PasswordEncrypt {
	private static final Charset US_ASCII = Charset.forName("US-ASCII");
	public final String md5;
	public final String apr1; // md5
	public final String sha256;
	public final String sha512;

	public PasswordEncrypt(final String key) {
		final byte[] keyBytes = key.getBytes(US_ASCII);
		this.md5 = Md5Crypt.md5Crypt(keyBytes.clone());
		this.apr1 = Md5Crypt.apr1Crypt(keyBytes.clone());
		this.sha256 = Sha2Crypt.sha256Crypt(keyBytes.clone());
		this.sha512 = Sha2Crypt.sha512Crypt(keyBytes.clone());
		Arrays.fill(keyBytes, (byte) 0);
	}

	public static boolean isCrypted(final String input) {
		if ((input == null) || input.isEmpty())
			return false;
		if (input.charAt(0) != '$')
			return false;
		if (input.startsWith("$1$") ||        // MD5
				input.startsWith("$apr1$") || // APR1
				input.startsWith("$5$") ||    // SHA2-256
				input.startsWith("$6$")) {    // SHA2-512
			return true;
		}
		return false;
	}

	public static boolean checkPassword(final String crypted, final String key) {
		String crypted2 = null;
		if (crypted == null)
			return false;
		if (crypted.length() < 24)
			return false;
		if (crypted.charAt(0) != '$')
			return false;
		final int offset2ndDolar = crypted.indexOf('$', 1);
		if (offset2ndDolar < 0)
			return false;
		final int offset3ndDolar = crypted.indexOf('$', offset2ndDolar + 1);
		if (offset3ndDolar < 0)
			return false;
		final String salt = crypted.substring(0, offset3ndDolar + 1);
		final byte[] keyBytes = key.getBytes(US_ASCII);
		if (crypted.startsWith("$1$")) { // MD5
			crypted2 = Md5Crypt.md5Crypt(keyBytes.clone(), salt);
		} else if (crypted.startsWith("$apr1$")) { // APR1
			crypted2 = Md5Crypt.apr1Crypt(keyBytes.clone(), salt);
		} else if (crypted.startsWith("$5$")) { // SHA2-256
			crypted2 = Sha2Crypt.sha256Crypt(keyBytes.clone(), salt);
		} else if (crypted.startsWith("$6$")) { // SHA2-512
			crypted2 = Sha2Crypt.sha512Crypt(keyBytes.clone(), salt);
		}
		Arrays.fill(keyBytes, (byte) 0);
		if (crypted2 == null)
			return false;
		return crypted.equals(crypted2);
	}

	@Override
	public String toString() {
		final StringBuilder sb = new StringBuilder(16 + md5.length() + apr1.length() + sha256.length()
				+ sha512.length());
		sb.append("md5=").append(md5).append(' ');
		sb.append("apr1=").append(apr1).append(' ');
		sb.append("sha256=").append(sha256).append(' ');
		sb.append("sha512=").append(sha512);
		return sb.toString();
	}

	public static void main(final String[] args) throws Throwable {
		final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String key = null;
		if (args.length == 0) {
			System.out.println("Enter new password: ");
			key = in.readLine().trim();
			System.out.println("Retype new password: ");
			if (!key.equals(in.readLine().trim())) {
				System.out.println("Sorry, passwords do not match");
				return;
			}
		} else {
			key = args[0];
			if (key.startsWith("-")) {
				if (key.equals("-h") || key.equals("--help")) {
					System.out.println(PasswordEncrypt.class.getName() + " [<password>]");
					return;
				}
			}
		}
		final PasswordEncrypt crypt = new PasswordEncrypt(key);
		System.out.println(crypt.toString().replace(' ', '\n'));
		// Sample:
		// plain=changeit
		// md5=$1$Ndo.HC0w$ZilSmY0T22G.haCsIKNBq1
		// apr1=$apr1$I5GYTkfO$6LN/fWivetFT0avEP9WdI/
		// sha256=$5$sVB7PKni$xyo0VYNfaWEqa8lQ5kGbwKogEoQO9w0/b/l.tS1PnUD
		// sha512=$6$/aLGYlhc$8Jn6qlvvr5i9lc2CwSCQX1qiAkEbKKfaXbhCjjRueTp4jqN1iM5o9YBJ/7u7VL2hSWE.huvUtsjH1UoVxBRXJ0
	}
}