#!/usr/bin/env compileAndGo # -*- coding: utf-8 mode: java -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 compiler=javac mainClass=upassword compileAndGo import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.regex.Pattern; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; public class upassword { public static final String UTF_8 = "UTF-8"; public static final int MIN_LEN = 8; public static final int MIN_UPPER = 0; public static final int MIN_LOWER = 0; public static final int MIN_ALPHA = 2; public static final int MIN_NUMBER = 0; public static final int MIN_SYMBOL = 0; public static final int MIN_SPECIAL = 2; public static final boolean ALLOW_MULTIBYTES = false; public static final String getSummary(Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); return sw.toString(); } public static final void println(String text) { System.out.println(text); System.out.flush(); } public static final StringBuilder toHex(StringBuilder sb, byte b) { if (sb == null) return null; int l = b & 0x0F, u = (b & 0xF0) >> 4; u += u < 10? '0': 'A' - 10; l += l < 10? '0': 'A' - 10; return sb.append((char)u).append((char)l); } public static final String toHex(byte[] ba) { if (ba == null) return null; StringBuilder sb = new StringBuilder(2 * ba.length); for (int i = 0; i < ba.length; i++) { toHex(sb, ba[i]); } return sb.toString(); } public static final boolean isHex(String str) { int l = str.length(); if (l % 2 != 0) return false; for (int i = 0; i < l; i++) { char c = str.charAt(i); if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) { return false; } } return true; } public static final byte[] fromHex(String str) { if (str == null) return null; int l = str.length(); byte[] ba = new byte[l / 2]; int j = 0; for (int i = 0; i < l; i += 2) { byte b = (byte)Short.parseShort(str.substring(i, i + 2), 16); ba[j++] = b; } return ba; } public static final boolean strIsempty(String str) { return str == null || str.length() == 0; } public static final boolean strEquals(String s1, String s2) { return s1 == s2 || (s1 != null && s1.equals(s2)); } public static final String strNotnull(String str) { return str == null? "": str; } public static final String strSubstr(String str, int start, int end) { if (str == null) return null; int l = str.length(); if (l > 0) { while (start < 0) start += l; while (end < 0) end += l; } else { if (start < 0) start = 0; if (end < 0) end = 0; } if (start >= l || start >= end) return ""; if (end >= l + 1) end = l; return str.substring(start, end); } public static final String strSubstr(String str, int start) { if (str == null) return null; return strSubstr(str, start, str.length()); } // ------------------------------------------------------------------------ public static class Base64 { public final static int NO_OPTIONS = 0; public final static int ENCODE = 1; public final static int DECODE = 0; public final static int GZIP = 2; public final static int DONT_BREAK_LINES = 8; private final static int MAX_LINE_LENGTH = 76; private final static byte EQUALS_SIGN = (byte)'='; private final static byte NEW_LINE = (byte)'\n'; private final static String PREFERRED_ENCODING = "UTF-8"; private final static byte[] ALPHABET; private final static byte[] _NATIVE_ALPHABET = { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'}; static { byte[] __bytes; try { __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" .getBytes(PREFERRED_ENCODING); } catch (java.io.UnsupportedEncodingException use) { __bytes = _NATIVE_ALPHABET; } ALPHABET = __bytes; } private final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, -5, -5, -9, -9, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 62, -9, -9, -9, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -9, -9, -9, -1, -9, -9, -9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -9, -9, -9, -9, -9, -9, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -9, -9, -9, -9}; private final static byte WHITE_SPACE_ENC = -5; private final static byte EQUALS_SIGN_ENC = -1; private Base64() { } private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes) { encode3to4(threeBytes, 0, numSigBytes, b4, 0); return b4; } private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset) { int inBuff = (numSigBytes > 0? ((source[srcOffset] << 24) >>> 8): 0) | (numSigBytes > 1? ((source[srcOffset + 1] << 24) >>> 16): 0) | (numSigBytes > 2? ((source[srcOffset + 2] << 24) >>> 24): 0); switch (numSigBytes) { case 3: destination[destOffset] = ALPHABET[(inBuff >>> 18)]; destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; return destination; case 2: destination[destOffset] = ALPHABET[(inBuff >>> 18)]; destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; destination[destOffset + 3] = EQUALS_SIGN; return destination; case 1: destination[destOffset] = ALPHABET[(inBuff >>> 18)]; destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; destination[destOffset + 2] = EQUALS_SIGN; destination[destOffset + 3] = EQUALS_SIGN; return destination; default: return destination; } } public static String encodeObject(java.io.Serializable serializableObject) { return encodeObject(serializableObject, NO_OPTIONS); } public static String encodeObject(java.io.Serializable serializableObject, int options) { java.io.ByteArrayOutputStream baos = null; java.io.OutputStream b64os = null; java.io.ObjectOutputStream oos = null; java.util.zip.GZIPOutputStream gzos = null; int gzip = (options & GZIP); int dontBreakLines = (options & DONT_BREAK_LINES); try { baos = new java.io.ByteArrayOutputStream(); b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines); if (gzip == GZIP) { gzos = new java.util.zip.GZIPOutputStream(b64os); oos = new java.io.ObjectOutputStream(gzos); } else oos = new java.io.ObjectOutputStream(b64os); oos.writeObject(serializableObject); } catch (java.io.IOException e) { e.printStackTrace(); return null; } finally { try { oos.close(); } catch (Exception e) { } try { gzos.close(); } catch (Exception e) { } try { b64os.close(); } catch (Exception e) { } try { baos.close(); } catch (Exception e) { } } try { return new String(baos.toByteArray(), PREFERRED_ENCODING); } catch (java.io.UnsupportedEncodingException uue) { return new String(baos.toByteArray()); } } public static String encodeBytes(byte[] source) { return encodeBytes(source, 0, source.length, NO_OPTIONS); } public static String encodeBytes(byte[] source, int options) { return encodeBytes(source, 0, source.length, options); } public static String encodeBytes(byte[] source, int off, int len) { return encodeBytes(source, off, len, NO_OPTIONS); } public static String encodeBytes(byte[] source, int off, int len, int options) { int dontBreakLines = (options & DONT_BREAK_LINES); int gzip = (options & GZIP); if (gzip == GZIP) { java.io.ByteArrayOutputStream baos = null; java.util.zip.GZIPOutputStream gzos = null; Base64.OutputStream b64os = null; try { baos = new java.io.ByteArrayOutputStream(); b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines); gzos = new java.util.zip.GZIPOutputStream(b64os); gzos.write(source, off, len); gzos.close(); } catch (java.io.IOException e) { e.printStackTrace(); return null; } finally { try { gzos.close(); } catch (Exception e) { } try { b64os.close(); } catch (Exception e) { } try { baos.close(); } catch (Exception e) { } } try { return new String(baos.toByteArray(), PREFERRED_ENCODING); } catch (java.io.UnsupportedEncodingException uue) { return new String(baos.toByteArray()); } } else { boolean breakLines = dontBreakLines == 0; int len43 = len * 4 / 3; byte[] outBuff = new byte[(len43) + ((len % 3) > 0? 4: 0) + (breakLines? (len43 / MAX_LINE_LENGTH): 0)]; int d = 0; int e = 0; int len2 = len - 2; int lineLength = 0; for (; d < len2; d += 3, e += 4) { encode3to4(source, d + off, 3, outBuff, e); lineLength += 4; if (breakLines && lineLength == MAX_LINE_LENGTH) { outBuff[e + 4] = NEW_LINE; e++; lineLength = 0; } } if (d < len) { encode3to4(source, d + off, len - d, outBuff, e); e += 4; } try { return new String(outBuff, 0, e, PREFERRED_ENCODING); } catch (java.io.UnsupportedEncodingException uue) { return new String(outBuff, 0, e); } } } private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) { if (source[srcOffset + 2] == EQUALS_SIGN) { int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); destination[destOffset] = (byte)(outBuff >>> 16); return 1; } else if (source[srcOffset + 3] == EQUALS_SIGN) { int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); destination[destOffset] = (byte)(outBuff >>> 16); destination[destOffset + 1] = (byte)(outBuff >>> 8); return 2; } else { try { int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF)); destination[destOffset] = (byte)(outBuff >> 16); destination[destOffset + 1] = (byte)(outBuff >> 8); destination[destOffset + 2] = (byte)(outBuff); return 3; } catch (Exception e) { System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]])); System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]])); System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]])); System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]])); return -1; } } } public static byte[] decode(byte[] source, int off, int len) { int len34 = len * 3 / 4; byte[] outBuff = new byte[len34]; int outBuffPosn = 0; byte[] b4 = new byte[4]; int b4Posn = 0; int i = 0; byte sbiCrop = 0; byte sbiDecode = 0; for (i = off; i < off + len; i++) { sbiCrop = (byte)(source[i] & 0x7f); sbiDecode = DECODABET[sbiCrop]; if (sbiDecode >= WHITE_SPACE_ENC) { if (sbiDecode >= EQUALS_SIGN_ENC) { b4[b4Posn++] = sbiCrop; if (b4Posn > 3) { outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); b4Posn = 0; if (sbiCrop == EQUALS_SIGN) break; } } } else { throw new IllegalArgumentException("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); } } byte[] out = new byte[outBuffPosn]; System.arraycopy(outBuff, 0, out, 0, outBuffPosn); return out; } public static byte[] decode(String s) { byte[] bytes; try { bytes = s.getBytes(PREFERRED_ENCODING); } catch (java.io.UnsupportedEncodingException uee) { bytes = s.getBytes(); } bytes = decode(bytes, 0, bytes.length); if (bytes != null && bytes.length >= 4) { int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { java.io.ByteArrayInputStream bais = null; java.util.zip.GZIPInputStream gzis = null; java.io.ByteArrayOutputStream baos = null; byte[] buffer = new byte[2048]; int length = 0; try { baos = new java.io.ByteArrayOutputStream(); bais = new java.io.ByteArrayInputStream(bytes); gzis = new java.util.zip.GZIPInputStream(bais); while ((length = gzis.read(buffer)) >= 0) { baos.write(buffer, 0, length); } bytes = baos.toByteArray(); } catch (java.io.IOException e) { } finally { try { baos.close(); } catch (Exception e) { } try { gzis.close(); } catch (Exception e) { } try { bais.close(); } catch (Exception e) { } } } } return bytes; } public static Object decodeToObject(String encodedObject) { byte[] objBytes = decode(encodedObject); java.io.ByteArrayInputStream bais = null; java.io.ObjectInputStream ois = null; Object obj = null; try { bais = new java.io.ByteArrayInputStream(objBytes); ois = new java.io.ObjectInputStream(bais); obj = ois.readObject(); } catch (java.io.IOException e) { e.printStackTrace(); obj = null; } catch (java.lang.ClassNotFoundException e) { e.printStackTrace(); obj = null; } finally { try { bais.close(); } catch (Exception e) { } try { ois.close(); } catch (Exception e) { } } return obj; } public static boolean encodeToFile(byte[] dataToEncode, String filename) { boolean success = false; Base64.OutputStream bos = null; try { bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.ENCODE); bos.write(dataToEncode); success = true; } catch (java.io.IOException e) { success = false; } finally { try { bos.close(); } catch (Exception e) { } } return success; } public static boolean decodeToFile(String dataToDecode, String filename) { boolean success = false; Base64.OutputStream bos = null; try { bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.DECODE); bos.write(dataToDecode.getBytes(PREFERRED_ENCODING)); success = true; } catch (java.io.IOException e) { success = false; } finally { try { bos.close(); } catch (Exception e) { } } return success; } public static byte[] decodeFromFile(String filename) { byte[] decodedData = null; Base64.InputStream bis = null; try { java.io.File file = new java.io.File(filename); byte[] buffer = null; int length = 0; int numBytes = 0; if (file.length() > Integer.MAX_VALUE) { throw new IllegalArgumentException( "File is too big for this convenience method (" + file.length() + " bytes)."); } buffer = new byte[(int)file.length()]; bis = new Base64.InputStream(new java.io.BufferedInputStream( new java.io.FileInputStream(file)), Base64.DECODE); while ((numBytes = bis.read(buffer, length, 4096)) >= 0) length += numBytes; decodedData = new byte[length]; System.arraycopy(buffer, 0, decodedData, 0, length); } catch (java.io.IOException e) { throw new IllegalArgumentException("Error decoding from file " + filename); } finally { try { bis.close(); } catch (Exception e) { } } return decodedData; } public static String encodeFromFile(String filename) { String encodedData = null; Base64.InputStream bis = null; try { java.io.File file = new java.io.File(filename); byte[] buffer = new byte[(int)(file.length() * 1.4)]; int length = 0; int numBytes = 0; bis = new Base64.InputStream(new java.io.BufferedInputStream( new java.io.FileInputStream(file)), Base64.ENCODE); while ((numBytes = bis.read(buffer, length, 4096)) >= 0) length += numBytes; encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING); } catch (java.io.IOException e) { System.err.println("Error encoding from file " + filename); } finally { try { bis.close(); } catch (Exception e) { } } return encodedData; } public static class InputStream extends java.io.FilterInputStream { private boolean encode; private int position; private byte[] buffer; private int bufferLength; private int numSigBytes; private int lineLength; private boolean breakLines; public InputStream(java.io.InputStream in) { this(in, DECODE); } public InputStream(java.io.InputStream in, int options) { super(in); this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; this.encode = (options & ENCODE) == ENCODE; this.bufferLength = encode? 4: 3; this.buffer = new byte[bufferLength]; this.position = -1; this.lineLength = 0; } public int read() throws java.io.IOException { if (position < 0) { if (encode) { byte[] b3 = new byte[3]; int numBinaryBytes = 0; for (int i = 0; i < 3; i++) { try { int b = in.read(); if (b >= 0) { b3[i] = (byte)b; numBinaryBytes++; } } catch (java.io.IOException e) { if (i == 0) throw e; } } if (numBinaryBytes > 0) { encode3to4(b3, 0, numBinaryBytes, buffer, 0); position = 0; numSigBytes = 4; } else { return -1; } } else { byte[] b4 = new byte[4]; int i = 0; for (i = 0; i < 4; i++) { int b = 0; do { b = in.read(); } while (b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC); if (b < 0) break; b4[i] = (byte)b; } if (i == 4) { numSigBytes = decode4to3(b4, 0, buffer, 0); position = 0; } else if (i == 0) { return -1; } else { throw new java.io.IOException("Improperly padded Base64 input."); } } } if (position >= 0) { if ( /* !encode && */position >= numSigBytes) return -1; if (encode && breakLines && lineLength >= MAX_LINE_LENGTH) { lineLength = 0; return '\n'; } else { lineLength++; int b = buffer[position++]; if (position >= bufferLength) position = -1; return b & 0xFF; } } else { throw new java.io.IOException("Error in Base64 code reading stream."); } } public int read(byte[] dest, int off, int len) throws java.io.IOException { int i; int b; for (i = 0; i < len; i++) { b = read(); if (b >= 0) dest[off + i] = (byte)b; else if (i == 0) return -1; else break; } return i; } } public static class OutputStream extends java.io.FilterOutputStream { private boolean encode; private int position; private byte[] buffer; private int bufferLength; private int lineLength; private boolean breakLines; private byte[] b4; private boolean suspendEncoding; public OutputStream(java.io.OutputStream out) { this(out, ENCODE); } public OutputStream(java.io.OutputStream out, int options) { super(out); this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; this.encode = (options & ENCODE) == ENCODE; this.bufferLength = encode? 3: 4; this.buffer = new byte[bufferLength]; this.position = 0; this.lineLength = 0; this.suspendEncoding = false; this.b4 = new byte[4]; } public void write(int theByte) throws java.io.IOException { if (suspendEncoding) { super.out.write(theByte); return; } if (encode) { buffer[position++] = (byte)theByte; if (position >= bufferLength) { out.write(encode3to4(b4, buffer, bufferLength)); lineLength += 4; if (breakLines && lineLength >= MAX_LINE_LENGTH) { out.write(NEW_LINE); lineLength = 0; } position = 0; } } else { if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC) { buffer[position++] = (byte)theByte; if (position >= bufferLength) { int len = Base64.decode4to3(buffer, 0, b4, 0); out.write(b4, 0, len); position = 0; } } else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC) { throw new java.io.IOException("Invalid character in Base64 data."); } } } public void write(byte[] theBytes, int off, int len) throws java.io.IOException { if (suspendEncoding) { super.out.write(theBytes, off, len); return; } for (int i = 0; i < len; i++) { write(theBytes[off + i]); } } public void flushBase64() throws java.io.IOException { if (position > 0) { if (encode) { out.write(encode3to4(b4, buffer, position)); position = 0; } else { throw new java.io.IOException("Base64 input not properly padded."); } } } public void close() throws java.io.IOException { flushBase64(); super.close(); buffer = null; out = null; } public void suspendEncoding() throws java.io.IOException { flushBase64(); this.suspendEncoding = true; } public void resumeEncoding() { this.suspendEncoding = false; } } } // ------------------------------------------------------------------------ public static class DES { private int[] encryptKeys = new int[32]; private int[] decryptKeys = new int[32]; private int[] tempInts = new int[2]; public DES() { } public DES(byte[] key) { if (key.length == 7) { byte[] key8 = new byte[8]; makeSMBKey(key, key8); setKey(key8); } else { setKey(key); } } public static void makeSMBKey(byte[] key7, byte[] key8) { int i; key8[0] = (byte)((key7[0] >> 1) & 0xff); key8[1] = (byte)((((key7[0] & 0x01) << 6) | (((key7[1] & 0xff) >> 2) & 0xff)) & 0xff); key8[2] = (byte)((((key7[1] & 0x03) << 5) | (((key7[2] & 0xff) >> 3) & 0xff)) & 0xff); key8[3] = (byte)((((key7[2] & 0x07) << 4) | (((key7[3] & 0xff) >> 4) & 0xff)) & 0xff); key8[4] = (byte)((((key7[3] & 0x0F) << 3) | (((key7[4] & 0xff) >> 5) & 0xff)) & 0xff); key8[5] = (byte)((((key7[4] & 0x1F) << 2) | (((key7[5] & 0xff) >> 6) & 0xff)) & 0xff); key8[6] = (byte)((((key7[5] & 0x3F) << 1) | (((key7[6] & 0xff) >> 7) & 0xff)) & 0xff); key8[7] = (byte)(key7[6] & 0x7F); for (i = 0; i < 8; i++) { key8[i] = (byte)(key8[i] << 1); } } public void setKey(byte[] key) { deskey(key, true, encryptKeys); deskey(key, false, decryptKeys); } private void deskey(byte[] keyBlock, boolean encrypting, int[] KnL) { int i, j, l, m, n; int[] pc1m = new int[56]; int[] pcr = new int[56]; int[] kn = new int[32]; for (j = 0; j < 56; ++j) { l = pc1[j]; m = l & 07; pc1m[j] = ((keyBlock[l >>> 3] & bytebit[m]) != 0)? 1: 0; } for (i = 0; i < 16; ++i) { if (encrypting) m = i << 1; else m = (15 - i) << 1; n = m + 1; kn[m] = kn[n] = 0; for (j = 0; j < 28; ++j) { l = j + totrot[i]; if (l < 28) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (j = 28; j < 56; ++j) { l = j + totrot[i]; if (l < 56) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (j = 0; j < 24; ++j) { if (pcr[pc2[j]] != 0) kn[m] |= bigbyte[j]; if (pcr[pc2[j + 24]] != 0) kn[n] |= bigbyte[j]; } } cookey(kn, KnL); } private void cookey(int[] raw, int KnL[]) { int raw0, raw1; int rawi, KnLi; int i; for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) { raw0 = raw[rawi++]; raw1 = raw[rawi++]; KnL[KnLi] = (raw0 & 0x00fc0000) << 6; KnL[KnLi] |= (raw0 & 0x00000fc0) << 10; KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10; KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6; ++KnLi; KnL[KnLi] = (raw0 & 0x0003f000) << 12; KnL[KnLi] |= (raw0 & 0x0000003f) << 16; KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4; KnL[KnLi] |= (raw1 & 0x0000003f); ++KnLi; } } private void encrypt(byte[] clearText, int clearOff, byte[] cipherText, int cipherOff) { squashBytesToInts(clearText, clearOff, tempInts, 0, 2); des(tempInts, tempInts, encryptKeys); spreadIntsToBytes(tempInts, 0, cipherText, cipherOff, 2); } private void decrypt(byte[] cipherText, int cipherOff, byte[] clearText, int clearOff) { squashBytesToInts(cipherText, cipherOff, tempInts, 0, 2); des(tempInts, tempInts, decryptKeys); spreadIntsToBytes(tempInts, 0, clearText, clearOff, 2); } private void des(int[] inInts, int[] outInts, int[] keys) { int fval, work, right, leftt; int round; int keysi = 0; leftt = inInts[0]; right = inInts[1]; work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f; right ^= work; leftt ^= (work << 4); work = ((leftt >>> 16) ^ right) & 0x0000ffff; right ^= work; leftt ^= (work << 16); work = ((right >>> 2) ^ leftt) & 0x33333333; leftt ^= work; right ^= (work << 2); work = ((right >>> 8) ^ leftt) & 0x00ff00ff; leftt ^= work; right ^= (work << 8); right = (right << 1) | ((right >>> 31) & 1); work = (leftt ^ right) & 0xaaaaaaaa; leftt ^= work; right ^= work; leftt = (leftt << 1) | ((leftt >>> 31) & 1); for (round = 0; round < 8; ++round) { work = (right << 28) | (right >>> 4); work ^= keys[keysi++]; fval = SP7[work & 0x0000003f]; fval |= SP5[(work >>> 8) & 0x0000003f]; fval |= SP3[(work >>> 16) & 0x0000003f]; fval |= SP1[(work >>> 24) & 0x0000003f]; work = right ^ keys[keysi++]; fval |= SP8[work & 0x0000003f]; fval |= SP6[(work >>> 8) & 0x0000003f]; fval |= SP4[(work >>> 16) & 0x0000003f]; fval |= SP2[(work >>> 24) & 0x0000003f]; leftt ^= fval; work = (leftt << 28) | (leftt >>> 4); work ^= keys[keysi++]; fval = SP7[work & 0x0000003f]; fval |= SP5[(work >>> 8) & 0x0000003f]; fval |= SP3[(work >>> 16) & 0x0000003f]; fval |= SP1[(work >>> 24) & 0x0000003f]; work = leftt ^ keys[keysi++]; fval |= SP8[work & 0x0000003f]; fval |= SP6[(work >>> 8) & 0x0000003f]; fval |= SP4[(work >>> 16) & 0x0000003f]; fval |= SP2[(work >>> 24) & 0x0000003f]; right ^= fval; } right = (right << 31) | (right >>> 1); work = (leftt ^ right) & 0xaaaaaaaa; leftt ^= work; right ^= work; leftt = (leftt << 31) | (leftt >>> 1); work = ((leftt >>> 8) ^ right) & 0x00ff00ff; right ^= work; leftt ^= (work << 8); work = ((leftt >>> 2) ^ right) & 0x33333333; right ^= work; leftt ^= (work << 2); work = ((right >>> 16) ^ leftt) & 0x0000ffff; leftt ^= work; right ^= (work << 16); work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f; leftt ^= work; right ^= (work << 4); outInts[0] = right; outInts[1] = leftt; } public void encrypt(byte[] clearText, byte[] cipherText) { encrypt(clearText, 0, cipherText, 0); } public void decrypt(byte[] cipherText, byte[] clearText) { decrypt(cipherText, 0, clearText, 0); } public byte[] encrypt(byte[] clearText) { int length = clearText.length; if (length % 8 != 0) { System.out.println("Array must be a multiple of 8"); return null; } byte[] cipherText = new byte[length]; int count = length / 8; for (int i = 0; i < count; i++) encrypt(clearText, i * 8, cipherText, i * 8); return cipherText; } public byte[] decrypt(byte[] cipherText) { int length = cipherText.length; if (length % 8 != 0) { System.out.println("Array must be a multiple of 8"); return null; } byte[] clearText = new byte[length]; int count = length / 8; for (int i = 0; i < count; i++) encrypt(cipherText, i * 8, clearText, i * 8); return clearText; } private static byte[] bytebit = { (byte)0x80, (byte)0x40, (byte)0x20, (byte)0x10, (byte)0x08, (byte)0x04, (byte)0x02, (byte)0x01}; private static int[] bigbyte = { 0x800000, 0x400000, 0x200000, 0x100000, 0x080000, 0x040000, 0x020000, 0x010000, 0x008000, 0x004000, 0x002000, 0x001000, 0x000800, 0x000400, 0x000200, 0x000100, 0x000080, 0x000040, 0x000020, 0x000010, 0x000008, 0x000004, 0x000002, 0x000001}; private static byte[] pc1 = { (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte)8, (byte)0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17, (byte)9, (byte)1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26, (byte)18, (byte)10, (byte)2, (byte)59, (byte)51, (byte)43, (byte)35, (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14, (byte)6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21, (byte)13, (byte)5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28, (byte)20, (byte)12, (byte)4, (byte)27, (byte)19, (byte)11, (byte)3}; private static int[] totrot = {1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28}; private static byte[] pc2 = { (byte)13, (byte)16, (byte)10, (byte)23, (byte)0, (byte)4, (byte)2, (byte)27, (byte)14, (byte)5, (byte)20, (byte)9, (byte)22, (byte)18, (byte)11, (byte)3, (byte)25, (byte)7, (byte)15, (byte)6, (byte)26, (byte)19, (byte)12, (byte)1, (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54, (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47, (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52, (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,}; private static int[] SP1 = { 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004}; private static int[] SP2 = { 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000}; private static int[] SP3 = { 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200}; private static int[] SP4 = { 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080}; private static int[] SP5 = { 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100}; private static int[] SP6 = { 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010}; private static int[] SP7 = { 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002}; private static int[] SP8 = { 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000}; public static void squashBytesToInts(byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen) { for (int i = 0; i < intLen; ++i) outInts[outOff + i] = ((inBytes[inOff + i * 4] & 0xff) << 24) | ((inBytes[inOff + i * 4 + 1] & 0xff) << 16) | ((inBytes[inOff + i * 4 + 2] & 0xff) << 8) | (inBytes[inOff + i * 4 + 3] & 0xff); } public static void spreadIntsToBytes(int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen) { for (int i = 0; i < intLen; ++i) { outBytes[outOff + i * 4] = (byte)(inInts[inOff + i] >>> 24); outBytes[outOff + i * 4 + 1] = (byte)(inInts[inOff + i] >>> 16); outBytes[outOff + i * 4 + 2] = (byte)(inInts[inOff + i] >>> 8); outBytes[outOff + i * 4 + 3] = (byte)inInts[inOff + i]; } } } // ------------------------------------------------------------------------ public static class MD4 extends MessageDigest implements Cloneable { private static final int BLOCK_LENGTH = 64; private int[] context = new int[4]; private long count; private byte[] buffer = new byte[BLOCK_LENGTH]; private int[] X = new int[16]; public MD4() { super("MD4"); engineReset(); } private MD4(MD4 md) { this(); context = (int[])md.context.clone(); buffer = (byte[])md.buffer.clone(); count = md.count; } public Object clone() { return new MD4(this); } public void engineReset() { context[0] = 0x67452301; context[1] = 0xEFCDAB89; context[2] = 0x98BADCFE; context[3] = 0x10325476; count = 0L; for (int i = 0; i < BLOCK_LENGTH; i++) buffer[i] = 0; } public void engineUpdate(byte b) { int i = (int)(count % BLOCK_LENGTH); count++; buffer[i] = b; if (i == BLOCK_LENGTH - 1) transform(buffer, 0); } public void engineUpdate(byte[] input, int offset, int len) { if (offset < 0 || len < 0 || (long)offset + len > input.length) throw new ArrayIndexOutOfBoundsException(); int bufferNdx = (int)(count % BLOCK_LENGTH); count += len; int partLen = BLOCK_LENGTH - bufferNdx; int i = 0; if (len >= partLen) { System.arraycopy(input, offset, buffer, bufferNdx, partLen); transform(buffer, 0); for (i = partLen; i + BLOCK_LENGTH - 1 < len; i += BLOCK_LENGTH) transform(input, offset + i); bufferNdx = 0; } if (i < len) System.arraycopy(input, offset + i, buffer, bufferNdx, len - i); } public byte[] engineDigest() { int bufferNdx = (int)(count % BLOCK_LENGTH); int padLen = (bufferNdx < 56)? (56 - bufferNdx): (120 - bufferNdx); byte[] tail = new byte[padLen + 8]; tail[0] = (byte)0x80; for (int i = 0; i < 8; i++) tail[padLen + i] = (byte)((count * 8) >>> (8 * i)); engineUpdate(tail, 0, tail.length); byte[] result = new byte[16]; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) result[i * 4 + j] = (byte)(context[i] >>> (8 * j)); engineReset(); return result; } private void transform(byte[] block, int offset) { for (int i = 0; i < 16; i++) X[i] = (block[offset++] & 0xFF) | (block[offset++] & 0xFF) << 8 | (block[offset++] & 0xFF) << 16 | (block[offset++] & 0xFF) << 24; int A = context[0]; int B = context[1]; int C = context[2]; int D = context[3]; A = FF(A, B, C, D, X[0], 3); D = FF(D, A, B, C, X[1], 7); C = FF(C, D, A, B, X[2], 11); B = FF(B, C, D, A, X[3], 19); A = FF(A, B, C, D, X[4], 3); D = FF(D, A, B, C, X[5], 7); C = FF(C, D, A, B, X[6], 11); B = FF(B, C, D, A, X[7], 19); A = FF(A, B, C, D, X[8], 3); D = FF(D, A, B, C, X[9], 7); C = FF(C, D, A, B, X[10], 11); B = FF(B, C, D, A, X[11], 19); A = FF(A, B, C, D, X[12], 3); D = FF(D, A, B, C, X[13], 7); C = FF(C, D, A, B, X[14], 11); B = FF(B, C, D, A, X[15], 19); A = GG(A, B, C, D, X[0], 3); D = GG(D, A, B, C, X[4], 5); C = GG(C, D, A, B, X[8], 9); B = GG(B, C, D, A, X[12], 13); A = GG(A, B, C, D, X[1], 3); D = GG(D, A, B, C, X[5], 5); C = GG(C, D, A, B, X[9], 9); B = GG(B, C, D, A, X[13], 13); A = GG(A, B, C, D, X[2], 3); D = GG(D, A, B, C, X[6], 5); C = GG(C, D, A, B, X[10], 9); B = GG(B, C, D, A, X[14], 13); A = GG(A, B, C, D, X[3], 3); D = GG(D, A, B, C, X[7], 5); C = GG(C, D, A, B, X[11], 9); B = GG(B, C, D, A, X[15], 13); A = HH(A, B, C, D, X[0], 3); D = HH(D, A, B, C, X[8], 9); C = HH(C, D, A, B, X[4], 11); B = HH(B, C, D, A, X[12], 15); A = HH(A, B, C, D, X[2], 3); D = HH(D, A, B, C, X[10], 9); C = HH(C, D, A, B, X[6], 11); B = HH(B, C, D, A, X[14], 15); A = HH(A, B, C, D, X[1], 3); D = HH(D, A, B, C, X[9], 9); C = HH(C, D, A, B, X[5], 11); B = HH(B, C, D, A, X[13], 15); A = HH(A, B, C, D, X[3], 3); D = HH(D, A, B, C, X[11], 9); C = HH(C, D, A, B, X[7], 11); B = HH(B, C, D, A, X[15], 15); context[0] += A; context[1] += B; context[2] += C; context[3] += D; } private int FF(int a, int b, int c, int d, int x, int s) { int t = a + ((b & c) | (~b & d)) + x; return t << s | t >>> (32 - s); } private int GG(int a, int b, int c, int d, int x, int s) { int t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999; return t << s | t >>> (32 - s); } private int HH(int a, int b, int c, int d, int x, int s) { int t = a + (b ^ c ^ d) + x + 0x6ED9EBA1; return t << s | t >>> (32 - s); } } // ------------------------------------------------------------------------ public static class jcrypt { private jcrypt() { } private static final int ITERATIONS = 16; private static final int con_salt[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,}; private static final boolean shifts2[] = { false, false, true, true, true, true, true, true, false, true, true, true, true, true, true, false}; private static final int skb[][] = { { 0x00000000, 0x00000010, 0x20000000, 0x20000010, 0x00010000, 0x00010010, 0x20010000, 0x20010010, 0x00000800, 0x00000810, 0x20000800, 0x20000810, 0x00010800, 0x00010810, 0x20010800, 0x20010810, 0x00000020, 0x00000030, 0x20000020, 0x20000030, 0x00010020, 0x00010030, 0x20010020, 0x20010030, 0x00000820, 0x00000830, 0x20000820, 0x20000830, 0x00010820, 0x00010830, 0x20010820, 0x20010830, 0x00080000, 0x00080010, 0x20080000, 0x20080010, 0x00090000, 0x00090010, 0x20090000, 0x20090010, 0x00080800, 0x00080810, 0x20080800, 0x20080810, 0x00090800, 0x00090810, 0x20090800, 0x20090810, 0x00080020, 0x00080030, 0x20080020, 0x20080030, 0x00090020, 0x00090030, 0x20090020, 0x20090030, 0x00080820, 0x00080830, 0x20080820, 0x20080830, 0x00090820, 0x00090830, 0x20090820, 0x20090830,}, { 0x00000000, 0x02000000, 0x00002000, 0x02002000, 0x00200000, 0x02200000, 0x00202000, 0x02202000, 0x00000004, 0x02000004, 0x00002004, 0x02002004, 0x00200004, 0x02200004, 0x00202004, 0x02202004, 0x00000400, 0x02000400, 0x00002400, 0x02002400, 0x00200400, 0x02200400, 0x00202400, 0x02202400, 0x00000404, 0x02000404, 0x00002404, 0x02002404, 0x00200404, 0x02200404, 0x00202404, 0x02202404, 0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000, 0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004, 0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400, 0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404,}, { 0x00000000, 0x00000001, 0x00040000, 0x00040001, 0x01000000, 0x01000001, 0x01040000, 0x01040001, 0x00000002, 0x00000003, 0x00040002, 0x00040003, 0x01000002, 0x01000003, 0x01040002, 0x01040003, 0x00000200, 0x00000201, 0x00040200, 0x00040201, 0x01000200, 0x01000201, 0x01040200, 0x01040201, 0x00000202, 0x00000203, 0x00040202, 0x00040203, 0x01000202, 0x01000203, 0x01040202, 0x01040203, 0x08000000, 0x08000001, 0x08040000, 0x08040001, 0x09000000, 0x09000001, 0x09040000, 0x09040001, 0x08000002, 0x08000003, 0x08040002, 0x08040003, 0x09000002, 0x09000003, 0x09040002, 0x09040003, 0x08000200, 0x08000201, 0x08040200, 0x08040201, 0x09000200, 0x09000201, 0x09040200, 0x09040201, 0x08000202, 0x08000203, 0x08040202, 0x08040203, 0x09000202, 0x09000203, 0x09040202, 0x09040203,}, { 0x00000000, 0x00100000, 0x00000100, 0x00100100, 0x00000008, 0x00100008, 0x00000108, 0x00100108, 0x00001000, 0x00101000, 0x00001100, 0x00101100, 0x00001008, 0x00101008, 0x00001108, 0x00101108, 0x04000000, 0x04100000, 0x04000100, 0x04100100, 0x04000008, 0x04100008, 0x04000108, 0x04100108, 0x04001000, 0x04101000, 0x04001100, 0x04101100, 0x04001008, 0x04101008, 0x04001108, 0x04101108, 0x00020000, 0x00120000, 0x00020100, 0x00120100, 0x00020008, 0x00120008, 0x00020108, 0x00120108, 0x00021000, 0x00121000, 0x00021100, 0x00121100, 0x00021008, 0x00121008, 0x00021108, 0x00121108, 0x04020000, 0x04120000, 0x04020100, 0x04120100, 0x04020008, 0x04120008, 0x04020108, 0x04120108, 0x04021000, 0x04121000, 0x04021100, 0x04121100, 0x04021008, 0x04121008, 0x04021108, 0x04121108,}, { 0x00000000, 0x10000000, 0x00010000, 0x10010000, 0x00000004, 0x10000004, 0x00010004, 0x10010004, 0x20000000, 0x30000000, 0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x00100000, 0x10100000, 0x00110000, 0x10110000, 0x00100004, 0x10100004, 0x00110004, 0x10110004, 0x20100000, 0x30100000, 0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 0x00001000, 0x10001000, 0x00011000, 0x10011000, 0x00001004, 0x10001004, 0x00011004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000, 0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x00101000, 0x10101000, 0x00111000, 0x10111000, 0x00101004, 0x10101004, 0x00111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000, 0x20101004, 0x30101004, 0x20111004, 0x30111004,}, { 0x00000000, 0x08000000, 0x00000008, 0x08000008, 0x00000400, 0x08000400, 0x00000408, 0x08000408, 0x00020000, 0x08020000, 0x00020008, 0x08020008, 0x00020400, 0x08020400, 0x00020408, 0x08020408, 0x00000001, 0x08000001, 0x00000009, 0x08000009, 0x00000401, 0x08000401, 0x00000409, 0x08000409, 0x00020001, 0x08020001, 0x00020009, 0x08020009, 0x00020401, 0x08020401, 0x00020409, 0x08020409, 0x02000000, 0x0A000000, 0x02000008, 0x0A000008, 0x02000400, 0x0A000400, 0x02000408, 0x0A000408, 0x02020000, 0x0A020000, 0x02020008, 0x0A020008, 0x02020400, 0x0A020400, 0x02020408, 0x0A020408, 0x02000001, 0x0A000001, 0x02000009, 0x0A000009, 0x02000401, 0x0A000401, 0x02000409, 0x0A000409, 0x02020001, 0x0A020001, 0x02020009, 0x0A020009, 0x02020401, 0x0A020401, 0x02020409, 0x0A020409,}, { 0x00000000, 0x00000100, 0x00080000, 0x00080100, 0x01000000, 0x01000100, 0x01080000, 0x01080100, 0x00000010, 0x00000110, 0x00080010, 0x00080110, 0x01000010, 0x01000110, 0x01080010, 0x01080110, 0x00200000, 0x00200100, 0x00280000, 0x00280100, 0x01200000, 0x01200100, 0x01280000, 0x01280100, 0x00200010, 0x00200110, 0x00280010, 0x00280110, 0x01200010, 0x01200110, 0x01280010, 0x01280110, 0x00000200, 0x00000300, 0x00080200, 0x00080300, 0x01000200, 0x01000300, 0x01080200, 0x01080300, 0x00000210, 0x00000310, 0x00080210, 0x00080310, 0x01000210, 0x01000310, 0x01080210, 0x01080310, 0x00200200, 0x00200300, 0x00280200, 0x00280300, 0x01200200, 0x01200300, 0x01280200, 0x01280300, 0x00200210, 0x00200310, 0x00280210, 0x00280310, 0x01200210, 0x01200310, 0x01280210, 0x01280310,}, { 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000002, 0x04000002, 0x00040002, 0x04040002, 0x00002000, 0x04002000, 0x00042000, 0x04042000, 0x00002002, 0x04002002, 0x00042002, 0x04042002, 0x00000020, 0x04000020, 0x00040020, 0x04040020, 0x00000022, 0x04000022, 0x00040022, 0x04040022, 0x00002020, 0x04002020, 0x00042020, 0x04042020, 0x00002022, 0x04002022, 0x00042022, 0x04042022, 0x00000800, 0x04000800, 0x00040800, 0x04040800, 0x00000802, 0x04000802, 0x00040802, 0x04040802, 0x00002800, 0x04002800, 0x00042800, 0x04042800, 0x00002802, 0x04002802, 0x00042802, 0x04042802, 0x00000820, 0x04000820, 0x00040820, 0x04040820, 0x00000822, 0x04000822, 0x00040822, 0x04040822, 0x00002820, 0x04002820, 0x00042820, 0x04042820, 0x00002822, 0x04002822, 0x00042822, 0x04042822,},}; private static final int SPtrans[][] = { { 0x00820200, 0x00020000, 0x80800000, 0x80820200, 0x00800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200, 0x00820200, 0x00820000, 0x80000200, 0x80800200, 0x00800000, 0x00000000, 0x80020000, 0x00020000, 0x80000000, 0x00800200, 0x00020200, 0x80820200, 0x00820000, 0x80000200, 0x00800200, 0x80000000, 0x00000200, 0x00020200, 0x80820000, 0x00000200, 0x80800200, 0x80820000, 0x00000000, 0x00000000, 0x80820200, 0x00800200, 0x80020000, 0x00820200, 0x00020000, 0x80000200, 0x00800200, 0x80820000, 0x00000200, 0x00020200, 0x80800000, 0x80020200, 0x80000000, 0x80800000, 0x00820000, 0x80820200, 0x00020200, 0x00820000, 0x80800200, 0x00800000, 0x80000200, 0x80020000, 0x00000000, 0x00020000, 0x00800000, 0x80800200, 0x00820200, 0x80000000, 0x80820000, 0x00000200, 0x80020200,}, { 0x10042004, 0x00000000, 0x00042000, 0x10040000, 0x10000004, 0x00002004, 0x10002000, 0x00042000, 0x00002000, 0x10040004, 0x00000004, 0x10002000, 0x00040004, 0x10042000, 0x10040000, 0x00000004, 0x00040000, 0x10002004, 0x10040004, 0x00002000, 0x00042004, 0x10000000, 0x00000000, 0x00040004, 0x10002004, 0x00042004, 0x10042000, 0x10000004, 0x10000000, 0x00040000, 0x00002004, 0x10042004, 0x00040004, 0x10042000, 0x10002000, 0x00042004, 0x10042004, 0x00040004, 0x10000004, 0x00000000, 0x10000000, 0x00002004, 0x00040000, 0x10040004, 0x00002000, 0x10000000, 0x00042004, 0x10002004, 0x10042000, 0x00002000, 0x00000000, 0x10000004, 0x00000004, 0x10042004, 0x00042000, 0x10040000, 0x10040004, 0x00040000, 0x00002004, 0x10002000, 0x10002004, 0x00000004, 0x10040000, 0x00042000,}, { 0x41000000, 0x01010040, 0x00000040, 0x41000040, 0x40010000, 0x01000000, 0x41000040, 0x00010040, 0x01000040, 0x00010000, 0x01010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0x00000000, 0x40010000, 0x01010040, 0x00000040, 0x40000040, 0x41010040, 0x00010000, 0x41000000, 0x41010000, 0x01000040, 0x40010040, 0x01010000, 0x00010040, 0x00000000, 0x01000000, 0x40010040, 0x01010040, 0x00000040, 0x40000000, 0x00010000, 0x40000040, 0x40010000, 0x01010000, 0x41000040, 0x00000000, 0x01010040, 0x00010040, 0x41010000, 0x40010000, 0x01000000, 0x41010040, 0x40000000, 0x40010040, 0x41000000, 0x01000000, 0x41010040, 0x00010000, 0x01000040, 0x41000040, 0x00010040, 0x01000040, 0x00000000, 0x41010000, 0x40000040, 0x41000000, 0x40010040, 0x00000040, 0x01010000,}, { 0x00100402, 0x04000400, 0x00000002, 0x04100402, 0x00000000, 0x04100000, 0x04000402, 0x00100002, 0x04100400, 0x04000002, 0x04000000, 0x00000402, 0x04000002, 0x00100402, 0x00100000, 0x04000000, 0x04100002, 0x00100400, 0x00000400, 0x00000002, 0x00100400, 0x04000402, 0x04100000, 0x00000400, 0x00000402, 0x00000000, 0x00100002, 0x04100400, 0x04000400, 0x04100002, 0x04100402, 0x00100000, 0x04100002, 0x00000402, 0x00100000, 0x04000002, 0x00100400, 0x04000400, 0x00000002, 0x04100000, 0x04000402, 0x00000000, 0x00000400, 0x00100002, 0x00000000, 0x04100002, 0x04100400, 0x00000400, 0x04000000, 0x04100402, 0x00100402, 0x00100000, 0x04100402, 0x00000002, 0x04000400, 0x00100402, 0x00100002, 0x00100400, 0x04100000, 0x04000402, 0x00000402, 0x04000000, 0x04000002, 0x04100400,}, { 0x02000000, 0x00004000, 0x00000100, 0x02004108, 0x02004008, 0x02000100, 0x00004108, 0x02004000, 0x00004000, 0x00000008, 0x02000008, 0x00004100, 0x02000108, 0x02004008, 0x02004100, 0x00000000, 0x00004100, 0x02000000, 0x00004008, 0x00000108, 0x02000100, 0x00004108, 0x00000000, 0x02000008, 0x00000008, 0x02000108, 0x02004108, 0x00004008, 0x02004000, 0x00000100, 0x00000108, 0x02004100, 0x02004100, 0x02000108, 0x00004008, 0x02004000, 0x00004000, 0x00000008, 0x02000008, 0x02000100, 0x02000000, 0x00004100, 0x02004108, 0x00000000, 0x00004108, 0x02000000, 0x00000100, 0x00004008, 0x02000108, 0x00000100, 0x00000000, 0x02004108, 0x02004008, 0x02004100, 0x00000108, 0x00004000, 0x00004100, 0x02004008, 0x02000100, 0x00000108, 0x00000008, 0x00004108, 0x02004000, 0x02000008,}, { 0x20000010, 0x00080010, 0x00000000, 0x20080800, 0x00080010, 0x00000800, 0x20000810, 0x00080000, 0x00000810, 0x20080810, 0x00080800, 0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x00080810, 0x00080000, 0x20000810, 0x20080010, 0x00000000, 0x00000800, 0x00000010, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 0x00000810, 0x00000010, 0x00080800, 0x00080810, 0x20000800, 0x00000810, 0x20000000, 0x20000800, 0x00080810, 0x20080800, 0x00080010, 0x00000000, 0x20000800, 0x20000000, 0x00000800, 0x20080010, 0x00080000, 0x00080010, 0x20080810, 0x00080800, 0x00000010, 0x20080810, 0x00080800, 0x00080000, 0x20000810, 0x20000010, 0x20080000, 0x00080810, 0x00000000, 0x00000800, 0x20000010, 0x20000810, 0x20080800, 0x20080000, 0x00000810, 0x00000010, 0x20080010,}, { 0x00001000, 0x00000080, 0x00400080, 0x00400001, 0x00401081, 0x00001001, 0x00001080, 0x00000000, 0x00400000, 0x00400081, 0x00000081, 0x00401000, 0x00000001, 0x00401080, 0x00401000, 0x00000081, 0x00400081, 0x00001000, 0x00001001, 0x00401081, 0x00000000, 0x00400080, 0x00400001, 0x00001080, 0x00401001, 0x00001081, 0x00401080, 0x00000001, 0x00001081, 0x00401001, 0x00000080, 0x00400000, 0x00001081, 0x00401000, 0x00401001, 0x00000081, 0x00001000, 0x00000080, 0x00400000, 0x00401001, 0x00400081, 0x00001081, 0x00001080, 0x00000000, 0x00000080, 0x00400001, 0x00000001, 0x00400080, 0x00000000, 0x00400081, 0x00400080, 0x00001080, 0x00000081, 0x00001000, 0x00401081, 0x00400000, 0x00401080, 0x00000001, 0x00001001, 0x00401081, 0x00400001, 0x00401080, 0x00401000, 0x00001001,}, { 0x08200020, 0x08208000, 0x00008020, 0x00000000, 0x08008000, 0x00200020, 0x08200000, 0x08208020, 0x00000020, 0x08000000, 0x00208000, 0x00008020, 0x00208020, 0x08008020, 0x08000020, 0x08200000, 0x00008000, 0x00208020, 0x00200020, 0x08008000, 0x08208020, 0x08000020, 0x00000000, 0x00208000, 0x08000000, 0x00200000, 0x08008020, 0x08200020, 0x00200000, 0x00008000, 0x08208000, 0x00000020, 0x00200000, 0x00008000, 0x08000020, 0x08208020, 0x00008020, 0x08000000, 0x00000000, 0x00208000, 0x08200020, 0x08008020, 0x08008000, 0x00200020, 0x08208000, 0x00000020, 0x00200020, 0x08008000, 0x08208020, 0x00200000, 0x08200000, 0x08000020, 0x00208000, 0x00008020, 0x08008020, 0x08200000, 0x00000020, 0x08208000, 0x00208020, 0x00000000, 0x08000000, 0x08200020, 0x00008000, 0x00208020}}; private static final int cov_2char[] = { 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A}; private static final int byteToUnsigned(byte b) { int value = (int)b; return (value >= 0? value: value + 256); } private static int fourBytesToInt(byte b[], int offset) { int value; value = byteToUnsigned(b[offset++]); value |= (byteToUnsigned(b[offset++]) << 8); value |= (byteToUnsigned(b[offset++]) << 16); value |= (byteToUnsigned(b[offset++]) << 24); return (value); } private static final void intToFourBytes(int iValue, byte b[], int offset) { b[offset++] = (byte)((iValue) & 0xff); b[offset++] = (byte)((iValue >>> 8) & 0xff); b[offset++] = (byte)((iValue >>> 16) & 0xff); b[offset++] = (byte)((iValue >>> 24) & 0xff); } private static final void PERM_OP(int a, int b, int n, int m, int results[]) { int t; t = ((a >>> n) ^ b) & m; a ^= t << n; b ^= t; results[0] = a; results[1] = b; } private static final int HPERM_OP(int a, int n, int m) { int t; t = ((a << (16 - n)) ^ a) & m; a = a ^ t ^ (t >>> (16 - n)); return (a); } private static int[] des_set_key(byte key[]) { int schedule[] = new int[ITERATIONS * 2]; int c = fourBytesToInt(key, 0); int d = fourBytesToInt(key, 4); int results[] = new int[2]; PERM_OP(d, c, 4, 0x0f0f0f0f, results); d = results[0]; c = results[1]; c = HPERM_OP(c, -2, 0xcccc0000); d = HPERM_OP(d, -2, 0xcccc0000); PERM_OP(d, c, 1, 0x55555555, results); d = results[0]; c = results[1]; PERM_OP(c, d, 8, 0x00ff00ff, results); c = results[0]; d = results[1]; PERM_OP(d, c, 1, 0x55555555, results); d = results[0]; c = results[1]; d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) | ((d & 0x00ff0000) >>> 16) | ((c & 0xf0000000) >>> 4)); c &= 0x0fffffff; int s, t; int j = 0; for (int i = 0; i < ITERATIONS; i++) { if (shifts2[i]) { c = (c >>> 2) | (c << 26); d = (d >>> 2) | (d << 26); } else { c = (c >>> 1) | (c << 27); d = (d >>> 1) | (d << 27); } c &= 0x0fffffff; d &= 0x0fffffff; s = skb[0][(c) & 0x3f] | skb[1][((c >>> 6) & 0x03) | ((c >>> 7) & 0x3c)] | skb[2][((c >>> 13) & 0x0f) | ((c >>> 14) & 0x30)] | skb[3][((c >>> 20) & 0x01) | ((c >>> 21) & 0x06) | ((c >>> 22) & 0x38)]; t = skb[4][(d) & 0x3f] | skb[5][((d >>> 7) & 0x03) | ((d >>> 8) & 0x3c)] | skb[6][(d >>> 15) & 0x3f] | skb[7][((d >>> 21) & 0x0f) | ((d >>> 22) & 0x30)]; schedule[j++] = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff; s = ((s >>> 16) | (t & 0xffff0000)); s = (s << 4) | (s >>> 28); schedule[j++] = s & 0xffffffff; } return (schedule); } private static final int D_ENCRYPT(int L, int R, int S, int E0, int E1, int s[]) { int t, u, v; v = R ^ (R >>> 16); u = v & E0; v = v & E1; u = (u ^ (u << 16)) ^ R ^ s[S]; t = (v ^ (v << 16)) ^ R ^ s[S + 1]; t = (t >>> 4) | (t << 28); L ^= SPtrans[1][(t) & 0x3f] | SPtrans[3][(t >>> 8) & 0x3f] | SPtrans[5][(t >>> 16) & 0x3f] | SPtrans[7][(t >>> 24) & 0x3f] | SPtrans[0][(u) & 0x3f] | SPtrans[2][(u >>> 8) & 0x3f] | SPtrans[4][(u >>> 16) & 0x3f] | SPtrans[6][(u >>> 24) & 0x3f]; return (L); } private static final int[] body(int schedule[], int Eswap0, int Eswap1) { int left = 0; int right = 0; int t = 0; for (int j = 0; j < 25; j++) { for (int i = 0; i < ITERATIONS * 2; i += 4) { left = D_ENCRYPT(left, right, i, Eswap0, Eswap1, schedule); right = D_ENCRYPT(right, left, i + 2, Eswap0, Eswap1, schedule); } t = left; left = right; right = t; } t = right; right = (left >>> 1) | (left << 31); left = (t >>> 1) | (t << 31); left &= 0xffffffff; right &= 0xffffffff; int results[] = new int[2]; PERM_OP(right, left, 1, 0x55555555, results); right = results[0]; left = results[1]; PERM_OP(left, right, 8, 0x00ff00ff, results); left = results[0]; right = results[1]; PERM_OP(right, left, 2, 0x33333333, results); right = results[0]; left = results[1]; PERM_OP(left, right, 16, 0x0000ffff, results); left = results[0]; right = results[1]; PERM_OP(right, left, 4, 0x0f0f0f0f, results); right = results[0]; left = results[1]; int out[] = new int[2]; out[0] = left; out[1] = right; return (out); } public static final String crypt(String salt, String original) { while (salt.length() < 2) salt += "A"; StringBuffer buffer = new StringBuffer(" "); char charZero = salt.charAt(0); char charOne = salt.charAt(1); buffer.setCharAt(0, charZero); buffer.setCharAt(1, charOne); int Eswap0 = con_salt[(int)charZero]; int Eswap1 = con_salt[(int)charOne] << 4; byte key[] = new byte[8]; for (int i = 0; i < key.length; i++) key[i] = (byte)0; for (int i = 0; i < key.length && i < original.length(); i++) { int iChar = (int)original.charAt(i); key[i] = (byte)(iChar << 1); } int schedule[] = des_set_key(key); int out[] = body(schedule, Eswap0, Eswap1); byte b[] = new byte[9]; intToFourBytes(out[0], b, 0); intToFourBytes(out[1], b, 4); b[8] = 0; for (int i = 2, y = 0, u = 0x80; i < 13; i++) { for (int j = 0, c = 0; j < 6; j++) { c <<= 1; if (((int)b[y] & u) != 0) c |= 1; u >>>= 1; if (u == 0) { y++; u = 0x80; } buffer.setCharAt(i, (char)cov_2char[c]); } } return (buffer.toString()); } public static void main(String args[]) { if (args.length >= 2) { System.out.println("[" + args[0] + "] [" + args[1] + "] => [" + jcrypt.crypt(args[0], args[1]) + "]"); } } } // ------------------------------------------------------------------------ public static class Hash { private Hash() { } private static final byte[] getBytes(String s) { try { return s.getBytes(UTF_8); } catch (UnsupportedEncodingException e) { return s.getBytes(); } } public static final String crypt(String original, String salt) { return jcrypt.crypt(salt, original); } public static final byte[] md5_bytes(String original) { MessageDigest md; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new AssertionError("MD5 n'est pas disponible: " + getSummary(e)); } return md.digest(getBytes(original)); } public static final String md5(String original) { return Base64.encodeBytes(md5_bytes(original)); } public static final byte[] smd5_bytes(String original, byte[] salt) { if (salt == null) salt = new byte[0]; MessageDigest md; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new AssertionError("MD5 n'est pas disponible: " + getSummary(e)); } md.update(getBytes(original)); md.update(salt); byte[] tmpdigest = md.digest(); byte[] digest = new byte[tmpdigest.length + salt.length]; System.arraycopy(tmpdigest, 0, digest, 0, tmpdigest.length); System.arraycopy(salt, 0, digest, tmpdigest.length, salt.length); return digest; } public static final String smd5(String original, byte[] salt) { return Base64.encodeBytes(smd5_bytes(original, salt)); } public static final byte[] sha_bytes(String original) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { throw new AssertionError("SHA-1 n'est pas disponible: " + getSummary(e)); } return md.digest(getBytes(original)); } public static final String sha(String original) { return Base64.encodeBytes(sha_bytes(original)); } public static final byte[] ssha_bytes(String original, byte[] salt) { if (salt == null) salt = new byte[0]; MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { throw new AssertionError("SHA-1 n'est pas disponible: " + getSummary(e)); } md.update(getBytes(original)); md.update(salt); byte[] tmpdigest = md.digest(); byte[] digest = new byte[tmpdigest.length + salt.length]; System.arraycopy(tmpdigest, 0, digest, 0, tmpdigest.length); System.arraycopy(salt, 0, digest, tmpdigest.length, salt.length); return digest; } public static final String ssha(String original, byte[] salt) { return Base64.encodeBytes(ssha_bytes(original, salt)); } public static final byte[] ntHash_bytes(String password) { try { return new MD4().digest(password.getBytes("UTF-16LE")); } catch (UnsupportedEncodingException e) { throw new AssertionError("UTF-16LE n'est pas disponible: " + getSummary(e)); } } public static final String ntlm(String password) { return toHex(ntHash_bytes(password)); } public static final byte[] lmHash_bytes(String password) { try { byte[] oemPassword = password.toUpperCase().getBytes("US-ASCII"); int length = Math.min(oemPassword.length, 14); byte[] keys = new byte[14]; System.arraycopy(oemPassword, 0, keys, 0, length); byte[] magic = "KGS!@#$%".getBytes("US-ASCII"); byte[] key1 = new byte[7]; System.arraycopy(keys, 0, key1, 0, 7); byte[] hash1 = new DES(key1).encrypt(magic); byte[] key2 = new byte[7]; System.arraycopy(keys, 7, key2, 0, 7); byte[] hash2 = new DES(key2).encrypt(magic); byte[] hash = new byte[16]; System.arraycopy(hash1, 0, hash, 0, 8); System.arraycopy(hash2, 0, hash, 8, 8); return hash; } catch (UnsupportedEncodingException e) { throw new AssertionError("US-ASCII n'est pas disponible: " + getSummary(e)); } } public static final String lm(String password) { return toHex(lmHash_bytes(password)); } } // ------------------------------------------------------------------------ public static class Salt { public static final String getCryptSalt(String pw) { if (pw == null) return null; if (strSubstr(pw, 0, 7).equalsIgnoreCase("{crypt}")) pw = strSubstr(pw, 7); return strSubstr(pw, 0, 2); } public static final byte[] getSmd5Salt(byte[] digest) { if (digest == null) return null; if (digest.length <= 16) return new byte[0]; byte[] salt = new byte[digest.length - 16]; System.arraycopy(digest, 16, salt, 0, salt.length); return salt; } public static final byte[] getSmd5Salt(String pw) { if (pw == null) return null; if (strSubstr(pw, 0, 6).equalsIgnoreCase("{smd5}")) pw = strSubstr(pw, 6); try { return getSmd5Salt(Base64.decode(pw)); } catch (IllegalArgumentException e) { return null; } } public static final byte[] getSshaSalt(byte[] digest) { if (digest == null) return null; if (digest.length <= 20) return new byte[0]; byte[] salt = new byte[digest.length - 20]; System.arraycopy(digest, 20, salt, 0, salt.length); return salt; } public static final byte[] getSshaSalt(String pw) { if (pw == null) return null; if (strSubstr(pw, 0, 6).equalsIgnoreCase("{ssha}")) pw = strSubstr(pw, 6); try { return getSshaSalt(Base64.decode(pw)); } catch (IllegalArgumentException e) { return null; } } public static final String[] DEFAULT_CRYPT_SALT_SECTIONS = new String[] { PasswordGenerator.UPPER, PasswordGenerator.LOWER, PasswordGenerator.NUMBERS}; private static final SecureRandom newSecureRandom() { try { return SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { return new SecureRandom(); } } private static final SecureRandom DEFAULT_RAND = newSecureRandom(); private static final int DEFAULT_BINARY_SALT_LENGTH = 20; private static final Salt instance = new Salt(); public static final Salt getInstance() { return instance; } public Salt(Random rand, String[] cryptSaltSections, int binarySaltLength) { if (rand == null) rand = DEFAULT_RAND; if (cryptSaltSections == null) cryptSaltSections = DEFAULT_CRYPT_SALT_SECTIONS; if (binarySaltLength <= 0) binarySaltLength = DEFAULT_BINARY_SALT_LENGTH; this.rand = rand; this.cryptSaltSections = cryptSaltSections; this.binarySaltLength = binarySaltLength; } public Salt() { this(null, null, -1); } private Random rand; private String[] cryptSaltSections; public String newCryptSalt() { return PasswordGenerator.generate(2, cryptSaltSections, rand); } private int binarySaltLength; public byte[] newBinarySalt() { byte[] salt = new byte[binarySaltLength]; rand.nextBytes(salt); return salt; } } // ------------------------------------------------------------------------ public static class Password { public static final String CLEARTEXT = "", CRYPT = "CRYPT", MD5 = "MD5", SMD5 = "SMD5", SHA = "SHA", SSHA = "SSHA"; public static final String DEFAULT_SCHEME = SSHA; public static final List VALID_SCHEMES = Arrays.asList(new String[] { CLEARTEXT, CRYPT, MD5, SMD5, SHA, SSHA}); private static final Pattern NORMALIZED_FORMAT = Pattern.compile("\\{.+\\}.+"); public static final boolean isNormalizedFormat(String pw) { return NORMALIZED_FORMAT.matcher(pw).matches(); } public static final String getNormalizedScheme(String pw) { if (pw == null) return null; if (isNormalizedFormat(pw)) { int p = pw.indexOf('}'); return strSubstr(pw, 1, p).toUpperCase(); } else { return CLEARTEXT; } } public static final String getNormalizedPassword(String pw) { if (pw == null) return null; if (isNormalizedFormat(pw)) { int p = pw.indexOf('}'); return strSubstr(pw, p + 1); } else { return pw; } } public static final boolean isClearScheme(String pw) { String scheme = getNormalizedScheme(pw); return strIsempty(scheme) || CLEARTEXT.equals(scheme); } public static final boolean isCryptScheme(String pw) { return CRYPT.equals(getNormalizedScheme(pw)); } public static final boolean isMd5Scheme(String pw) { return MD5.equals(getNormalizedScheme(pw)); } public static final boolean isSmd5Scheme(String pw) { return SMD5.equals(getNormalizedScheme(pw)); } public static final boolean isShaScheme(String pw) { return SHA.equals(getNormalizedScheme(pw)); } public static final boolean isSshaScheme(String pw) { return SSHA.equals(getNormalizedScheme(pw)); } public static final boolean validate(String clear, String normalized) { return new Password(normalized).validate(clear); } private Salt saltGenerator = Salt.getInstance(); public void setSaltGenerator(Salt saltGenerator) { if (saltGenerator == null) saltGenerator = Salt.getInstance(); this.saltGenerator = saltGenerator; } public Password(String clear, String scheme, String crypted, String lmhash, String ntlmhash) { reset(true); setClear(clear); setScheme(scheme); this.crypted = crypted; this.lmHash = lmhash; this.ntlmHash = ntlmhash; } public Password() { reset(true); } public Password(String normalized) { this(); setNormalized(normalized); } public Password(String clear, String scheme) { this(); setClear(clear); setScheme(scheme); } protected String scheme; public String getScheme() { return scheme; } public void setScheme(String scheme) { if (scheme == null) scheme = DEFAULT_SCHEME; if (!strEquals(this.scheme, scheme)) { this.scheme = scheme; crypted = normalized = ntlmHash = lmHash = null; } } public boolean isClearScheme() { return strIsempty(scheme) || CLEARTEXT.equals(scheme); } public boolean isCryptScheme() { return CRYPT.equals(scheme); } public boolean isMd5Scheme() { return MD5.equals(scheme); } public boolean isSmd5Scheme() { return SMD5.equals(scheme); } public boolean isShaScheme() { return SHA.equals(scheme); } public boolean isSshaScheme() { return SSHA.equals(scheme); } private final void reset(boolean resetScheme) { if (resetScheme || scheme == null) scheme = DEFAULT_SCHEME; clear = crypted = normalized = lmHash = ntlmHash = null; } protected String clear; public boolean hasClear() { return clear != null; } protected String randomCryptSalt() { return saltGenerator.newCryptSalt(); } protected byte[] randomBinarySalt() { return saltGenerator.newBinarySalt(); } public static class NotAvailableException extends Exception { private static final long serialVersionUID = 1L; public static final String DEFAULT_MESSAGE = "Mot de passe en clair non disponible"; public NotAvailableException(String message) { super(message != null? message: DEFAULT_MESSAGE); } public NotAvailableException() { this(null); } } public String getClear() throws NotAvailableException { if (clear != null || crypted == null) return clear; throw new NotAvailableException(); } public String getClearOrNull() { return clear; } public Password setClear(String clear) { reset(false); this.clear = clear; return this; } public Password setCryptPassword(String pw) { reset(true); scheme = CRYPT; crypted = pw; return this; } public Password setMd5Password(String pw) { reset(true); scheme = MD5; crypted = pw; return this; } public Password setSmd5Password(String pw) { reset(true); scheme = SMD5; crypted = pw; return this; } public Password setShaPassword(String pw) { reset(true); scheme = SHA; crypted = pw; return this; } public Password setSshaPassword(String pw) { reset(true); scheme = SSHA; crypted = pw; return this; } private static final String DISABLED = "*disabled*"; public boolean isDisabled() { return !isClearScheme() && strEquals(crypted, DISABLED); } public Password setDisabled(boolean disabled) { if (disabled && !isClearScheme()) { crypted = DISABLED; ntlmHash = lmHash = normalized = null; } return this; } protected String crypted; public String getCrypted() { if (isClearScheme()) return clear; else if (crypted == null) { if (isCryptScheme()) crypted = Hash.crypt(clear, randomCryptSalt()); else if (isMd5Scheme()) crypted = Hash.md5(clear); else if (isSmd5Scheme()) crypted = Hash.smd5(clear, randomBinarySalt()); else if (isShaScheme()) crypted = Hash.sha(clear); else if (isSshaScheme()) crypted = Hash.ssha(clear, randomBinarySalt()); else throw new IllegalStateException("Type de cryptage non reconnu: " + scheme); } return crypted; } public String getCryptCrypted() { if (isCryptScheme()) return getCrypted(); else if (clear != null) return Hash.crypt(clear, randomCryptSalt()); else return null; } public String getMd5Crypted() { if (isMd5Scheme()) return getCrypted(); else if (clear != null) return Hash.md5(clear); else return null; } public String getSmd5Crypted() { if (isSmd5Scheme()) return getCrypted(); else if (clear != null) return Hash.smd5(clear, randomBinarySalt()); else return null; } public String getShaCrypted() { if (isShaScheme()) return getCrypted(); else if (clear != null) return Hash.sha(clear); else return null; } public String getSshaCrypted() { if (isSshaScheme()) return getCrypted(); else if (clear != null) return Hash.ssha(clear, randomBinarySalt()); else return null; } protected String normalized; public String getNormalized() { if (normalized == null) { if (isClearScheme()) normalized = clear; else normalized = "{" + scheme + "}" + getCrypted(); } return normalized; } public String toString() { return getNormalized(); } public Password setNormalized(String pw) { reset(true); if (pw == null) { scheme = CLEARTEXT; return this; } if (isNormalizedFormat(pw)) { int p = pw.indexOf('}'); scheme = strSubstr(pw, 1, p).toUpperCase(); crypted = strSubstr(pw, p + 1); } else { scheme = CLEARTEXT; clear = pw; } return this; } private static final String NTLM_DISABLED = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; protected String ntlmHash; public String getNtlmHash() throws NotAvailableException { if (ntlmHash == null) { if (isDisabled()) ntlmHash = NTLM_DISABLED; else if (hasClear()) ntlmHash = Hash.ntlm(clear); else throw new NotAvailableException(); } return ntlmHash; } protected String lmHash; public String getLmHash() throws NotAvailableException { if (lmHash == null) { if (isDisabled()) lmHash = NTLM_DISABLED; else if (hasClear()) lmHash = Hash.lm(clear); else throw new NotAvailableException(); } return lmHash; } public boolean validate(String userPassword) { getNormalized(); if (isClearScheme()) { return strEquals(strNotnull(this.clear), strNotnull(userPassword)); } if (userPassword == null) return false; if (isCryptScheme()) { return Hash.crypt(userPassword, Salt.getCryptSalt(crypted)).equals(crypted); } else if (isMd5Scheme()) { return Hash.md5(userPassword).equals(crypted); } else if (isSmd5Scheme()) { return Hash.smd5(userPassword, Salt.getSmd5Salt(crypted)).equals(crypted); } else if (isShaScheme()) { return Hash.sha(userPassword).equals(crypted); } else if (isSshaScheme()) { return Hash.ssha(userPassword, Salt.getSshaSalt(crypted)).equals(crypted); } return false; } public boolean equals(Object obj) { if (obj == null) return false; else if (obj instanceof String) { String pw = (String)obj; if (isNormalizedFormat(pw)) { return strEquals(getNormalized(), pw); } else return validate((String)obj); } else if (obj instanceof Password) { return strEquals(getNormalized(), ((Password)obj).getNormalized()); } throw new IllegalArgumentException("Ne peut comparer qu'avec une instance de " + getClass() + " (obtenu une " + "instance de " + obj.getClass() + ")"); } } // ------------------------------------------------------------------------ public static class PasswordChecker { public PasswordChecker(int minLen, int minUpper, int minLower, int minAlpha, int minNumber, int minSymbol, int minSpecial, boolean allowMultibytes) { this.minLen = minLen; this.minUpper = minUpper; this.minLower = minLower; this.minAlpha = minAlpha; this.minNumber = minNumber; this.minSymbol = minSymbol; this.minSpecial = minSpecial; this.allowMultibytes = allowMultibytes; } public PasswordChecker() { this(MIN_LEN, MIN_UPPER, MIN_LOWER, MIN_ALPHA, MIN_NUMBER, MIN_SYMBOL, MIN_SPECIAL, ALLOW_MULTIBYTES); } private int minLen; public int getMinLen() { return minLen; } public void setMinLen(int minLen) { this.minLen = minLen; } private int minUpper; public int getMinUpper() { return minUpper; } public void setMinUpper(int minUpper) { this.minUpper = minUpper; } private int minLower; public int getMinLower() { return minLower; } public void setMinLower(int minLower) { this.minLower = minLower; } private int minAlpha; public int getMinAlpha() { return minAlpha; } public void setMinAlpha(int minAlpha) { this.minAlpha = minAlpha; } private int minNumber; public int getMinNumber() { return minNumber; } public void setMinNumber(int minNumber) { this.minNumber = minNumber; } private int minSymbol; public int getMinSymbol() { return minSymbol; } public void setMinSymbol(int minSymbol) { this.minSymbol = minSymbol; } private int minSpecial; public int getMinSpecial() { return minSpecial; } public void setMinSpecial(int minSpecial) { this.minSpecial = minSpecial; } private boolean allowMultibytes; public boolean isAllowMultibytes() { return allowMultibytes; } public void setAllowMultibytes(boolean allowMultibytes) { this.allowMultibytes = allowMultibytes; } /** * Obtenir une description des caractéristiques du mot de passe. La chaine retournée est de * la forme '$prefix doit faire au moins N caractères, et contenir au moins 2 lettres, 2 * chiffres ou caractères spéciaux'. *

