Author: bdonlan Date: 2005-06-10 12:35:51 -0400 (Fri, 10 Jun 2005) New Revision: 752
Added: trunk/clients/Javer2/src/org/haverdev/haver/Base64.java trunk/clients/Javer2/src/org/haverdev/haver/server/AuthCallback.java trunk/clients/Javer2/src/org/haverdev/haver/server/AuthProvider.java trunk/clients/Javer2/src/org/haverdev/haver/server/AuthenticationProcess.java trunk/clients/Javer2/src/org/haverdev/haver/server/BasicAuthentication.java trunk/clients/Javer2/src/org/haverdev/haver/server/UserBase.java trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandWrapper.java trunk/clients/Javer2/src/org/haverdev/haver/server/Xiao.java trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/AuthenticationFailureException.java trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/UnknownAuthTypeException.java Removed: trunk/clients/Javer2/src/org/haverdev/haver/SHA1.java Modified: trunk/clients/Javer2/server.conf trunk/clients/Javer2/src/org/haverdev/haver/server/LoginContext.java trunk/clients/Javer2/src/org/haverdev/haver/server/PersistBot.java trunk/clients/Javer2/src/org/haverdev/haver/server/User.java trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandReflect.java trunk/clients/Javer2/src/org/haverdev/haver/server/UserContextFactory.java Log: Implement AUTH:BASIC Modified: trunk/clients/Javer2/server.conf =================================================================== --- trunk/clients/Javer2/server.conf 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/server.conf 2005-06-10 16:35:51 UTC (rev 752) @@ -19,9 +19,13 @@ haver.PingInterval=60 # The amount of time the full login negotiation (from connect to S: ACCEPT) is allowed -haver.HandshakeTimeout=120 +haver.HandshakeTimeout=1200 -# Default chat channels +# Authentication methods +haver.auth.methods=basic +haver.auth.basic.delegate=org.haverdev.haver.server.BasicAuthentication + +# Default chat channels (deprecated) #haver.ChatChannels=lobby,conspiracy,haver,creatures haver.ChatChannels= @@ -48,8 +52,9 @@ init.successor=login login.class=org.haverdev.haver.server.LoginContext -login.successor=normal +haver.postLoginContext=normal + normal.class=org.haverdev.haver.server.NormalContext dynachan.class=org.haverdev.haver.server.DynamicChannelPlugin @@ -62,7 +67,7 @@ org.haverdev.haver.server.DynamicChannelPlugin.store=channels.txt # Entities to load -org.haverdev.haver.server.EntityLoader.entities=stats persist +org.haverdev.haver.server.EntityLoader.entities=stats persist xiao # Entity implementation stats.class=org.haverdev.haver.server.StatsBot @@ -73,6 +78,9 @@ persist.class=org.haverdev.haver.server.PersistBot persist.argument=&PersistBot +xiao.class=org.haverdev.haver.server.Xiao +xiao.argument=&Xiao + # Defaults log4j.rootLogger=DEBUG, __A1 log4j.appender.__A1=org.apache.log4j.ConsoleAppender Added: trunk/clients/Javer2/src/org/haverdev/haver/Base64.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/Base64.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/Base64.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,1451 @@ +package org.haverdev.haver; + +/** + * Encodes and decodes to and from Base64 notation. + * + * <p> + * Change Log: + * </p> + * <ul> + * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added + * some convenience methods for reading and writing to and from files.</li> + * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems + * with other encodings (like EBCDIC).</li> + * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the + * encoded data was a single byte.</li> + * <li>v2.0 - I got rid of methods that used booleans to set options. + * Now everything is more consolidated and cleaner. The code now detects + * when data that's being decoded is gzip-compressed and will decompress it + * automatically. Generally things are cleaner. You'll probably have to + * change some method calls that you were making to support the new + * options format (<tt>int</tt>s that you "OR" together).</li> + * <li>v1.5.1 - Fixed bug when decompressing and decoding to a + * byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>. + * Added the ability to "suspend" encoding in the Output Stream so + * you can turn on and off the encoding if you need to embed base64 + * data in an otherwise "normal" stream (like an XML file).</li> + * <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself. + * This helps when using GZIP streams. + * Added the ability to GZip-compress objects before encoding them.</li> + * <li>v1.4 - Added helper methods to read/write files.</li> + * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li> + * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream + * where last buffer being read, if not completely full, was not returned.</li> + * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li> + * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li> + * </ul> + * + * <p> + * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a> + * periodically to check for updates or to contribute improvements. + * </p> + * + * @author Robert Harder + * @author [EMAIL PROTECTED] + * @version 2.1 + */ +public class Base64 +{ + +/* ******** P U B L I C F I E L D S ******** */ + + + /** No options specified. Value is zero. */ + public final static int NO_OPTIONS = 0; + + /** Specify encoding. */ + public final static int ENCODE = 1; + + + /** Specify decoding. */ + public final static int DECODE = 0; + + + /** Specify that data should be gzip-compressed. */ + public final static int GZIP = 2; + + + /** Don't break lines when encoding (violates strict Base64 specification) */ + public final static int DONT_BREAK_LINES = 8; + + +/* ******** P R I V A T E F I E L D S ******** */ + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "UTF-8"; + + + /** The 64 valid Base64 values. */ + private final static byte[] ALPHABET; + private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */ + { + (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)'/' + }; + + /** Determine which ALPHABET to use. */ + static + { + byte[] __bytes; + try + { + __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes( PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException use) + { + __bytes = _NATIVE_ALPHABET; // Fall back to native encoding + } // end catch + ALPHABET = __bytes; + } // end static + + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + // I think I end up not using the BAD_ENCODING indicator. + //private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + + /** Defeats instantiation. */ + private Base64(){} + + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes up to the first three bytes of array <var>threeBytes</var> + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by <var>numSigBytes</var>. + * The array <var>threeBytes</var> needs only be as big as + * <var>numSigBytes</var>. + * Code can reuse a byte array by passing a four-byte array as <var>b4</var>. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes ) + { + encode3to4( threeBytes, 0, numSigBytes, b4, 0 ); + return b4; + } // end encode3to4 + + + /** + * Encodes up to three bytes of the array <var>source</var> + * and writes the resulting four Base64 bytes to <var>destination</var>. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * <var>srcOffset</var> and <var>destOffset</var>. + * This method does not check to make sure your arrays + * are large enough to accomodate <var>srcOffset</var> + 3 for + * the <var>source</var> array or <var>destOffset</var> + 4 for + * the <var>destination</var> array. + * The actual number of significant bytes in your array is + * given by <var>numSigBytes</var>. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the <var>destination</var> array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset ) + { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + 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; + } // end switch + } // end encode3to4 + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return <tt>null</tt>. + * The object is not GZip-compressed before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject ) + { + return encodeObject( serializableObject, NO_OPTIONS ); + } // end encodeObject + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return <tt>null</tt>. + * <p> + * Valid options:<pre> + * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * <i>Note: Technically, this makes your encoding non-compliant.</i> + * </pre> + * <p> + * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or + * <p> + * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code> + * + * @param serializableObject The object to encode + * @param options Specified options + * @return The Base64-encoded object + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeObject( java.io.Serializable serializableObject, int options ) + { + // Streams + java.io.ByteArrayOutputStream baos = null; + java.io.OutputStream b64os = null; + java.io.ObjectOutputStream oos = null; + java.util.zip.GZIPOutputStream gzos = null; + + // Isolate options + int gzip = (options & GZIP); + int dontBreakLines = (options & DONT_BREAK_LINES); + + try + { + // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream( baos, ENCODE | dontBreakLines ); + + // GZip? + if( gzip == GZIP ) + { + gzos = new java.util.zip.GZIPOutputStream( b64os ); + oos = new java.io.ObjectOutputStream( gzos ); + } // end if: gzip + else + oos = new java.io.ObjectOutputStream( b64os ); + + oos.writeObject( serializableObject ); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + 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 ){} + } // end finally + + // Return value according to relevant encoding. + try + { + return new String( baos.toByteArray(), PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + return new String( baos.toByteArray() ); + } // end catch + + } // end encode + + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + * @param source The data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source ) + { + return encodeBytes( source, 0, source.length, NO_OPTIONS ); + } // end encodeBytes + + + + /** + * Encodes a byte array into Base64 notation. + * <p> + * Valid options:<pre> + * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * <i>Note: Technically, this makes your encoding non-compliant.</i> + * </pre> + * <p> + * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or + * <p> + * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code> + * + * + * @param source The data to convert + * @param options Specified options + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int options ) + { + return encodeBytes( source, 0, source.length, options ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len ) + { + return encodeBytes( source, off, len, NO_OPTIONS ); + } // end encodeBytes + + + + /** + * Encodes a byte array into Base64 notation. + * <p> + * Valid options:<pre> + * GZIP: gzip-compresses object before encoding it. + * DONT_BREAK_LINES: don't break lines at 76 characters + * <i>Note: Technically, this makes your encoding non-compliant.</i> + * </pre> + * <p> + * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or + * <p> + * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code> + * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int off, int len, int options ) + { + // Isolate options + int dontBreakLines = ( options & DONT_BREAK_LINES ); + int gzip = ( options & GZIP ); + + // Compress? + if( gzip == GZIP ) + { + java.io.ByteArrayOutputStream baos = null; + java.util.zip.GZIPOutputStream gzos = null; + Base64.OutputStream b64os = null; + + + try + { + // GZip -> Base64 -> ByteArray + 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(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + finally + { + try{ gzos.close(); } catch( Exception e ){} + try{ b64os.close(); } catch( Exception e ){} + try{ baos.close(); } catch( Exception e ){} + } // end finally + + // Return value according to relevant encoding. + try + { + return new String( baos.toByteArray(), PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + return new String( baos.toByteArray() ); + } // end catch + } // end if: compress + + // Else, don't compress. Better not to use streams at all then. + else + { + // Convert option to boolean in way that code likes it. + boolean breakLines = dontBreakLines == 0; + + int len43 = len * 4 / 3; + byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + 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; + } // end if: end of line + } // en dfor: each piece of array + + if( d < len ) + { + encode3to4( source, d+off, len - d, outBuff, e ); + e += 4; + } // end if: some padding needed + + + // Return value according to relevant encoding. + try + { + return new String( outBuff, 0, e, PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + return new String( outBuff, 0, e ); + } // end catch + + } // end else: don't compress + + } // end encodeBytes + + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array <var>source</var> + * and writes the resulting bytes (up to three of them) + * to <var>destination</var>. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * <var>srcOffset</var> and <var>destOffset</var>. + * This method does not check to make sure your arrays + * are large enough to accomodate <var>srcOffset</var> + 4 for + * the <var>source</var> array or <var>destOffset</var> + 3 for + * the <var>destination</var> array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset ) + { + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + 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; + } + + // Example: DkLE + else + { + try{ + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + 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; + } //e nd catch + } + } // end decodeToBytes + + + + + /** + * Very low-level access to decoding ASCII characters in + * the form of a byte array. Does not support automatically + * gunzipping or any other "fancy" features. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len ) + { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + 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); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; + + if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better + { + if( sbiDecode >= EQUALS_SIGN_ENC ) + { + b4[ b4Posn++ ] = sbiCrop; + if( b4Posn > 3 ) + { + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else + { + System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); + return null; + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode + + + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s ) + { + byte[] bytes; + try + { + bytes = s.getBytes( PREFERRED_ENCODING ); + } // end try + catch( java.io.UnsupportedEncodingException uee ) + { + bytes = s.getBytes(); + } // end catch + //</change> + + // Decode + bytes = decode( bytes, 0, bytes.length ); + + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + 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); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch( java.io.IOException e ) + { + // Just return originally-decoded bytes + } // end catch + finally + { + try{ baos.close(); } catch( Exception e ){} + try{ gzis.close(); } catch( Exception e ){} + try{ bais.close(); } catch( Exception e ){} + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns <tt>null</tt> if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @since 1.5 + */ + public static Object decodeToObject( String encodedObject ) + { + // Decode and gunzip if necessary + 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(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + catch( java.lang.ClassNotFoundException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + finally + { + try{ bais.close(); } catch( Exception e ){} + try{ ois.close(); } catch( Exception e ){} + } // end finally + + return obj; + } // end decodeObject + + + + /** + * Convenience method for encoding data to a file. + * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @return <tt>true</tt> if successful, <tt>false</tt> otherwise + * + * @since 2.1 + */ + 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; + } // end try + catch( java.io.IOException e ) + { + + success = false; + } // end catch: IOException + finally + { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end encodeToFile + + + /** + * Convenience method for decoding data to a file. + * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @return <tt>true</tt> if successful, <tt>false</tt> otherwise + * + * @since 2.1 + */ + 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; + } // end try + catch( java.io.IOException e ) + { + success = false; + } // end catch: IOException + finally + { + try{ bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end decodeToFile + + + + + /** + * Convenience method for reading a base64-encoded + * file and decoding it. + * + * @param filename Filename for reading encoded data + * @return decoded byte array or null if unsuccessful + * + * @since 2.1 + */ + public static byte[] decodeFromFile( String filename ) + { + byte[] decodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if( file.length() > Integer.MAX_VALUE ) + { + System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." ); + return null; + } // end if: file too big for int index + buffer = new byte[ (int)file.length() ]; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.DECODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + decodedData = new byte[ length ]; + System.arraycopy( buffer, 0, decodedData, 0, length ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error decoding from file " + filename ); + } // end catch: IOException + finally + { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return decodedData; + } // end decodeFromFile + + + + /** + * Convenience method for reading a binary file + * and base64-encoding it. + * + * @param filename Filename for reading binary data + * @return base64-encoded string or null if unsuccessful + * + * @since 2.1 + */ + public static String encodeFromFile( String filename ) + { + String encodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = new byte[ (int)(file.length() * 1.4) ]; + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.ENCODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error encoding from file " + filename ); + } // end catch: IOException + finally + { + try{ bis.close(); } catch( Exception e) {} + } // end finally + + return encodedData; + } // end encodeFromFile + + + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + + /** + * A [EMAIL PROTECTED] Base64.InputStream} will read data from another + * <tt>java.io.InputStream</tt>, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream + { + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + + + /** + * Constructs a [EMAIL PROTECTED] Base64.InputStream} in DECODE mode. + * + * @param in the <tt>java.io.InputStream</tt> from which to read data. + * @since 1.3 + */ + public InputStream( java.io.InputStream in ) + { + this( in, DECODE ); + } // end constructor + + + /** + * Constructs a [EMAIL PROTECTED] Base64.InputStream} in + * either ENCODE or DECODE mode. + * <p> + * Valid options:<pre> + * ENCODE or DECODE: Encode or Decode as data is read. + * DONT_BREAK_LINES: don't break lines at 76 characters + * (only meaningful when encoding) + * <i>Note: Technically, this makes your encoding non-compliant.</i> + * </pre> + * <p> + * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code> + * + * + * @param in the <tt>java.io.InputStream</tt> from which to read data. + * @param options Specified options + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + 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; + } // end constructor + + /** + * Reads enough of the input stream to convert + * to/from Base64 and returns the next byte. + * + * @return next byte + * @since 1.3 + */ + public int read() throws java.io.IOException + { + // Do we need to get data? + 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 end of stream, b is -1. + if( b >= 0 ) + { + b3[i] = (byte)b; + numBinaryBytes++; + } // end if: not end of stream + + } // end try: read + catch( java.io.IOException e ) + { + // Only a problem if we got no data at all. + if( i == 0 ) + throw e; + + } // end catch + } // end for: each needed input byte + + if( numBinaryBytes > 0 ) + { + encode3to4( b3, 0, numBinaryBytes, buffer, 0 ); + position = 0; + numSigBytes = 4; + } // end if: got data + else + { + return -1; + } // end else + } // end if: encoding + + // Else decoding + else + { + byte[] b4 = new byte[4]; + int i = 0; + for( i = 0; i < 4; i++ ) + { + // Read four "meaningful" bytes: + int b = 0; + do{ b = in.read(); } + while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC ); + + if( b < 0 ) + break; // Reads a -1 if end of stream + + b4[i] = (byte)b; + } // end for: each needed input byte + + if( i == 4 ) + { + numSigBytes = decode4to3( b4, 0, buffer, 0 ); + position = 0; + } // end if: got four characters + else if( i == 0 ){ + return -1; + } // end else if: also padded correctly + else + { + // Must have broken out from above. + throw new java.io.IOException( "Improperly padded Base64 input." ); + } // end + + } // end else: decode + } // end else: get data + + // Got data? + if( position >= 0 ) + { + // End of relevant data? + if( /*!encode &&*/ position >= numSigBytes ) + return -1; + + if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) + { + lineLength = 0; + return '\n'; + } // end if + else + { + lineLength++; // This isn't important when decoding + // but throwing an extra "if" seems + // just as wasteful. + + int b = buffer[ position++ ]; + + if( position >= bufferLength ) + position = -1; + + return b & 0xFF; // This is how you "cast" a byte that's + // intended to be unsigned. + } // end else + } // end if: position >= 0 + + // Else error + else + { + // When JDK1.4 is more accepted, use an assertion here. + throw new java.io.IOException( "Error in Base64 code reading stream." ); + } // end else + } // end read + + + /** + * Calls [EMAIL PROTECTED] #read()} repeatedly until the end of stream + * is reached or <var>len</var> bytes are read. + * Returns number of bytes read into array or -1 if + * end of stream is encountered. + * + * @param dest array to hold values + * @param off offset for array + * @param len max number of bytes to read into array + * @return bytes read into array or -1 if end of stream is encountered. + * @since 1.3 + */ + 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 && i == 0 ) + // return -1; + + if( b >= 0 ) + dest[off + i] = (byte)b; + else if( i == 0 ) + return -1; + else + break; // Out of 'for' loop + } // end for: each byte read + return i; + } // end read + + } // end inner class InputStream + + + + + + + /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ + + + + /** + * A [EMAIL PROTECTED] Base64.OutputStream} will write data to another + * <tt>java.io.OutputStream</tt>, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + 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; // Scratch used in a few places + private boolean suspendEncoding; + + /** + * Constructs a [EMAIL PROTECTED] Base64.OutputStream} in ENCODE mode. + * + * @param out the <tt>java.io.OutputStream</tt> to which data will be written. + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out ) + { + this( out, ENCODE ); + } // end constructor + + + /** + * Constructs a [EMAIL PROTECTED] Base64.OutputStream} in + * either ENCODE or DECODE mode. + * <p> + * Valid options:<pre> + * ENCODE or DECODE: Encode or Decode as data is read. + * DONT_BREAK_LINES: don't break lines at 76 characters + * (only meaningful when encoding) + * <i>Note: Technically, this makes your encoding non-compliant.</i> + * </pre> + * <p> + * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code> + * + * @param out the <tt>java.io.OutputStream</tt> to which data will be written. + * @param options Specified options. + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 1.3 + */ + 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]; + } // end constructor + + + /** + * Writes the byte to the output stream after + * converting to/from Base64 notation. + * When encoding, bytes are buffered three + * at a time before the output stream actually + * gets a write() call. + * When decoding, bytes are buffered four + * at a time. + * + * @param theByte the byte to write + * @since 1.3 + */ + public void write(int theByte) throws java.io.IOException + { + // Encoding suspended? + if( suspendEncoding ) + { + super.out.write( theByte ); + return; + } // end if: supsended + + // Encode? + if( encode ) + { + buffer[ position++ ] = (byte)theByte; + if( position >= bufferLength ) // Enough to encode. + { + out.write( encode3to4( b4, buffer, bufferLength ) ); + + lineLength += 4; + if( breakLines && lineLength >= MAX_LINE_LENGTH ) + { + out.write( NEW_LINE ); + lineLength = 0; + } // end if: end of line + + position = 0; + } // end if: enough to output + } // end if: encoding + + // Else, Decoding + else + { + // Meaningful Base64 character? + if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC ) + { + buffer[ position++ ] = (byte)theByte; + if( position >= bufferLength ) // Enough to output. + { + int len = Base64.decode4to3( buffer, 0, b4, 0 ); + out.write( b4, 0, len ); + //out.write( Base64.decode4to3( buffer ) ); + position = 0; + } // end if: enough to output + } // end if: meaningful base64 character + else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC ) + { + throw new java.io.IOException( "Invalid character in Base64 data." ); + } // end else: not white space either + } // end else: decoding + } // end write + + + + /** + * Calls [EMAIL PROTECTED] #write(int)} repeatedly until <var>len</var> + * bytes are written. + * + * @param theBytes array from which to read bytes + * @param off offset for array + * @param len max number of bytes to read into array + * @since 1.3 + */ + public void write( byte[] theBytes, int off, int len ) throws java.io.IOException + { + // Encoding suspended? + if( suspendEncoding ) + { + super.out.write( theBytes, off, len ); + return; + } // end if: supsended + + for( int i = 0; i < len; i++ ) + { + write( theBytes[ off + i ] ); + } // end for: each byte written + + } // end write + + + + /** + * Method added by PHIL. [Thanks, PHIL. -Rob] + * This pads the buffer without closing the stream. + */ + public void flushBase64() throws java.io.IOException + { + if( position > 0 ) + { + if( encode ) + { + out.write( encode3to4( b4, buffer, position ) ); + position = 0; + } // end if: encoding + else + { + throw new java.io.IOException( "Base64 input not properly padded." ); + } // end else: decoding + } // end if: buffer partially full + + } // end flush + + + /** + * Flushes and closes (I think, in the superclass) the stream. + * + * @since 1.3 + */ + public void close() throws java.io.IOException + { + // 1. Ensure that pending characters are written + flushBase64(); + + // 2. Actually close the stream + // Base class both flushes and closes. + super.close(); + + buffer = null; + out = null; + } // end close + + + + /** + * Suspends encoding of the stream. + * May be helpful if you need to embed a piece of + * base640-encoded data in a stream. + * + * @since 1.5.1 + */ + public void suspendEncoding() throws java.io.IOException + { + flushBase64(); + this.suspendEncoding = true; + } // end suspendEncoding + + + /** + * Resumes encoding of the stream. + * May be helpful if you need to embed a piece of + * base640-encoded data in a stream. + * + * @since 1.5.1 + */ + public void resumeEncoding() + { + this.suspendEncoding = false; + } // end resumeEncoding + + + + } // end inner class OutputStream + + +} // end class Base64 Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/Base64.java ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Deleted: trunk/clients/Javer2/src/org/haverdev/haver/SHA1.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/SHA1.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/SHA1.java 2005-06-10 16:35:51 UTC (rev 752) @@ -1,697 +0,0 @@ -package org.haverdev.haver; -/* @(#)SHA1.java 1.11 2004-04-26 - * This file was freely contributed to the LimeWire project and is covered - * by its existing GPL licence, but it may be used individually as a public - * domain implementation of a published algorithm (see below for references). - * It was also freely contributed to the Bitzi public domain sources. - * @author Philippe Verdy - */ - -/* Sun may wish to change the following package name, if integrating this - * class in the Sun JCE Security Provider for Java 1.5 (code-named Tiger). - * - * You can include it in your own Security Provider by inserting - * this property in your Provider derived class: - * put("MessageDigest.SHA-1", "com.bitzi.util.SHA1"); - */ -//package com.bitzi.util; -import java.security.*; -//--+---+1--+---+--2+---+---+3--+---+--4+---+---+5--+---+--6+---+---+7--+---+-- -//34567890123456789012345678901234567890123456789012345678901234567890123456789 - -/** - * <p>The FIPS PUB 180-2 standard specifies four secure hash algorithms (SHA-1, - * SHA-256, SHA-384 and SHA-512) for computing a condensed representation of - * electronic data (message). When a message of any length < 2^^64 bits (for - * SHA-1 and SHA-256) or < 2^^128 bits (for SHA-384 and SHA-512) is input to - * an algorithm, the result is an output called a message digest. The message - * digests range in length from 160 to 512 bits, depending on the algorithm. - * Secure hash algorithms are typically used with other cryptographic - * algorithms, such as digital signature algorithms and keyed-hash message - * authentication codes, or in the generation of random numbers (bits).</p> - * - * <p>The four hash algorithms specified in this "SHS" standard are called - * secure because, for a given algorithm, it is computationally infeasible - * 1) to find a message that corresponds to a given message digest, or 2) - * to find two different messages that produce the same message digest. Any - * change to a message will, with a very high probability, result in a - * different message digest. This will result in a verification failure when - * the secure hash algorithm is used with a digital signature algorithm or a - * keyed-hash message authentication algorithm.</p> - * - * <p>A "SHS change notice" adds a SHA-224 algorithm for interoperability, - * which, like SHA-1 and SHA-256, operates on 512-bit blocks and 32-bit words, - * but truncates the final digest and uses distinct initialization values.</p> - * - * <p><b>References:</b></p> - * <ol> - * <li> NIST FIPS PUB 180-2, "Secure Hash Signature Standard (SHS) with - * change notice", National Institute of Standards and Technology (NIST), - * 2002 August 1, and U.S. Department of Commerce, August 26.<br> - * <a href="http://csrc.ncsl.nist.gov/CryptoToolkit/Hash.html"> - * http://csrc.ncsl.nist.gov/CryptoToolkit/Hash.html</a> - * <li> NIST FIPS PUB 180-1, "Secure Hash Standard", - * U.S. Department of Commerce, May 1993.<br> - * <a href="http://www.itl.nist.gov/div897/pubs/fip180-1.htm"> - * http://www.itl.nist.gov/div897/pubs/fip180-1.htm</a></li> - * <li> Bruce Schneier, "Section 18.7 Secure Hash Algorithm (SHA)", - * <cite>Applied Cryptography, 2nd edition</cite>, <br> - * John Wiley & Sons, 1996</li> - * </ol> - */ -public final class SHA1 extends MessageDigest implements Cloneable { - - /** - * This implementation returns a fixed-size digest. - */ - private static final int HASH_LENGTH = 20; // bytes == 160 bits - - /** - * Private context for incomplete blocks and padding bytes. - * INVARIANT: padding must be in 0..63. - * When the padding reaches 64, a new block is computed, and - * the 56 last bytes are kept in the padding history. - */ - private byte[] pad; - private int padding; - - /** - * Private contextual byte count, sent in the next block, - * after the ending padding block. - */ - private long bytes; - - /** - * Private context that contains the current digest key. - */ - private int hA, hB, hC, hD, hE; - - /** - * Creates a SHA1 object with default initial state. - */ - public SHA1() { - super("SHA-1"); - pad = new byte[64]; - init(); - } - - /** - * Clones this object. - */ - public Object clone() throws CloneNotSupportedException { - SHA1 that = (SHA1)super.clone(); - that.pad = (byte[])this.pad.clone(); - return that; - } - - /** - * Returns the digest length in bytes. - * - * Can be used to allocate your own output buffer when - * computing multiple digests. - * - * Overrides the protected abstract method of - * <code>java.security.MessageDigestSpi</code>. - * @return the digest length in bytes. - */ - public int engineGetDigestLength() { - return HASH_LENGTH; - } - - /** - * Reset athen initialize the digest context. - * - * Overrides the protected abstract method of - * <code>java.security.MessageDigestSpi</code>. - */ - protected void engineReset() { - int i = 60; - do { - pad[i ] = (byte)0x00; - pad[i + 1] = (byte)0x00; - pad[i + 2] = (byte)0x00; - pad[i + 3] = (byte)0x00; - } while ((i -= 4) >= 0); - padding = 0; - bytes = 0; - init(); - } - - /** - * Initialize the digest context. - */ - protected void init() { - hA = 0x67452301; - hB = 0xefcdab89; - hC = 0x98badcfe; - hD = 0x10325476; - hE = 0xc3d2e1f0; - } - - /** - * Updates the digest using the specified byte. - * Requires internal buffering, and may be slow. - * - * Overrides the protected abstract method of - * java.security.MessageDigestSpi. - * @param input the byte to use for the update. - */ - public void engineUpdate(byte input) { - bytes++; - if (padding < 63) { - pad[padding++] = input; - return; - } - pad[63] = input; - computeBlock(pad, 0); - padding = 0; - } - - /** - * Updates the digest using the specified array of bytes, - * starting at the specified offset. - * - * Input length can be any size. May require internal buffering, - * if input blocks are not multiple of 64 bytes. - * - * Overrides the protected abstract method of - * java.security.MessageDigestSpi. - * @param input the array of bytes to use for the update. - * @param offset the offset to start from in the array of bytes. - * @param len the number of bytes to use, starting at offset. - */ - public void engineUpdate(byte[] input, int offset, int len) { - if (offset >= 0 && len >= 0 && offset + len <= input.length) { - bytes += len; - /* Terminate the previous block. */ - int padlen = 64 - padding; - if (padding > 0 && len >= padlen) { - System.arraycopy(input, offset, pad, padding, padlen); - computeBlock(pad, 0); - padding = 0; - offset += padlen; - len -= padlen; - } - /* Loop on large sets of complete blocks. */ - while (len >= 512) { - computeBlock(input, offset); - computeBlock(input, offset + 64); - computeBlock(input, offset + 128); - computeBlock(input, offset + 192); - computeBlock(input, offset + 256); - computeBlock(input, offset + 320); - computeBlock(input, offset + 384); - computeBlock(input, offset + 448); - offset += 512; - len -= 512; - } - /* Loop on remaining complete blocks. */ - while (len >= 64) { - computeBlock(input, offset); - offset += 64; - len -= 64; - } - /* remaining bytes kept for next block. */ - if (len > 0) { - System.arraycopy(input, offset, pad, padding, len); - padding += len; - } - return; - } - throw new ArrayIndexOutOfBoundsException(offset); - } - - /** - * Completes the hash computation by performing final operations - * such as padding. Computes the final hash and returns the final - * value as a byte[20] array. Once engineDigest has been called, - * the engine will be automatically reset as specified in the - * JavaSecurity MessageDigest specification. - * - * For faster operations with multiple digests, allocate your own - * array and use engineDigest(byte[], int offset, int len). - * - * Overrides the protected abstract method of - * java.security.MessageDigestSpi. - * @return the length of the digest stored in the output buffer. - */ - public byte[] engineDigest() { - try { - final byte hashvalue[] = new byte[HASH_LENGTH]; - engineDigest(hashvalue, 0, HASH_LENGTH); - return hashvalue; - } catch (DigestException e) { - return null; - } - } - - /** - * Completes the hash computation by performing final operations - * such as padding. Once engineDigest has been called, the engine - * will be automatically reset (see engineReset). - * - * Overrides the protected abstract method of - * java.security.MessageDigestSpi. - * @param hashvalue the output buffer in which to store the digest. - * @param offset offset to start from in the output buffer - * @param len number of bytes within buf allotted for the digest. - * Both this default implementation and the SUN provider - * do not return partial digests. The presence of this - * parameter is solely for consistency in our API's. - * If the value of this parameter is less than the - * actual digest length, the method will throw a - * DigestException. This parameter is ignored if its - * value is greater than or equal to the actual digest - * length. - * @return the length of the digest stored in the output buffer. - */ - public int engineDigest(byte[] hashvalue, int offset, final int len) - throws DigestException { - if (len >= HASH_LENGTH) { - if (hashvalue.length - offset >= HASH_LENGTH) { - /* Flush the trailing bytes, adding padding bytes into last - * blocks. */ - int i; - /* Add padding null bytes but replace the last 8 padding bytes - * by the little-endian 64-bit digested message bit-length. */ - pad[i = padding] = (byte)0x80; /* required 1st padding byte */ - /* Check if 8 bytes available in pad to store the total - * message size */ - switch (i) { /* INVARIANT: i must be in [0..63] */ - case 52: pad[53] = (byte)0x00; /* no break; falls thru */ - case 53: pad[54] = (byte)0x00; /* no break; falls thru */ - case 54: pad[55] = (byte)0x00; /* no break; falls thru */ - case 55: break; - case 56: pad[57] = (byte)0x00; /* no break; falls thru */ - case 57: pad[58] = (byte)0x00; /* no break; falls thru */ - case 58: pad[59] = (byte)0x00; /* no break; falls thru */ - case 59: pad[60] = (byte)0x00; /* no break; falls thru */ - case 60: pad[61] = (byte)0x00; /* no break; falls thru */ - case 61: pad[62] = (byte)0x00; /* no break; falls thru */ - case 62: pad[63] = (byte)0x00; /* no break; falls thru */ - case 63: - computeBlock(pad, 0); - /* Clear the 56 first bytes of pad[]. */ - i = 52; - do { - pad[i ] = (byte)0x00; - pad[i + 1] = (byte)0x00; - pad[i + 2] = (byte)0x00; - pad[i + 3] = (byte)0x00; - } while ((i -= 4) >= 0); - break; - default: - /* Clear the rest of 56 first bytes of pad[]. */ - switch (i & 3) { - case 3: i++; - break; - case 2: pad[(i += 2) - 1] = (byte)0x00; - break; - case 1: pad[(i += 3) - 2] = (byte)0x00; - pad[ i - 1] = (byte)0x00; - break; - case 0: pad[(i += 4) - 3] = (byte)0x00; - pad[ i - 2] = (byte)0x00; - pad[ i - 1] = (byte)0x00; - } - do { - pad[i ] = (byte)0x00; - pad[i + 1] = (byte)0x00; - pad[i + 2] = (byte)0x00; - pad[i + 3] = (byte)0x00; - } while ((i += 4) < 56); - } - /* Convert the message size from bytes to big-endian bits. */ - pad[56] = (byte)((i = (int)(bytes >>> 29)) >> 24); - pad[57] = (byte)(i >>> 16); - pad[58] = (byte)(i >>> 8); - pad[59] = (byte)i; - pad[60] = (byte)((i = (int)bytes << 3) >> 24); - pad[61] = (byte)(i >>> 16); - pad[62] = (byte)(i >>> 8); - pad[63] = (byte)i; - computeBlock(pad, 0); - /* Return the computed digest in big-endian byte order. */ - hashvalue[offset ] = (byte)((i = hA) >>> 24); - hashvalue[offset + 1] = (byte)(i >>> 16); - hashvalue[offset + 2] = (byte)(i >>> 8); - hashvalue[offset + 3] = (byte)i; - hashvalue[offset + 4] = (byte)((i = hB) >>> 24); - hashvalue[offset += 5] = (byte)(i >>> 16); - hashvalue[offset + 1] = (byte)(i >>> 8); - hashvalue[offset + 2] = (byte)i; - hashvalue[offset + 3] = (byte)((i = hC) >>> 24); - hashvalue[offset + 4] = (byte)(i >>> 16); - hashvalue[offset += 5] = (byte)(i >>> 8); - hashvalue[offset + 1] = (byte)i; - hashvalue[offset + 2] = (byte)((i = hD) >>> 24); - hashvalue[offset + 3] = (byte)(i >>> 16); - hashvalue[offset + 4] = (byte)(i >>> 8); - hashvalue[offset += 5] = (byte)i; - hashvalue[offset + 1] = (byte)((i = hE) >>> 24); - hashvalue[offset + 2] = (byte)(i >>> 16); - hashvalue[offset + 3] = (byte)(i >>> 8); - hashvalue[offset + 4] = (byte)i; - engineReset(); /* clear the evidence */ - return HASH_LENGTH; - } - throw new DigestException( - "insufficient space in output buffer to store the digest"); - } - throw new DigestException("partial digests not returned"); - } - - /** - * Updates the digest using the specified array of bytes, - * starting at the specified offset, but an implied length - * of exactly 64 bytes. - * - * Requires no internal buffering, but assumes a fixed input size, - * in which the required padding bytes may have been added. - * - * @param input the array of bytes to use for the update. - * @param offset the offset to start from in the array of bytes. - */ - private void computeBlock(final byte[] input, int offset) { - /* Local temporary work variables for intermediate digests. */ - int a, b, c, d, e; - /* Cache the input block into the local working set of 32-bit - * values, in big-endian byte order. Be careful when - * widening bytes or integers due to sign extension! */ - int i00, i01, i02, i03, i04, i05, i06, i07, - i08, i09, i10, i11, i12, i13, i14, i15; - /* Use hash schedule function Ch (rounds 0..19): - * Ch(x,y,z) = (x & y) ^ (~x & z) = (x & (y ^ z)) ^ z, - * and K00 = .... = K19 = 0x5a827999. */ - /* First pass, on big endian input (rounds 0..15). */ - e = hE - + (((a = hA) << 5) | (a >>> 27)) + 0x5a827999 // K00 - + (((b = hB) & ((c = hC) ^ (d = hD))) ^ d) // Ch(b,c,d) - + (i00 = input[offset ] << 24 - | (input[offset + 1] & 0xff) << 16 - | (input[offset + 2] & 0xff) << 8 - | (input[offset + 3] & 0xff)); // W00 - d += ((e << 5) | (e >>> 27)) + 0x5a827999 // K01 - + ((a & ((b = (b << 30) | (b >>> 2)) ^ c)) ^ c) // Ch(a,b,c) - + (i01 = input[offset + 4] << 24 - | (input[offset += 5] & 0xff) << 16 - | (input[offset + 1] & 0xff) << 8 - | (input[offset + 2] & 0xff)); // W01 - c += ((d << 5) | (d >>> 27)) + 0x5a827999 // K02 - + ((e & ((a = (a << 30) | (a >>> 2)) ^ b)) ^ b) // Ch(e,a,b) - + (i02 = input[offset + 3] << 24 - | (input[offset + 4] & 0xff) << 16 - | (input[offset += 5] & 0xff) << 8 - | (input[offset + 1] & 0xff)); // W02 - b += ((c << 5) | (c >>> 27)) + 0x5a827999 // K03 - + ((d & ((e = (e << 30) | (e >>> 2)) ^ a)) ^ a) // Ch(d,e,a) - + (i03 = input[offset + 2] << 24 - | (input[offset + 3] & 0xff) << 16 - | (input[offset + 4] & 0xff) << 8 - | (input[offset += 5] & 0xff)); // W03 - a += ((b << 5) | (b >>> 27)) + 0x5a827999 // K04 - + ((c & ((d = (d << 30) | (d >>> 2)) ^ e)) ^ e) // Ch(c,d,e) - + (i04 = input[offset + 1] << 24 - | (input[offset + 2] & 0xff) << 16 - | (input[offset + 3] & 0xff) << 8 - | (input[offset + 4] & 0xff)); // W04 - e += ((a << 5) | (a >>> 27)) + 0x5a827999 // K05 - + ((b & ((c = (c << 30) | (c >>> 2)) ^ d)) ^ d) // Ch(b,c,d) - + (i05 = input[offset += 5] << 24 - | (input[offset + 1] & 0xff) << 16 - | (input[offset + 2] & 0xff) << 8 - | (input[offset + 3] & 0xff)); // W05 - d += ((e << 5) | (e >>> 27)) + 0x5a827999 // K06 - + ((a & ((b = (b << 30) | (b >>> 2)) ^ c)) ^ c) // Ch(a,b,c) - + (i06 = input[offset + 4] << 24 - | (input[offset += 5] & 0xff) << 16 - | (input[offset + 1] & 0xff) << 8 - | (input[offset + 2] & 0xff)); // W06 - c += ((d << 5) | (d >>> 27)) + 0x5a827999 // K07 - + ((e & ((a = (a << 30) | (a >>> 2)) ^ b)) ^ b) // Ch(e,a,b) - + (i07 = input[offset + 3] << 24 - | (input[offset + 4] & 0xff) << 16 - | (input[offset += 5] & 0xff) << 8 - | (input[offset + 1] & 0xff)); // W07 - b += ((c << 5) | (c >>> 27)) + 0x5a827999 // K08 - + ((d & ((e = (e << 30) | (e >>> 2)) ^ a)) ^ a) // Ch(d,e,a) - + (i08 = input[offset + 2] << 24 - | (input[offset + 3] & 0xff) << 16 - | (input[offset + 4] & 0xff) << 8 - | (input[offset += 5] & 0xff)); // W08 - a += ((b << 5) | (b >>> 27)) + 0x5a827999 // K09 - + ((c & ((d = (d << 30) | (d >>> 2)) ^ e)) ^ e) // Ch(c,d,e) - + (i09 = input[offset + 1] << 24 - | (input[offset + 2] & 0xff) << 16 - | (input[offset + 3] & 0xff) << 8 - | (input[offset + 4] & 0xff)); // W09 - e += ((a << 5) | (a >>> 27)) + 0x5a827999 // K10 - + ((b & ((c = (c << 30) | (c >>> 2)) ^ d)) ^ d) // Ch(b,c,d) - + (i10 = input[offset += 5] << 24 - | (input[offset + 1] & 0xff) << 16 - | (input[offset + 2] & 0xff) << 8 - | (input[offset + 3] & 0xff)); // W10 - d += ((e << 5) | (e >>> 27)) + 0x5a827999 // K11 - + ((a & ((b = (b << 30) | (b >>> 2)) ^ c)) ^ c) // Ch(a,b,c) - + (i11 = input[offset + 4] << 24 - | (input[offset += 5] & 0xff) << 16 - | (input[offset + 1] & 0xff) << 8 - | (input[offset + 2] & 0xff)); // W11 - c += ((d << 5) | (d >>> 27)) + 0x5a827999 // K12 - + ((e & ((a = (a << 30) | (a >>> 2)) ^ b)) ^ b) // Ch(e,a,b) - + (i12 = input[offset + 3] << 24 - | (input[offset + 4] & 0xff) << 16 - | (input[offset += 5] & 0xff) << 8 - | (input[offset + 1] & 0xff)); // W12 - b += ((c << 5) | (c >>> 27)) + 0x5a827999 // K13 - + ((d & ((e = (e << 30) | (e >>> 2)) ^ a)) ^ a) // Ch(d,e,a) - + (i13 = input[offset + 2] << 24 - | (input[offset + 3] & 0xff) << 16 - | (input[offset + 4] & 0xff) << 8 - | (input[offset += 5] & 0xff)); // W13 - a += ((b << 5) | (b >>> 27)) + 0x5a827999 // K14 - + ((c & ((d = (d << 30) | (d >>> 2)) ^ e)) ^ e) // Ch(c,d,e) - + (i14 = input[offset + 1] << 24 - | (input[offset + 2] & 0xff) << 16 - | (input[offset + 3] & 0xff) << 8 - | (input[offset + 4] & 0xff)); // W14 - e += ((a << 5) | (a >>> 27)) + 0x5a827999 // K15 - + ((b & ((c = (c << 30) | (c >>> 2)) ^ d)) ^ d) // Ch(b,c,d) - + (i15 = input[offset += 5] << 24 - | (input[offset + 1] & 0xff) << 16 - | (input[offset + 2] & 0xff) << 8 - | (input[offset + 3] & 0xff)); // W15 - /* Second pass, on scheduled input (rounds 16..31). */ - d += ((e << 5) | (e >>> 27)) + 0x5a827999 // K16 - + ((a & ((b = (b << 30) | (b >>> 2)) ^ c)) ^ c) // Ch(a,b,c) - + (i00 = ((i00 ^= i02 ^ i08 ^ i13) << 1) | (i00 >>> 31)); // W16 - c += ((d << 5) | (d >>> 27)) + 0x5a827999 // K17 - + ((e & ((a = (a << 30) | (a >>> 2)) ^ b)) ^ b) // Ch(e,a,b) - + (i01 = ((i01 ^= i03 ^ i09 ^ i14) << 1) | (i01 >>> 31)); // W17 - b += ((c << 5) | (c >>> 27)) + 0x5a827999 // K18 - + ((d & ((e = (e << 30) | (e >>> 2)) ^ a)) ^ a) // Ch(d,e,a) - + (i02 = ((i02 ^= i04 ^ i10 ^ i15) << 1) | (i02 >>> 31)); // W18 - a += ((b << 5) | (b >>> 27)) + 0x5a827999 // K19 - + ((c & ((d = (d << 30) | (d >>> 2)) ^ e)) ^ e) // Ch(c,d,e) - + (i03 = ((i03 ^= i05 ^ i11 ^ i00) << 1) | (i03 >>> 31)); // W19 - /* Use hash schedule function Parity (rounds 20..39): - * Parity(x,y,z) = x ^ y ^ z, - * and K20 = .... = K39 = 0x6ed9eba1. */ - e += ((a << 5) | (a >>> 27)) + 0x6ed9eba1 // K20 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i04 = ((i04 ^= i06 ^ i12 ^ i01) << 1) | (i04 >>> 31)); // W20 - d += ((e << 5) | (e >>> 27)) + 0x6ed9eba1 // K21 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i05 = ((i05 ^= i07 ^ i13 ^ i02) << 1) | (i05 >>> 31)); // W21 - c += ((d << 5) | (d >>> 27)) + 0x6ed9eba1 // K22 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i06 = ((i06 ^= i08 ^ i14 ^ i03) << 1) | (i06 >>> 31)); // W22 - b += ((c << 5) | (c >>> 27)) + 0x6ed9eba1 // K23 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i07 = ((i07 ^= i09 ^ i15 ^ i04) << 1) | (i07 >>> 31)); // W23 - a += ((b << 5) | (b >>> 27)) + 0x6ed9eba1 // K24 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i08 = ((i08 ^= i10 ^ i00 ^ i05) << 1) | (i08 >>> 31)); // W24 - e += ((a << 5) | (a >>> 27)) + 0x6ed9eba1 // K25 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i09 = ((i09 ^= i11 ^ i01 ^ i06) << 1) | (i09 >>> 31)); // W25 - d += ((e << 5) | (e >>> 27)) + 0x6ed9eba1 // K26 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i10 = ((i10 ^= i12 ^ i02 ^ i07) << 1) | (i10 >>> 31)); // W26 - c += ((d << 5) | (d >>> 27)) + 0x6ed9eba1 // K27 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i11 = ((i11 ^= i13 ^ i03 ^ i08) << 1) | (i11 >>> 31)); // W27 - b += ((c << 5) | (c >>> 27)) + 0x6ed9eba1 // K28 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i12 = ((i12 ^= i14 ^ i04 ^ i09) << 1) | (i12 >>> 31)); // W28 - a += ((b << 5) | (b >>> 27)) + 0x6ed9eba1 // K29 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i13 = ((i13 ^= i15 ^ i05 ^ i10) << 1) | (i13 >>> 31)); // W29 - e += ((a << 5) | (a >>> 27)) + 0x6ed9eba1 // K30 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i14 = ((i14 ^= i00 ^ i06 ^ i11) << 1) | (i14 >>> 31)); // W30 - d += ((e << 5) | (e >>> 27)) + 0x6ed9eba1 // K31 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i15 = ((i15 ^= i01 ^ i07 ^ i12) << 1) | (i15 >>> 31)); // W31 - /* Third pass, on scheduled input (rounds 32..47). */ - c += ((d << 5) | (d >>> 27)) + 0x6ed9eba1 // K32 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i00 = ((i00 ^= i02 ^ i08 ^ i13) << 1) | (i00 >>> 31)); // W32 - b += ((c << 5) | (c >>> 27)) + 0x6ed9eba1 // K33 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i01 = ((i01 ^= i03 ^ i09 ^ i14) << 1) | (i01 >>> 31)); // W33 - a += ((b << 5) | (b >>> 27)) + 0x6ed9eba1 // K34 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i02 = ((i02 ^= i04 ^ i10 ^ i15) << 1) | (i02 >>> 31)); // W34 - e += ((a << 5) | (a >>> 27)) + 0x6ed9eba1 // K35 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i03 = ((i03 ^= i05 ^ i11 ^ i00) << 1) | (i03 >>> 31)); // W35 - d += ((e << 5) | (e >>> 27)) + 0x6ed9eba1 // K36 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i04 = ((i04 ^= i06 ^ i12 ^ i01) << 1) | (i04 >>> 31)); // W36 - c += ((d << 5) | (d >>> 27)) + 0x6ed9eba1 // K37 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i05 = ((i05 ^= i07 ^ i13 ^ i02) << 1) | (i05 >>> 31)); // W37 - b += ((c << 5) | (c >>> 27)) + 0x6ed9eba1 // K38 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i06 = ((i06 ^= i08 ^ i14 ^ i03) << 1) | (i06 >>> 31)); // W38 - a += ((b << 5) | (b >>> 27)) + 0x6ed9eba1 // K39 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i07 = ((i07 ^= i09 ^ i15 ^ i04) << 1) | (i07 >>> 31)); // W39 - /* Use hash schedule function Maj (rounds 40..59): - * Maj(x,y,z) = (x&y) ^ (x&z) ^ (y&z) = (x & y) | ((x | y) & z), - * and K40 = .... = K59 = 0x8f1bbcdc. */ - e += ((a << 5) | (a >>> 27)) + 0x8f1bbcdc // K40 - + ((b & (c = (c << 30) | (c >>> 2))) | ((b | c) & d)) // Maj(b,c,d) - + (i08 = ((i08 ^= i10 ^ i00 ^ i05) << 1) | (i08 >>> 31)); // W40 - d += ((e << 5) | (e >>> 27)) + 0x8f1bbcdc // K41 - + ((a & (b = (b << 30) | (b >>> 2))) | ((a | b) & c)) // Maj(a,b,c) - + (i09 = ((i09 ^= i11 ^ i01 ^ i06) << 1) | (i09 >>> 31)); // W41 - c += ((d << 5) | (d >>> 27)) + 0x8f1bbcdc // K42 - + ((e & (a = (a << 30) | (a >>> 2))) | ((e | a) & b)) // Maj(e,a,b) - + (i10 = ((i10 ^= i12 ^ i02 ^ i07) << 1) | (i10 >>> 31)); // W42 - b += ((c << 5) | (c >>> 27)) + 0x8f1bbcdc // K43 - + ((d & (e = (e << 30) | (e >>> 2))) | ((d | e) & a)) // Maj(d,e,a) - + (i11 = ((i11 ^= i13 ^ i03 ^ i08) << 1) | (i11 >>> 31)); // W43 - a += ((b << 5) | (b >>> 27)) + 0x8f1bbcdc // K44 - + ((c & (d = (d << 30) | (d >>> 2))) | ((c | d) & e)) // Maj(c,d,e) - + (i12 = ((i12 ^= i14 ^ i04 ^ i09) << 1) | (i12 >>> 31)); // W44 - e += ((a << 5) | (a >>> 27)) + 0x8f1bbcdc // K45 - + ((b & (c = (c << 30) | (c >>> 2))) | ((b | c) & d)) // Maj(b,c,d) - + (i13 = ((i13 ^= i15 ^ i05 ^ i10) << 1) | (i13 >>> 31)); // W45 - d += ((e << 5) | (e >>> 27)) + 0x8f1bbcdc // K46 - + ((a & (b = (b << 30) | (b >>> 2))) | ((a | b) & c)) // Maj(a,b,c) - + (i14 = ((i14 ^= i00 ^ i06 ^ i11) << 1) | (i14 >>> 31)); // W46 - c += ((d << 5) | (d >>> 27)) + 0x8f1bbcdc // K47 - + ((e & (a = (a << 30) | (a >>> 2))) | ((e | a) & b)) // Maj(e,a,b) - + (i15 = ((i15 ^= i01 ^ i07 ^ i12) << 1) | (i15 >>> 31)); // W47 - /* Fourth pass, on scheduled input (rounds 48..63). */ - b += ((c << 5) | (c >>> 27)) + 0x8f1bbcdc // K48 - + ((d & (e = (e << 30) | (e >>> 2))) | ((d | e) & a)) // Maj(d,e,a) - + (i00 = ((i00 ^= i02 ^ i08 ^ i13) << 1) | (i00 >>> 31)); // W48 - a += ((b << 5) | (b >>> 27)) + 0x8f1bbcdc // K49 - + ((c & (d = (d << 30) | (d >>> 2))) | ((c | d) & e)) // Maj(c,d,e) - + (i01 = ((i01 ^= i03 ^ i09 ^ i14) << 1) | (i01 >>> 31)); // W49 - e += ((a << 5) | (a >>> 27)) + 0x8f1bbcdc // K50 - + ((b & (c = (c << 30) | (c >>> 2))) | ((b | c) & d)) // Maj(b,c,d) - + (i02 = ((i02 ^= i04 ^ i10 ^ i15) << 1) | (i02 >>> 31)); // W50 - d += ((e << 5) | (e >>> 27)) + 0x8f1bbcdc // K51 - + ((a & (b = (b << 30) | (b >>> 2))) | ((a | b) & c)) // Maj(a,b,c) - + (i03 = ((i03 ^= i05 ^ i11 ^ i00) << 1) | (i03 >>> 31)); // W51 - c += ((d << 5) | (d >>> 27)) + 0x8f1bbcdc // K52 - + ((e & (a = (a << 30) | (a >>> 2))) | ((e | a) & b)) // Maj(e,a,b) - + (i04 = ((i04 ^= i06 ^ i12 ^ i01) << 1) | (i04 >>> 31)); // W52 - b += ((c << 5) | (c >>> 27)) + 0x8f1bbcdc // K53 - + ((d & (e = (e << 30) | (e >>> 2))) | ((d | e) & a)) // Maj(d,e,a) - + (i05 = ((i05 ^= i07 ^ i13 ^ i02) << 1) | (i05 >>> 31)); // W53 - a += ((b << 5) | (b >>> 27)) + 0x8f1bbcdc // K54 - + ((c & (d = (d << 30) | (d >>> 2))) | ((c | d) & e)) // Maj(c,d,e) - + (i06 = ((i06 ^= i08 ^ i14 ^ i03) << 1) | (i06 >>> 31)); // W54 - e += ((a << 5) | (a >>> 27)) + 0x8f1bbcdc // K55 - + ((b & (c = (c << 30) | (c >>> 2))) | ((b | c) & d)) // Maj(b,c,d) - + (i07 = ((i07 ^= i09 ^ i15 ^ i04) << 1) | (i07 >>> 31)); // W55 - d += ((e << 5) | (e >>> 27)) + 0x8f1bbcdc // K56 - + ((a & (b = (b << 30) | (b >>> 2))) | ((a | b) & c)) // Maj(a,b,c) - + (i08 = ((i08 ^= i10 ^ i00 ^ i05) << 1) | (i08 >>> 31)); // W56 - c += ((d << 5) | (d >>> 27)) + 0x8f1bbcdc // K57 - + ((e & (a = (a << 30) | (a >>> 2))) | ((e | a) & b)) // Maj(e,a,b) - + (i09 = ((i09 ^= i11 ^ i01 ^ i06) << 1) | (i09 >>> 31)); // W57 - b += ((c << 5) | (c >>> 27)) + 0x8f1bbcdc // K58 - + ((d & (e = (e << 30) | (e >>> 2))) | ((d | e) & a)) // Maj(d,e,a) - + (i10 = ((i10 ^= i12 ^ i02 ^ i07) << 1) | (i10 >>> 31)); // W58 - a += ((b << 5) | (b >>> 27)) + 0x8f1bbcdc // K59 - + ((c & (d = (d << 30) | (d >>> 2))) | ((c | d) & e)) // Maj(c,d,e) - + (i11 = ((i11 ^= i13 ^ i03 ^ i08) << 1) | (i11 >>> 31)); // W59 - /* Use hash schedule function Parity (rounds 60..79): - * Parity(x,y,z) = x ^ y ^ z, - * and K60 = .... = K79 = 0xca62c1d6. */ - e += ((a << 5) | (a >>> 27)) + 0xca62c1d6 // K60 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i12 = ((i12 ^= i14 ^ i04 ^ i09) << 1) | (i12 >>> 31)); // W60 - d += ((e << 5) | (e >>> 27)) + 0xca62c1d6 // K61 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i13 = ((i13 ^= i15 ^ i05 ^ i10) << 1) | (i13 >>> 31)); // W61 - c += ((d << 5) | (d >>> 27)) + 0xca62c1d6 // K62 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i14 = ((i14 ^= i00 ^ i06 ^ i11) << 1) | (i14 >>> 31)); // W62 - b += ((c << 5) | (c >>> 27)) + 0xca62c1d6 // K63 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i15 = ((i15 ^= i01 ^ i07 ^ i12) << 1) | (i15 >>> 31)); // W63 - /* Fifth pass, on scheduled input (rounds 64..79). */ - a += ((b << 5) | (b >>> 27)) + 0xca62c1d6 // K64 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i00 = ((i00 ^= i02 ^ i08 ^ i13) << 1) | (i00 >>> 31)); // W64 - e += ((a << 5) | (a >>> 27)) + 0xca62c1d6 // K65 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i01 = ((i01 ^= i03 ^ i09 ^ i14) << 1) | (i01 >>> 31)); // W65 - d += ((e << 5) | (e >>> 27)) + 0xca62c1d6 // K66 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i02 = ((i02 ^= i04 ^ i10 ^ i15) << 1) | (i02 >>> 31)); // W66 - c += ((d << 5) | (d >>> 27)) + 0xca62c1d6 // K67 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i03 = ((i03 ^= i05 ^ i11 ^ i00) << 1) | (i03 >>> 31)); // W67 - b += ((c << 5) | (c >>> 27)) + 0xca62c1d6 // K68 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i04 = ((i04 ^= i06 ^ i12 ^ i01) << 1) | (i04 >>> 31)); // W68 - a += ((b << 5) | (b >>> 27)) + 0xca62c1d6 // K69 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i05 = ((i05 ^= i07 ^ i13 ^ i02) << 1) | (i05 >>> 31)); // W69 - e += ((a << 5) | (a >>> 27)) + 0xca62c1d6 // K70 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i06 = ((i06 ^= i08 ^ i14 ^ i03) << 1) | (i06 >>> 31)); // W70 - d += ((e << 5) | (e >>> 27)) + 0xca62c1d6 // K71 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i07 = ((i07 ^= i09 ^ i15 ^ i04) << 1) | (i07 >>> 31)); // W71 - c += ((d << 5) | (d >>> 27)) + 0xca62c1d6 // K72 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i08 = ((i08 ^= i10 ^ i00 ^ i05) << 1) | (i08 >>> 31)); // W72 - b += ((c << 5) | (c >>> 27)) + 0xca62c1d6 // K73 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i09 = ((i09 ^= i11 ^ i01 ^ i06) << 1) | (i09 >>> 31)); // W73 - a += ((b << 5) | (b >>> 27)) + 0xca62c1d6 // K74 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i10 = ((i10 ^= i12 ^ i02 ^ i07) << 1) | (i10 >>> 31)); // W74 - e += ((a << 5) | (a >>> 27)) + 0xca62c1d6 // K75 - + (b ^ (c = (c << 30) | (c >>> 2)) ^ d) // Parity(b,c,d) - + (i11 = ((i11 ^= i13 ^ i03 ^ i08) << 1) | (i11 >>> 31)); // W75 - d += ((e << 5) | (e >>> 27)) + 0xca62c1d6 // K76 - + (a ^ (b = (b << 30) | (b >>> 2)) ^ c) // Parity(a,b,c) - + (i12 = ((i12 ^= i14 ^ i04 ^ i09) << 1) | (i12 >>> 31)); // W76 - c += ((d << 5) | (d >>> 27)) + 0xca62c1d6 // K77 - + (e ^ (a = (a << 30) | (a >>> 2)) ^ b) // Parity(e,a,b) - + (i13 = ((i13 ^= i15 ^ i05 ^ i10) << 1) | (i13 >>> 31)); // W77 - /* Terminate the last two rounds of fifth pass, - * feeding the final digest on the fly. */ - hB += - b += ((c << 5) | (c >>> 27)) + 0xca62c1d6 // K78 - + (d ^ (e = (e << 30) | (e >>> 2)) ^ a) // Parity(d,e,a) - + (i14 = ((i14 ^= i00 ^ i06 ^ i11) << 1) | (i14 >>> 31)); // W78 - hA += - a += ((b << 5) | (b >>> 27)) + 0xca62c1d6 // K79 - + (c ^ (d = (d << 30) | (d >>> 2)) ^ e) // Parity(c,d,e) - + (i15 = ((i15 ^= i01 ^ i07 ^ i12) << 1) | (i15 >>> 31)); // W79 - hE += e; - hD += d; - hC += /* c= */ (c << 30) | (c >>> 2); - } -} Added: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthCallback.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/AuthCallback.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/AuthCallback.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,21 @@ +/* + * AuthCallback.java + * + * Created on June 9, 2005, 10:59 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; +import org.haverdev.haver.server.exceptions.*; + +/** + * + * @author bdonlan + */ +public interface AuthCallback { + public void accept(); + public void reject(); +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthCallback.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthProvider.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/AuthProvider.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/AuthProvider.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,20 @@ +/* + * AuthProvider.java + * + * Created on June 9, 2005, 10:58 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; + +/** + * + * @author bdonlan + */ +public interface AuthProvider { + public String getProtocolName(); + public void initiateConversation(UserInfo info, UserConnection conn, AuthCallback cb); +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthProvider.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthenticationProcess.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/AuthenticationProcess.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/AuthenticationProcess.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,103 @@ +/* + * AuthenticationProcess.java + * + * Created on June 9, 2005, 11:20 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; +import org.apache.log4j.Logger; +import java.util.*; +import org.haverdev.haver.server.exceptions.*; +import java.lang.reflect.*; + +/** + * + * @author bdonlan + */ +public class AuthenticationProcess extends UserCommandWrapper implements AuthCallback { + + static final Logger log = Logger.getLogger(AuthenticationProcess.class); + + UserConnection conn = null; + UserInfo info = null; + + HashSet methodset = new HashSet(); + + /** Creates a new instance of AuthenticationProcess */ + public AuthenticationProcess(UserConnection conn, UserInfo info) { + + this.conn = conn; + this.info = info; + + if (!Boolean.parseBoolean(info.getProperty("authenticated", "false"))) { + accept(); + return; + } + + String[] methods = Misc.optionSplit(System.getProperty("haver.auth.methods")); + + for (int i = 0; i < methods.length; i++) + methodset.add(methods[i]); + + String[] msg = new String[methods.length + 1]; + msg[0] = "AUTH:TYPE"; + System.arraycopy(methods, 0, msg, 1, methods.length); + conn.sendLine(msg); + conn.context = this; + } + + public void accept() { + try { + conn.entity = new UserEntity(info); + conn.entity.attach(conn); + } + catch (PropagatedException e) { + conn.sendLine(e.clientReport()); + conn.cutConnection("internal.auth", "Unexpected error in authentication accept, see above FAIL"); + return; + } + + conn.context = UserContextFactory.constructState(conn, System.getProperty("haver.postLoginContext")); + conn.sendLine(new String[] { "HELLO", info.getName() }); + + log.info("User logged in: " + info.getName()); + conn.schedulePing(); + } + + public void reject() { + PropagatedException e = new AuthenticationFailureException(); + conn.sendLine(e.clientReport()); + conn.context = this; + } + + public void handleCommand(String[] cmd) throws PropagatedException { + if (!cmd[0].equals("AUTH:TYPE")) + throw new UnknownClientCommandException(cmd); + String method = cmd[1]; + if (!methodset.contains(method)) + throw new UnknownAuthTypeException(method); + + try { + String delegatename = System.getProperty("haver.auth." + method + ".delegate"); + Class delegate = Class.forName(delegatename); + + Object[] args = { method }; + Class[] prototype = { method.getClass() }; + + Constructor cons = delegate.getConstructor(prototype); + Object instance = cons.newInstance(args); + + AuthProvider provider = (AuthProvider)instance; + + provider.initiateConversation(info, conn, this); + } + catch (Exception e) { + log.error("Error initializing authentication provider for method " + method, e); + reject(); + } + } +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/AuthenticationProcess.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/clients/Javer2/src/org/haverdev/haver/server/BasicAuthentication.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/BasicAuthentication.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/BasicAuthentication.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,176 @@ +/* + * BasicAuthentication.java + * + * Created on June 9, 2005, 11:01 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; +import org.haverdev.haver.Base64; +import org.haverdev.haver.SHA1; +import java.security.*; +import java.nio.charset.Charset; +import java.nio.ByteBuffer; +import java.util.*; + +/** + * + * @author bdonlan + */ +public class BasicAuthentication extends UserCommandWrapper implements AuthProvider { + + org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(BasicAuthentication.class); + + static java.util.Map algos; + + static void mapAlgo(Map algos, String havername, String spiname) { + try { + MessageDigest.getInstance(spiname); + algos.put(havername, spiname); + } + catch (NoSuchAlgorithmException e) { + // XXX + } + } + + static void algoInit() { + if (algos != null) return; + + Map algotemp = new LinkedHashMap(); + mapAlgo(algotemp, "sha512", "SHA-512"); + mapAlgo(algotemp, "sha256", "SHA-256"); + mapAlgo(algotemp, "sha1", "SHA-1"); + mapAlgo(algotemp, "md5", "MD5"); + algos = Collections.unmodifiableMap(algotemp); + } + + UserConnection conn = null; + AuthCallback callback = null; + String nonce = null; + String passtok = null; + String cmd; + + /** Creates a new instance of BasicAuthentication */ + public BasicAuthentication(String tag) { + algoInit(); + cmd = "AUTH:" + tag.toUpperCase(); + } + + public void initiateConversation(UserInfo info, UserConnection conn, AuthCallback cb) { + this.conn = conn; + callback = cb; + SecureRandom rng = new SecureRandom(); + byte[] nonce_buf = new byte[16]; + rng.nextBytes(nonce_buf); + nonce = Base64.encodeBytes(nonce_buf); + + passtok = info.getProperty("auth.basic.token"); + if (passtok == null) { + cb.reject(); + return; + } + + String[] initcmd = new String[2 + algos.size()]; + initcmd[0] = "AUTH:BASIC"; + initcmd[1] = nonce; + + java.util.Iterator it = algos.keySet().iterator(); + int i = 2; + while (it.hasNext()) + initcmd[i++] = (String)it.next(); + + conn.sendLine(initcmd); + conn.context = this; + } + + static byte[] computeHash(MessageDigest algo, String passtok, String nonce) { + Charset utf8 = Charset.forName("UTF-8"); + + ByteBuffer passtok_bb = utf8.encode(passtok); + ByteBuffer nonce_bb = utf8.encode(nonce); + + byte[] passtok_b = new byte[passtok_bb.limit()]; + passtok_bb.get(passtok_b); + + byte[] nonce_b = new byte[nonce_bb.limit()]; + nonce_bb.get(nonce_b); + + byte[] combined = new byte[passtok_b.length + nonce_b.length]; + System.arraycopy(nonce_b, 0, combined, 0, nonce_b.length); + System.arraycopy(passtok_b, 0, combined, nonce_b.length, passtok_b.length); + + algo.update(combined); + byte[] result = algo.digest(); + return result; + } + + public void handleCommand(String[] cmd) throws org.haverdev.haver.server.exceptions.PropagatedException { + if (!cmd[0].equals(this.cmd)) + throw new org.haverdev.haver.server.exceptions.UnknownClientCommandException(cmd); + String algo = cmd[1]; + String hash = cmd[2]; + + MessageDigest h = null;; + try { + h = (MessageDigest) MessageDigest.getInstance((String) algos.get(algo)); + } catch (NoSuchAlgorithmException e) { + log.error("Unexpectedly lost digest " + algo + " spi " + algos.get(algo), e); + } + if (h == null) { + callback.reject(); + return; + } + + byte[] result = computeHash(h, passtok, nonce); + byte[] userval = Base64.decode(hash); + + // XXX: byte[].equals() doesn't work right, so we must do this + if (result.length != userval.length) { + callback.reject(); + return; + } + + for (int i = 0; i < result.length; i++) { + if (result[i] != userval[i]) { + callback.reject(); + return; + } + } + + callback.accept(); + } + + public String getProtocolName() { + return "basic"; + } + + public static void main(String[] args) throws Throwable { + // Simple test framework + algoInit(); + + if (args.length != 3) { + System.err.println("Usage: BasicAuthentication algo passtok nonce"); + System.err.println("Algos: "); + java.util.Iterator i = algos.keySet().iterator(); + while (i.hasNext()) + System.err.println("* " + i.next()); + System.exit(1); + } + String algo = args[0]; + String passtok = args[1]; + String nonce = args[2]; + + String spi = (String) algos.get(algo); + MessageDigest h = MessageDigest.getInstance(spi); + if (h == null) { + System.err.println("Algo " + algo + " unknown"); + System.exit(1); + } + + byte[] result = computeHash(h, passtok, nonce); + System.out.println(Base64.encodeBytes(result)); + } +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/BasicAuthentication.java ___________________________________________________________________ Name: svn:eol-style + native Modified: trunk/clients/Javer2/src/org/haverdev/haver/server/LoginContext.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/LoginContext.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/LoginContext.java 2005-06-10 16:35:51 UTC (rev 752) @@ -27,18 +27,9 @@ throw new UserAlreadyExists(args[1]); Misc.checkName(args[1], false); + log.info("User gave name: " + args[1]); UserInfo info = Main.theStore.getUser(args[1]); - conn.entity = new UserEntity(info); - conn.entity.attach(conn); - log.info("User logged in: " + args[1]); - - String[] msg = {"HELLO", args[1]}; - conn.sendLine(msg); - - //conn.context = new NormalContext(conn, "normal"); - advance(); - conn.readThread.setName("User " + args[1]); - conn.schedulePing(); + new AuthenticationProcess(conn, info); } } \ No newline at end of file Modified: trunk/clients/Javer2/src/org/haverdev/haver/server/PersistBot.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/PersistBot.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/PersistBot.java 2005-06-10 16:35:51 UTC (rev 752) @@ -11,7 +11,7 @@ * * @author bdonlan */ -public class PersistBot extends EntityBase implements User { +public class PersistBot extends UserBase implements User { /** Creates a new instance of PersistBot */ public PersistBot(String name) { Modified: trunk/clients/Javer2/src/org/haverdev/haver/server/User.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/User.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/User.java 2005-06-10 16:35:51 UTC (rev 752) @@ -16,4 +16,5 @@ public void notifyJoin(Entity channel, Entity what); public void notifyPart(Entity channel, Entity what); public void notifyQuit(Entity who, String type, String detail); + public UserInfo getInfo(); } Added: trunk/clients/Javer2/src/org/haverdev/haver/server/UserBase.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/UserBase.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/UserBase.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,46 @@ +/* + * UserBase.java + * + * Created on June 10, 2005, 10:35 AM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; + +/** + * + * @author bdonlan + */ +public abstract class UserBase extends EntityBase implements User { + + /** Creates a new instance of UserBase */ + public UserBase() { + } + + public void notifyQuit(Entity who, String type, String detail) { + } + + public void sendPrivateMessage(Entity from, String[] args) { + } + + public void notifyPublicMessage(Entity channel, Entity from, String[] args) { + } + + public void notifyPart(Entity channel, Entity what) { + } + + public void notifyJoin(Entity channel, Entity what) { + } + + public String getNamespace() { + return "user"; + } + + public UserInfo getInfo() { + return null; + } + +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/UserBase.java ___________________________________________________________________ Name: svn:eol-style + native Modified: trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandReflect.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandReflect.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandReflect.java 2005-06-10 16:35:51 UTC (rev 752) @@ -29,8 +29,6 @@ synchronized (conn) { // XXX: racy? conn.context = UserContextFactory.constructState(conn, System.getProperty(name + ".successor")); } - } catch (PropagatedException e) { - throw e; } catch (Throwable t) { throw new InternalCommandException("UNKNOWN", t); } Added: trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandWrapper.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandWrapper.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandWrapper.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,37 @@ +/* + * UserCommandWrapper.java + * + * Created on June 10, 2005, 12:04 AM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; +import org.haverdev.haver.server.exceptions.*; + +/** + * + * @author bdonlan + */ +public abstract class UserCommandWrapper implements UserCommandHandler { + + /** Creates a new instance of UserCommandWrapper */ + public UserCommandWrapper() { + } + + public void processCommand(String[] cmd) throws PropagatedException { + try { + handleCommand(cmd); + } + catch (PropagatedException e) { + e.setCmd(cmd[0]); + } + catch (Throwable t) { + throw new InternalCommandException(cmd[0], t); + } + } + + public abstract void handleCommand(String[] cmd) throws PropagatedException; +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/UserCommandWrapper.java ___________________________________________________________________ Name: svn:eol-style + native Modified: trunk/clients/Javer2/src/org/haverdev/haver/server/UserContextFactory.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/UserContextFactory.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/UserContextFactory.java 2005-06-10 16:35:51 UTC (rev 752) @@ -6,6 +6,7 @@ package org.haverdev.haver.server; import java.lang.reflect.*; +import org.apache.log4j.Logger; /** * @@ -13,15 +14,22 @@ */ public final class UserContextFactory { - public static UserCommandHandler constructState(UserConnection conn, String stateName) throws Exception { - MergingContext ctx = new MergingContext(); - String subcontexts = System.getProperty("haver.state." + stateName); - if (subcontexts == null) - throw new IllegalArgumentException("Subhandler " + stateName + " not configured"); - String[] ctx_arr = Misc.optionSplit(subcontexts); - for (int i = 0; i < ctx_arr.length; i++) - ctx.add(constructSubhandler(conn, ctx_arr[i])); - return ctx; + public static UserCommandHandler constructState(UserConnection conn, String stateName) { + try { + MergingContext ctx = new MergingContext(); + String subcontexts = System.getProperty("haver.state." + stateName); + if (subcontexts == null) + throw new IllegalArgumentException("Subhandler " + stateName + " not configured"); + String[] ctx_arr = Misc.optionSplit(subcontexts); + for (int i = 0; i < ctx_arr.length; i++) { + ctx.add(constructSubhandler(conn, ctx_arr[i])); + } + return ctx; + } catch (Exception e) { + Logger.getLogger(UserContextFactory.class).error("State machine initialization error in state " + stateName, e); + conn.cutConnection("internal.error", "Error configuring state machine"); + return null; + } } public static UserCommandHandler constructSubhandler(UserConnection conn, String name) throws Exception { Added: trunk/clients/Javer2/src/org/haverdev/haver/server/Xiao.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/Xiao.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/Xiao.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,126 @@ +/* + * Xiao.java + * + * Created on June 10, 2005, 10:27 AM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server; +import java.lang.reflect.*; // Mirror, mirror... +import org.apache.log4j.Logger; +import org.haverdev.haver.SHA1; +import org.haverdev.haver.Base64; + +import java.security.SecureRandom; +import java.nio.*; +import java.nio.charset.*; + +/** + * + * @author bdonlan + */ +public final class Xiao extends UserBase implements User { + + static final Logger log = Logger.getLogger(Xiao.class); + + /** Creates a new instance of Xiao */ + public Xiao(String name) { + setName(name); + } + + public void notifyQuit(Entity who, String type, String detail) { + } + + public void sendPrivateMessage(Entity from, String[] args) { + User ufrom = (User)from; + + if (args.length != 2) return; + if (!args[0].equals("say")) return; + String[] cmd = Misc.splitString(args[1], " "); +/* XXX + try { + Class[] proto = { ufrom.getClass(), cmd.getClass() }; + Object[] iargs = { ufrom, cmd }; + String meth = "handle_" + cmd[0].toUpperCase(); + Method m = getClass().getMethod(meth, proto); + m.invoke(this, iargs); + } + catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) + throw (RuntimeException) e.getCause(); + throw new RuntimeException("Unexpected target exception", e); + } + catch (NoSuchMethodException e) { + ((User)from).sendPrivateMessage(this, new String[] { "say", "unknown command: " + cmd[0] }); + } + catch (IllegalAccessException e) { + // wtf? + log.error("wtf? security exception in Xiao:", e); + } + **/ + if (cmd[0].toUpperCase().equals("REGISTER")) + handle_REGISTER(ufrom, cmd); + else if (cmd[0].toUpperCase().equals("UNREGISTER")) + handle_UNREGISTER(ufrom, cmd); + else + ufrom.sendPrivateMessage(this, new String[] { "say", "Unknown command: " + cmd[0] } ); + } + + public void handle_REGISTER(User from, String[] cmd) { + UserInfo info = from.getInfo(); + String password = cmd[1]; + + SecureRandom rng = new SecureRandom(); + byte[] salt = new byte[4]; + rng.nextBytes(salt); + + salt = new byte[0]; // until standardized + + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer pass_bb = utf8.encode(password); + + ByteBuffer fullbuffer = ByteBuffer.allocate(pass_bb.limit() + salt.length); + fullbuffer.rewind(); + fullbuffer.put(salt); + fullbuffer.put(pass_bb); + + log.debug(fullbuffer.array()); + + SHA1 hasher = new SHA1(); + byte[] hashin = fullbuffer.array(); + hasher.engineUpdate(hashin, 0, hashin.length); + byte[] hashout = hasher.engineDigest(); + String tok = Base64.encodeBytes(hashout); + + info.setProperty("persistant", "true"); + info.setProperty("auth.basic.token", tok); + info.setProperty("authenticated", "true"); + + from.sendPrivateMessage(this, new String[] { "say", "Registration successful." }); + } + + public void handle_UNREGISTER(User from, String[] cmd) { + UserInfo info = from.getInfo(); + info.setProperty("persistant", "false"); + + from.sendPrivateMessage(this, new String[] { "say", "Your user info will be deleted when you log out."} ); + } + + public void notifyPublicMessage(Entity channel, Entity from, String[] args) { + } + + public void notifyPart(Entity channel, Entity what) { + } + + public void notifyJoin(Entity channel, Entity what) { + } + + public String getNamespace() { + return "user"; + } + + +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/Xiao.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/AuthenticationFailureException.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/AuthenticationFailureException.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/AuthenticationFailureException.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,28 @@ +/* + * AuthenticationFailureException.java + * + * Created on June 9, 2005, 11:32 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server.exceptions; + +/** + * + * @author bdonlan + */ +public class AuthenticationFailureException extends SimplePropagatedException { + + /** Creates a new instance of AuthenticationFailureException */ + public AuthenticationFailureException() { + super("auth.fail", null); + } + + public AuthenticationFailureException(String detail) { + super("auth.fail", detail); + } + +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/AuthenticationFailureException.java ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/UnknownAuthTypeException.java =================================================================== --- trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/UnknownAuthTypeException.java 2005-06-10 02:56:27 UTC (rev 751) +++ trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/UnknownAuthTypeException.java 2005-06-10 16:35:51 UTC (rev 752) @@ -0,0 +1,24 @@ +/* + * UnknownAuthTypeException.java + * + * Created on June 9, 2005, 11:31 PM + * + * To change this template, choose Tools | Options and locate the template under + * the Source Creation and Management node. Right-click the template and choose + * Open. You can then make changes to the template in the Source Editor. + */ + +package org.haverdev.haver.server.exceptions; + +/** + * + * @author bdonlan + */ +public class UnknownAuthTypeException extends SimplePropagatedException { + + /** Creates a new instance of UnknownAuthTypeException */ + public UnknownAuthTypeException(String type) { + super("auth.unknown", type); + } + +} Property changes on: trunk/clients/Javer2/src/org/haverdev/haver/server/exceptions/UnknownAuthTypeException.java ___________________________________________________________________ Name: svn:eol-style + native