* Les valeurs actualXxx sont les nombres effectifs de caractères de chaque classe, ou -1 si * leur valeur doit être ignorée. Si le nombre effectif est satisfaisant, cette * caractéristique n'est pas mentionnée. hasMultibytes==true si le mot de passe * contient des caractères qui doivent être encodés sur plusieurs octets en UTF-8. *

*/ public String getQualityDescription(String prefix, int actualLen, int actualUpper, int actualLower, int actualAlpha, int actualNumber, int actualSymbol, int actualSpecial, boolean hasMultibytes) { if (prefix == null) prefix = "Le mot de passe"; if (minLen <= 0 && minUpper <= 0 && minLower <= 0 && minAlpha <= 0 && minNumber <= 0 && minSymbol <= 0 && minSpecial <= 0 && allowMultibytes) { return prefix + " n'as pas de restrictions particulières"; } StringBuilder sb = new StringBuilder(); sb.append(prefix); boolean mb = false; if (!allowMultibytes && hasMultibytes) { sb.append(" ne doit pas contenir de caractères accentués"); mb = true; } if (mb) sb.append(", doit "); else sb.append(" doit "); String ccPrefix; if (minLen > 0 && (actualLen == -1 || actualLen < minLen)) { sb.append("faire au moins "); sb.append(minLen); sb.append(" caractères"); ccPrefix = ", et contenir au moins"; } else { sb.append("contenir au moins"); ccPrefix = ""; } boolean first = true; if (minUpper > 0 && (actualUpper == -1 || actualUpper < minUpper)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minUpper); if (minUpper > 1) sb.append(" lettres majuscules"); else sb.append(" lettre majuscule"); first = false; } if (minLower > 0 && (actualLower == -1 || actualLower < minLower)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minLower); if (minLower > 1) sb.append(" lettres minuscules"); else sb.append(" lettre minuscule"); first = false; } if (minAlpha > 0 && (actualAlpha == -1 || actualAlpha < minAlpha)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minAlpha); if (minAlpha > 1) sb.append(" lettres"); else sb.append(" lettre"); first = false; } if (minNumber > 0 && (actualNumber == -1 || actualNumber < minNumber)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minNumber); if (minNumber > 1) sb.append(" chiffres"); else sb.append(" chiffre"); first = false; } if (minSymbol > 0 && (actualSymbol == -1 || actualSymbol < minSymbol)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minSymbol); if (minSymbol > 1) sb.append(" caractères spéciaux"); else sb.append(" caractère spécial"); first = false; } if (minSpecial > 0 && (actualSpecial == -1 || actualSpecial < minSpecial)) { if (first) sb.append(ccPrefix); else sb.append(","); sb.append(" "); sb.append(minSpecial); if (minSpecial > 1) sb.append(" chiffres ou caractères spéciaux"); else sb.append(" chiffre ou caractère spécial"); first = false; } return sb.toString(); } public String getQualityDescription(String prefix) { return getQualityDescription(prefix, -1, -1, -1, -1, -1, -1, -1, false); } private static final Pattern RE_NOT_UPPER = Pattern.compile("[^A-Z]"); private static final Pattern RE_NOT_LOWER = Pattern.compile("[^a-z]"); private static final Pattern RE_NOT_ALPHA = Pattern.compile("[^a-zA-Z]"); private static final Pattern RE_NOT_NUMBER = Pattern.compile("[^0-9]"); private static final Pattern RE_NOT_SYMBOL = Pattern.compile("[a-zA-Z0-9]"); private static final Pattern RE_NOT_SPECIAL = Pattern.compile("[a-zA-Z]"); /** * Vérifier que le mot de spécifié est de qualité. * * @return null si le mot de passe est correct. Sinon, retourner un message qui indique ce * qui ne va pas. */ public String validateQuality(String password) { password = strNotnull(password); String upper = RE_NOT_UPPER.matcher(password).replaceAll(""); String lower = RE_NOT_LOWER.matcher(password).replaceAll(""); String alpha = RE_NOT_ALPHA.matcher(password).replaceAll(""); String number = RE_NOT_NUMBER.matcher(password).replaceAll(""); String symbol = RE_NOT_SYMBOL.matcher(password).replaceAll(""); String special = RE_NOT_SPECIAL.matcher(password).replaceAll(""); int nbChars = password.length(); int nbBytes; try { byte[] passwordBytes = password.getBytes(UTF_8); nbBytes = passwordBytes.length; } catch (UnsupportedEncodingException e) { nbBytes = 0; } boolean hasMultibytes = nbChars != nbBytes; String qualityDescription = getQualityDescription( "Il", password.length(), upper.length(), lower.length(), alpha.length(), number.length(), symbol.length(), special.length(), hasMultibytes); if (password.length() < minLen) { return "Votre mot de passe est trop court (" + qualityDescription + ")"; } if (!allowMultibytes && hasMultibytes) { return "Votre mot de passe ne convient pas (" + qualityDescription + ")"; } if (upper.length() < minUpper || lower.length() < minLower || alpha.length() < minAlpha || number.length() < minNumber || symbol.length() < minSymbol || special.length() < minSpecial) { return "Votre mot de passe est trop simple (" + qualityDescription + ")"; } return null; } } // ------------------------------------------------------------------------ public static class PasswordGenerator { public static final String UPPER = "AZERTYUIOPQSDFGHJKLMWXCVBN", LOWER = "azertyuiopqsdfghjklmwxcvbn", NUMBERS = "1234567890", SYMBOLS = "&\"'(-_)=^$*!:;,?./%+#{[|\\]}"; public static final String[] DEFAULT_SECTIONS = new String[] { UPPER, LOWER, NUMBERS, SYMBOLS}; public static final int[] DEFAULT_MIN_COUNTS = new int[] {2, 2, 2, 1}; private static final Random DEFAULT_RAND = new Random(); private static final PasswordGenerator instance = new PasswordGenerator(); public static PasswordGenerator getInstance() { return instance; } public static final String generate(int minLen, String[] sections, int[] minCounts, Random rand) { if (sections == null) sections = DEFAULT_SECTIONS; if (minCounts == null) minCounts = new int[sections.length]; if (sections.length != minCounts.length) { throw new IllegalArgumentException("Les tableaux sections et minCounts " + "doivent faire la même taille"); } else { int[] tmp = new int[minCounts.length]; System.arraycopy(minCounts, 0, tmp, 0, minCounts.length); minCounts = tmp; } StringBuffer sb = new StringBuffer(); int i = 0; while (true) { int index; do { index = rand.nextInt(sections.length); } while (minCounts[index] <= 0); String section = sections[index]; sb.append(section.charAt(rand.nextInt(section.length()))); minCounts[index]--; i++; boolean done = true; for (int j = 0; j < minCounts.length; j++) { if (minCounts[j] > 0) { done = false; break; } } if (done) break; } while (sb.length() < minLen) { String section = sections[rand.nextInt(sections.length)]; sb.append(section.charAt(rand.nextInt(section.length()))); } return sb.toString(); } public static final String generate(int minLen, String[] sections, int[] minCounts) { return generate(minLen, sections, minCounts, DEFAULT_RAND); } public static final String generate(int minLen, int maxLen, String[] sections, int[] minCounts, Random rand) { int len; if (minLen > maxLen) { len = minLen; minLen = maxLen; maxLen = len; } if (minLen == maxLen) len = minLen; else len = rand.nextInt(maxLen - minLen) + minLen; return generate(len, sections, minCounts); } public static final String generate(int minLen, int maxLen, String[] sections, int[] minCounts) { return generate(minLen, maxLen, sections, minCounts, DEFAULT_RAND); } public static final String generate(int len, String[] sections, Random rand) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < len; i++) { String section = sections[rand.nextInt(sections.length)]; sb.append(section.charAt(rand.nextInt(section.length()))); } return sb.toString(); } public static final String generate(int len, String[] sections) { return generate(len, sections, DEFAULT_RAND); } public static final String generate(int minLen, int maxLen, String[] sections, Random rand) { int len; if (minLen > maxLen) { len = minLen; minLen = maxLen; maxLen = len; } if (minLen == maxLen) len = minLen; else len = rand.nextInt(maxLen - minLen) + minLen; return generate(len, sections); } public static final String generate(int minLen, int maxLen, String[] sections) { return generate(minLen, maxLen, sections, DEFAULT_RAND); } public PasswordGenerator(int minLen, String[] sections, int[] minCounts, Random rand) { setMinLen(minLen); setSections(sections); setMinCounts(minCounts); setRand(rand); } public PasswordGenerator() { this(-1, null, null, null); } private int minLen; public int getMinLen() { return minLen; } public void setMinLen(int minLen) { if (minLen < 0) minLen = MIN_LEN; this.minLen = minLen; } private String[] sections; public String[] getSections() { return sections; } public void setSections(String[] sections) { if (sections == null) sections = DEFAULT_SECTIONS; this.sections = sections; } private int[] minCounts; public int[] getMinCounts() { return minCounts; } public void setMinCounts(int[] minCounts) { if (minCounts == null) minCounts = DEFAULT_MIN_COUNTS; this.minCounts = minCounts; } private Random rand; public Random getRand() { return rand; } public void setRand(Random rand) { if (rand == null) rand = DEFAULT_RAND; this.rand = rand; } public String generate() { return generate(minLen, sections, minCounts, rand); } public String generate(int maxLen) { return generate(minLen, maxLen, sections, minCounts, rand); } } // ------------------------------------------------------------------------ public static class AESEnc { private static final String AES = "AES"; private static final String CIPHER = "AES/ECB/PKCS5Padding"; public static final byte[] genkey() throws Exception { KeyGenerator kg = KeyGenerator.getInstance(AES); kg.init(new SecureRandom()); SecretKey key = kg.generateKey(); return key.getEncoded(); } public static final String genskey() throws Exception { return Base64.encodeBytes(genkey()); } public static final byte[] genkey(String password, byte[] salt, int iterations) throws Exception { if (salt == null) salt = Salt.getInstance().newBinarySalt(); if (iterations <= 0) iterations = 10000; SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); SecretKey tmp = factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, iterations, 128)); SecretKeySpec key = new SecretKeySpec(tmp.getEncoded(), AES); return key.getEncoded(); } public static final byte[] genkey(String password) throws Exception { return genkey(password, null, -1); } public static final String genskey(String password, byte[] salt, int iterations) throws Exception { return Base64.encodeBytes(genkey(password, salt, iterations)); } public static final String genskey(String password) throws Exception { return Base64.encodeBytes(genkey(password)); } public static final byte[] getKey(String skey) { return Base64.decode(skey); } public static final String getSkey(byte[] key) { return Base64.encodeBytes(key, Base64.DONT_BREAK_LINES); } public static final byte[] encrypt(byte[] clear, byte[] key) throws Exception { if (clear == null) return null; if (key == null) throw new NullPointerException("key is required"); Cipher aes = Cipher.getInstance(CIPHER); aes.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, AES)); return aes.doFinal(clear); } public static final String sencrypt(String sclear, byte[] key) throws Exception { if (sclear == null) return null; byte[] input = sclear.getBytes(UTF_8); byte[] output = encrypt(input, key); return Base64.encodeBytes(output, Base64.DONT_BREAK_LINES); } public static final String sencrypt(String sclear, String skey) throws Exception { return sencrypt(sclear, getKey(skey)); } public static final byte[] decrypt(byte[] crypted, byte[] key) throws Exception { if (crypted == null) return null; if (key == null) throw new NullPointerException("key is required"); Cipher aes = Cipher.getInstance(CIPHER); aes.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, AES)); return aes.doFinal(crypted); } public static final String sdecrypt(String scrypted, byte[] key) throws Exception { if (scrypted == null) return null; byte[] input = Base64.decode(scrypted); byte[] output = decrypt(input, key); return new String(output, UTF_8); } public static final String sdecrypt(String scrypted, String skey) throws Exception { return sdecrypt(scrypted, getKey(skey)); } } // ------------------------------------------------------------------------ private Password getPasswordAnySalt(String clear, String scheme, final String anySalt) { return new Password(clear, scheme) { @Override protected String randomCryptSalt() { String salt = Salt.getCryptSalt(anySalt); if (salt == null) salt = super.randomCryptSalt(); return salt; } @Override protected byte[] randomBinarySalt() { byte[] salt = null; if (isSshaScheme()) salt = Salt.getSshaSalt(anySalt); else if (isSmd5Scheme()) salt = Salt.getSmd5Salt(anySalt); if (salt == null) salt = super.randomBinarySalt(); return salt; } }; } private Password getPasswordCryptSalt(String clear, String scheme, final String cryptSalt) { return new Password(clear, scheme) { @Override protected String randomCryptSalt() { String salt = cryptSalt; if (salt == null) salt = super.randomCryptSalt(); return salt; } }; } private Password getPasswordBinarySalt(String clear, String scheme, final byte[] binarySalt) { return new Password(clear, scheme) { @Override protected byte[] randomBinarySalt() { byte[] salt = binarySalt; if (salt == null) salt = super.randomBinarySalt(); return salt; } }; } private static final void die(String msg, Exception e) { if (msg != null) System.err.println(msg); if (e != null) e.printStackTrace(System.err); System.err.flush(); System.exit(1); } // actions private static enum EAction { HASH_PASSWORD, GEN_AESKEY, SHOW_AESKEY, AES_ENCRYPT, AES_DECRYPT; } private static final void checkExisting(String aeskeyfile) { if (aeskeyfile == null) die("Vous devez spécifier l'option -f", null); if (!new File(aeskeyfile).exists()) die(aeskeyfile + ": Fichier introuvable", null); } private static final byte[] readAeskeyfile(String aeskeyfile) { if (aeskeyfile == null) return null; byte[] aeskey = null; try { FileInputStream fis = new FileInputStream(aeskeyfile); try { aeskey = new byte[16]; fis.read(aeskey); } finally { fis.close(); } } catch (Exception e) { die(null, e); } return aeskey; } private static final void writeAeskeyfile(String aeskeyfile, byte[] key) { if (aeskeyfile == null) return; try { FileOutputStream fis = new FileOutputStream(aeskeyfile); try { fis.write(key); } finally { fis.close(); } } catch (Exception e) { die(null, e); } } private void run(String[] args) { if (args.length == 1 && strEquals(args[0], "--help")) { println("USAGE:" // + "\n upassword -p [-f aeskeyfile] [clear [salts...]]" + "\n upassword -f aeskeyfile -G [password [salt]]" + "\n upassword -f aeskeyfile -s" + "\n upassword -f aeskeyfile -e clear" + "\n upassword -f aeskeyfile -d crypted"); System.exit(0); } EAction action = EAction.HASH_PASSWORD; String aeskeyfile = null; int i = 0, max = args.length; while (i < args.length) { String arg = args[i]; if (arg.equals("-p")) { action = EAction.HASH_PASSWORD; i++; } else if (arg.equals("-G")) { action = EAction.GEN_AESKEY; i++; } else if (arg.equals("-s")) { action = EAction.SHOW_AESKEY; i++; } else if (arg.equals("-e")) { action = EAction.AES_ENCRYPT; i++; } else if (arg.equals("-d")) { action = EAction.AES_DECRYPT; i++; } else if (arg.substring(0, 2).equals("-f")) { int shift = 1; if (arg.equals("-f")) { if (args.length > i + 1) { aeskeyfile = args[i + 1]; shift = 2; } } else { aeskeyfile = arg.substring(2); } i += shift; } else { String[] newargs = new String[args.length - i]; System.arraycopy(args, i, newargs, 0, newargs.length); args = newargs; break; } } switch (action) { case HASH_PASSWORD: { byte[] aeskey = readAeskeyfile(aeskeyfile); String clear = null; if (args.length > 0) clear = args[0]; if (clear == null) { PasswordGenerator pg = new PasswordGenerator(); clear = pg.generate(); } if (args.length <= 1) { // Pas de salt, afficher simplement les versions cryptées des mots // de passe pour tous les schemes. Le salt est choisi au hasard pour // chaque mot de passe. Il est donc différent à chaque fois. Password p = getPasswordAnySalt(clear, null, null); String lm = null; String ntlm = null; try { lm = p.getLmHash(); ntlm = p.getNtlmHash(); } catch (Password.NotAvailableException e) { } String crypt = getPasswordAnySalt(clear, Password.CRYPT, null).getNormalized(); String sha = getPasswordAnySalt(clear, Password.SHA, null).getNormalized(); String ssha = getPasswordAnySalt(clear, Password.SSHA, null).getNormalized(); String md5 = getPasswordAnySalt(clear, Password.MD5, null).getNormalized(); String smd5 = getPasswordAnySalt(clear, Password.SMD5, null).getNormalized(); String aes = null; if (aeskey != null) { try { aes = AESEnc.sencrypt(clear, aeskey); } catch (Exception e) { die("Impossible de crypter avec AES", e); } } println("clear: " + clear); println("lm: " + lm); println("ntlm: " + ntlm); println("crypt: " + crypt); println("sha: " + sha); println("ssha: " + ssha); println("md5: " + md5); println("smd5: " + smd5); if (aes != null) println("aes: " + aes); } else { // Afficher uniquement les versions cryptées des mots de passe avec // les schemes correspondant aux salts spécifiés, pour chacun des // salts spécifiés. println("clear: " + clear); i = 1; max = args.length; while (i < max) { String salt = args[i++]; if (Password.isNormalizedFormat(salt)) { if (Password.isCryptScheme(salt)) { String cryptSalt = Salt.getCryptSalt(salt); String crypt = getPasswordCryptSalt(clear, Password.CRYPT, cryptSalt) .getNormalized(); println("salt: " + cryptSalt); println("crypt: " + crypt); } else if (Password.isSshaScheme(salt)) { byte[] sshaSalt = Salt.getSshaSalt(salt); String ssha = getPasswordBinarySalt(clear, Password.SSHA, sshaSalt) .getNormalized(); println("salt: " + toHex(sshaSalt)); println("ssha: " + ssha); } else if (Password.isSmd5Scheme(salt)) { byte[] smd5Salt = Salt.getSmd5Salt(salt); String smd5 = getPasswordBinarySalt(clear, Password.SMD5, smd5Salt) .getNormalized(); println("salt: " + toHex(smd5Salt)); println("smd5: " + smd5); } else { println("salt: " + salt + " !not supported"); } } else if (isHex(salt)) { byte[] binarySalt = fromHex(salt); String ssha = getPasswordBinarySalt(clear, Password.SSHA, binarySalt) .getNormalized(); String smd5 = getPasswordBinarySalt(clear, Password.SMD5, binarySalt) .getNormalized(); println("salt: " + toHex(binarySalt)); println("ssha: " + ssha); println("smd5: " + smd5); if (salt.length() >= 2) { String cryptSalt = Salt.getCryptSalt(salt); String crypt = getPasswordCryptSalt(clear, Password.CRYPT, cryptSalt) .getNormalized(); if (!salt.equals(cryptSalt)) println("salt: " + cryptSalt); println("crypt: " + crypt); } } else { String cryptSalt = Salt.getCryptSalt(salt); String crypt = getPasswordCryptSalt(clear, Password.CRYPT, cryptSalt) .getNormalized(); println("salt: " + cryptSalt); println("crypt: " + crypt); } } } break; } case GEN_AESKEY: { if (aeskeyfile == null) die("Vous devez spécifier l'option -f", null); if (new File(aeskeyfile).exists()) { die(aeskeyfile + ": Refus d'écraser un fichier existant", null); } String password = null; if (args.length > 0) password = args[0]; String salt = null; if (args.length > 1) salt = args[1]; byte[] key = null; try { if (password != null && salt != null) { key = AESEnc.genkey(); } else { key = AESEnc.genkey(password, salt.getBytes(UTF_8), -1); } } catch (Exception e) { die(null, e); } writeAeskeyfile(aeskeyfile, key); break; } case SHOW_AESKEY: { checkExisting(aeskeyfile); byte[] key = readAeskeyfile(aeskeyfile); println(AESEnc.getSkey(key)); break; } case AES_ENCRYPT: { checkExisting(aeskeyfile); byte[] key = readAeskeyfile(aeskeyfile); String sclear = null; if (args.length > 0) sclear = args[0]; if (sclear != null) { try { println(AESEnc.sencrypt(sclear, key)); } catch (Exception e) { die(null, e); } } break; } case AES_DECRYPT: { checkExisting(aeskeyfile); byte[] key = readAeskeyfile(aeskeyfile); String scrypted = null; if (args.length > 0) scrypted = args[0]; if (scrypted != null) { try { println(AESEnc.sdecrypt(scrypted, key)); } catch (Exception e) { die(null, e); } } break; } } } public static void main(String[] args) { new upassword().run(args); } }