User: starksm Date: 01/11/09 02:21:46 Modified: src/main/org/jboss/security Tag: Branch_2_4 ClientLoginModule.java Util.java Log: Cleanup formatting and logging Revision Changes Path No revision No revision 1.1.4.1 +138 -124 jbosssx/src/main/org/jboss/security/ClientLoginModule.java Index: ClientLoginModule.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/ClientLoginModule.java,v retrieving revision 1.1 retrieving revision 1.1.4.1 diff -u -r1.1 -r1.1.4.1 --- ClientLoginModule.java 2001/03/05 09:53:26 1.1 +++ ClientLoginModule.java 2001/11/09 10:21:46 1.1.4.1 @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ - + package org.jboss.security; @@ -18,137 +18,151 @@ import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; +import org.jboss.security.Logger; + /** A simple implementation of LoginModule for use by JBoss clients for -the establishment of the caller identity and credentials. This simply sets -the SecurityAssociation principal to the value of the NameCallback -filled in by the CallbackHandler, and the SecurityAssociation credential -to the value of the PasswordCallback filled in by the CallbackHandler. - -It has the following options: -<ul> -<li>multi-threaded=[true|false] -When the multi-threaded option is set to true, the SecurityAssociation.setServer() -so that each login thread has its own principal and credential storage. -<li>password-stacking=tryFirstPass|useFirstPass -When password-stacking option is set, this module first looks for a shared -username and password using "javax.security.auth.login.name" and -"javax.security.auth.login.password" respectively. This allows a module configured -prior to this one to establish a valid username and password that should be passed -to JBoss. -</ul> - -@author <a href="mailto:[EMAIL PROTECTED]">Oleg Nitz</a> -@author [EMAIL PROTECTED] -*/ + the establishment of the caller identity and credentials. This simply sets + the SecurityAssociation principal to the value of the NameCallback + filled in by the CallbackHandler, and the SecurityAssociation credential + to the value of the PasswordCallback filled in by the CallbackHandler. + + It has the following options: + <ul> + <li>multi-threaded=[true|false] + When the multi-threaded option is set to true, the SecurityAssociation.setServer() + so that each login thread has its own principal and credential storage. + <li>password-stacking=tryFirstPass|useFirstPass + When password-stacking option is set, this module first looks for a shared + username and password using "javax.security.auth.login.name" and + "javax.security.auth.login.password" respectively. This allows a module configured + prior to this one to establish a valid username and password that should be passed + to JBoss. + </ul> + + @author <a href="mailto:[EMAIL PROTECTED]">Oleg Nitz</a> + @author [EMAIL PROTECTED] + */ public class ClientLoginModule implements LoginModule { - private CallbackHandler _callbackHandler; - /** Shared state between login modules */ - private Map _sharedState; - /** Flag indicating if the shared password should be used */ - private boolean _useFirstPass; - - /** - * Initialize this LoginModule. - */ - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) - { - this._callbackHandler = callbackHandler; - this._sharedState = sharedState; - // Check for multi-threaded option - String mt = (String) options.get("multi-threaded"); - if( mt != null && Boolean.valueOf(mt).booleanValue() == true ) - { /* Turn on the server mode which uses thread local storage for + private CallbackHandler _callbackHandler; + /** Shared state between login modules */ + private Map _sharedState; + /** Flag indicating if the shared password should be used */ + private boolean _useFirstPass; + /** An interface into log4j */ + private Logger log; + + /** + * Initialize this LoginModule. + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) + { + this._callbackHandler = callbackHandler; + this._sharedState = sharedState; + // Check for multi-threaded option + String mt = (String) options.get("multi-threaded"); + if( mt != null && Boolean.valueOf(mt).booleanValue() == true ) + { /* Turn on the server mode which uses thread local storage for the principal information. - */ - SecurityAssociation.setServer(); - } - + */ + SecurityAssociation.setServer(); + } + /* Check for password sharing options. Any non-null value for password_stacking sets useFirstPass as this module has no way to validate any shared password. */ - String passwordStacking = (String) options.get("password-stacking"); - _useFirstPass = passwordStacking != null; - } - - /** - * Method to authenticate a Subject (phase 1). - */ - public boolean login() throws LoginException - { - // If useFirstPass is true, look for the shared password - if( _useFirstPass == true ) - { - try - { - String username = (String) _sharedState.get("javax.security.auth.login.name"); - Object credential = _sharedState.get("javax.security.auth.login.password"); - SecurityAssociation.setPrincipal(new SimplePrincipal(username)); - SecurityAssociation.setCredential(credential); - return true; - } - catch(Exception e) - { // Dump the exception and continue - e.printStackTrace(); - } - } - + String passwordStacking = (String) options.get("password-stacking"); + _useFirstPass = passwordStacking != null; + log = Logger.getInstance(getClass()); + } + + /** + * Method to authenticate a Subject (phase 1). + */ + public boolean login() throws LoginException + { + // If useFirstPass is true, look for the shared password + if( _useFirstPass == true ) + { + try + { + String username = (String) _sharedState.get("javax.security.auth.login.name"); + Object credential = _sharedState.get("javax.security.auth.login.password"); + SecurityAssociation.setPrincipal(new SimplePrincipal(username)); + SecurityAssociation.setCredential(credential); + return true; + } + catch(Exception e) + { // Dump the exception and continue + log.warn("Failed to setup SecurityAssociation from sharedState", e); + } + } + /* There is no password sharing or we are the first login module. Get the username and password from the callback hander. - */ - if (_callbackHandler == null) - throw new LoginException("Error: no CallbackHandler available " + - "to garner authentication information from the user"); - - PasswordCallback pc = new PasswordCallback("Password: ", false); - NameCallback nc = new NameCallback("User name: ", "guest"); - Callback[] callbacks = {nc, pc}; - try { - String username; - char[] password = null; - char[] tmpPassword; - - _callbackHandler.handle(callbacks); - username = nc.getName(); - SecurityAssociation.setPrincipal(new SimplePrincipal(username)); - tmpPassword = pc.getPassword(); - if (tmpPassword != null) { - password = new char[tmpPassword.length]; - System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length); - pc.clearPassword(); - } - SecurityAssociation.setCredential(password); - } catch (java.io.IOException ioe) { - throw new LoginException(ioe.toString()); - } catch (UnsupportedCallbackException uce) { - throw new LoginException("Error: " + uce.getCallback().toString() + - " not available to garner authentication information " + - "from the user"); - } - return true; - } - - /** - * Method to commit the authentication process (phase 2). - */ - public boolean commit() throws LoginException { - return true; - } - - /** - * Method to abort the authentication process (phase 2). - */ - public boolean abort() throws LoginException { - SecurityAssociation.setPrincipal(null); - SecurityAssociation.setCredential(null); - return true; - } - - public boolean logout() throws LoginException { - SecurityAssociation.setPrincipal(null); - SecurityAssociation.setCredential(null); - return true; - } + */ + if (_callbackHandler == null) + throw new LoginException("Error: no CallbackHandler available " + + "to garner authentication information from the user"); + + PasswordCallback pc = new PasswordCallback("Password: ", false); + NameCallback nc = new NameCallback("User name: ", "guest"); + Callback[] callbacks = {nc, pc}; + try + { + String username; + char[] password = null; + char[] tmpPassword; + + _callbackHandler.handle(callbacks); + username = nc.getName(); + SecurityAssociation.setPrincipal(new SimplePrincipal(username)); + tmpPassword = pc.getPassword(); + if (tmpPassword != null) + { + password = new char[tmpPassword.length]; + System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length); + pc.clearPassword(); + } + SecurityAssociation.setCredential(password); + } + catch (java.io.IOException ioe) + { + throw new LoginException(ioe.toString()); + } + catch (UnsupportedCallbackException uce) + { + throw new LoginException("Error: " + uce.getCallback().toString() + + " not available to garner authentication information " + + "from the user"); + } + return true; + } + + /** + * Method to commit the authentication process (phase 2). + */ + public boolean commit() throws LoginException + { + return true; + } + + /** + * Method to abort the authentication process (phase 2). + */ + public boolean abort() throws LoginException + { + SecurityAssociation.setPrincipal(null); + SecurityAssociation.setCredential(null); + return true; + } + + public boolean logout() throws LoginException + { + SecurityAssociation.setPrincipal(null); + SecurityAssociation.setCredential(null); + return true; + } } 1.1.4.1 +336 -316 jbosssx/src/main/org/jboss/security/Util.java Index: Util.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/Util.java,v retrieving revision 1.1 retrieving revision 1.1.4.1 diff -u -r1.1 -r1.1.4.1 --- Util.java 2001/03/05 09:53:28 1.1 +++ Util.java 2001/11/09 10:21:46 1.1.4.1 @@ -14,332 +14,352 @@ import java.util.Random; /** Various security related utilities like MessageDigest -factories, SecureRandom access, - -This product includes software developed by Tom Wu and Eugene -Jhong for the SRP Distribution (http://srp.stanford.edu/srp/). - -@author [EMAIL PROTECTED] -@version $Revision: 1.1 $ -*/ + factories, SecureRandom access, + + This product includes software developed by Tom Wu and Eugene + Jhong for the SRP Distribution (http://srp.stanford.edu/srp/). + + @author [EMAIL PROTECTED] + @version $Revision: 1.1.4.1 $ + */ public class Util { - private static final int HASH_LEN = 20; - private static final char[] base64Table = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./".toCharArray(); - private static SecureRandom psuedoRng; - private static MessageDigest sha1Digest; - private static boolean initialized; - - public static void init() throws NoSuchAlgorithmException - { - if( initialized ) - return; - init(null); - } - public static void init(byte[] prngSeed) throws NoSuchAlgorithmException - { - // Get an instance of the SHA-1 digest - sha1Digest = MessageDigest.getInstance("SHA"); - // Get a cryptographically strong pseudo-random generator - psuedoRng = SecureRandom.getInstance("SHA1PRNG"); - if( prngSeed != null ) - psuedoRng.setSeed(prngSeed); - initialized = true; - } - - public static MessageDigest newDigest() - { - MessageDigest md = null; - try - { - md = (MessageDigest) sha1Digest.clone(); - } - catch(CloneNotSupportedException e) - { - } - return md; - } - public static MessageDigest copy(MessageDigest md) - { - MessageDigest copy = null; - try - { - copy = (MessageDigest) md.clone(); - } - catch(CloneNotSupportedException e) - { - } - return copy; - } - - public static Random getPRNG() - { - return psuedoRng; - } - /** Returns the next pseudorandom, uniformly distributed double value - between 0.0 and 1.0 from this random number generator's sequence. + private static final int HASH_LEN = 20; + private static final char[] base64Table = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./".toCharArray(); + private static SecureRandom psuedoRng; + private static MessageDigest sha1Digest; + private static boolean initialized; + + public static void init() throws NoSuchAlgorithmException + { + if( initialized ) + return; + init(null); + } + public static void init(byte[] prngSeed) throws NoSuchAlgorithmException + { + // Get an instance of the SHA-1 digest + sha1Digest = MessageDigest.getInstance("SHA"); + // Get a cryptographically strong pseudo-random generator + psuedoRng = SecureRandom.getInstance("SHA1PRNG"); + if( prngSeed != null ) + psuedoRng.setSeed(prngSeed); + initialized = true; + } + + public static MessageDigest newDigest() + { + MessageDigest md = null; + try + { + md = (MessageDigest) sha1Digest.clone(); + } + catch(CloneNotSupportedException e) + { + } + return md; + } + public static MessageDigest copy(MessageDigest md) + { + MessageDigest copy = null; + try + { + copy = (MessageDigest) md.clone(); + } + catch(CloneNotSupportedException e) + { + } + return copy; + } + + public static Random getPRNG() + { + return psuedoRng; + } + /** Returns the next pseudorandom, uniformly distributed double value + between 0.0 and 1.0 from this random number generator's sequence. */ - public static double nextDouble() - { - return psuedoRng.nextDouble(); - } - /** Returns the next pseudorandom, uniformly distributed long value from - this random number generator's sequence. The general contract of - nextLong is that one long value is pseudorandomly generated and - returned. All 264 possible long values are produced with - (approximately) equal probability. - */ - public static long nextLong() - { - return psuedoRng.nextLong(); - } - /** Generates random bytes and places them into a user-supplied byte - array. The number of random bytes produced is equal to the length - of the byte array. - */ - public static void nextBytes(byte[] bytes) - { - psuedoRng.nextBytes(bytes); - } - /** Returns the given number of seed bytes, computed using the seed - generation algorithm that this class uses to seed itself. This call - may be used to seed other random number generators. + public static double nextDouble() + { + return psuedoRng.nextDouble(); + } + /** Returns the next pseudorandom, uniformly distributed long value from + this random number generator's sequence. The general contract of + nextLong is that one long value is pseudorandomly generated and + returned. All 264 possible long values are produced with + (approximately) equal probability. */ - public static byte[] generateSeed(int numBytes) - { - return psuedoRng.generateSeed(numBytes); - } - - public static byte[] calculatePasswordHash(String username, String password, - byte[] salt, BigInteger N, BigInteger g) - { - // Calculate x = H(s | H(U | ':' | password)) - MessageDigest xd = newDigest(); - // Try to convert the username, password to a byte[] using UTF-8 - byte[] user = null; - byte[] pass = null; - try - { - user = username.getBytes("UTF-8"); - pass = password.getBytes("UTF-8"); - } - catch(UnsupportedEncodingException e) - { - // Use the default platform encoding - user = username.getBytes(); - pass = password.getBytes(); - } - xd.update(user); - xd.update(":".getBytes()); - xd.update(pass); - byte[] h = xd.digest(); - xd.reset(); - xd.update(salt); - xd.update(h); - byte[] xb = xd.digest(); - // Calculate the password verfier v - BigInteger x = new BigInteger(1, xb); - return x.toByteArray(); - } - - /** Calculate x = H(s | H(U | ':' | password)) verifier - described in RFC2945. - */ - public static byte[] calculateVerifier(String username, String password, - byte[] salt, byte[] Nb, byte[] gb) - { - BigInteger g = new BigInteger(1, gb); - BigInteger N = new BigInteger(1, Nb); - return calculateVerifier(username, password, salt, N, g); - } - /** + public static long nextLong() + { + return psuedoRng.nextLong(); + } + /** Generates random bytes and places them into a user-supplied byte + array. The number of random bytes produced is equal to the length + of the byte array. */ - public static byte[] calculateVerifier(String username, String password, - byte[] salt, BigInteger N, BigInteger g) - { - byte[] xb = calculatePasswordHash(username, password, salt, N, g); - BigInteger x = new BigInteger(1, xb); - BigInteger v = g.modPow(x, N); - return v.toByteArray(); - } - - /** Perform an interleaved even-odd hash on the byte string + public static void nextBytes(byte[] bytes) + { + psuedoRng.nextBytes(bytes); + } + /** Returns the given number of seed bytes, computed using the seed + generation algorithm that this class uses to seed itself. This call + may be used to seed other random number generators. */ - public static byte[] sessionKeyHash(byte[] number) - { - int i, offset; - - for(offset = 0; offset < number.length && number[offset] == 0; ++offset) - ; - - byte[] key = new byte[2 * HASH_LEN]; - byte[] hout; - - int klen = (number.length - offset) / 2; - byte[] hbuf = new byte[klen]; - - for(i = 0; i < klen; ++i) - hbuf[i] = number[number.length - 2 * i - 1]; - hout = newDigest().digest(hbuf); - for(i = 0; i < HASH_LEN; ++i) - key[2 * i] = hout[i]; - - for(i = 0; i < klen; ++i) - hbuf[i] = number[number.length - 2 * i - 2]; - hout = newDigest().digest(hbuf); - for(i = 0; i < HASH_LEN; ++i) - key[2 * i + 1] = hout[i]; - - return key; - } - - /** Treat the input as the MSB representation of a number, - and lop off leading zero elements. For efficiency, the - input is simply returned if no leading zeroes are found. - */ - public static byte[] trim(byte[] in) - { - if(in.length == 0 || in[0] != 0) - return in; - - int len = in.length; - int i = 1; - while(in[i] == 0 && i < len) - ++i; - byte[] ret = new byte[len - i]; - System.arraycopy(in, i, ret, 0, len - i); - return ret; - } - - public static byte[] xor(byte[] b1, byte[] b2, int length) - { - byte[] result = new byte[length]; - for(int i = 0; i < length; ++i) - result[i] = (byte) (b1[i] ^ b2[i]); - return result; - } - - // These functions assume that the byte array has MSB at 0, LSB at end. - // Reverse the byte array (not the String) if this is not the case. - // All base64 strings are in natural order, least significant digit last. - - public static String tob64(byte[] buffer) { - boolean notleading = false; - int len = buffer.length, pos = len % 3, c; - byte b0 = 0, b1 = 0, b2 = 0; - StringBuffer sb = new StringBuffer(); - - switch(pos) { - case 1: - b2 = buffer[0]; - break; - case 2: - b1 = buffer[0]; - b2 = buffer[1]; - break; - } - do { - c = (b0 & 0xfc) >>> 2; - if(notleading || c != 0) { - sb.append(base64Table[c]); - notleading = true; - } - c = ((b0 & 3) << 4) | ((b1 & 0xf0) >>> 4); - if(notleading || c != 0) { - sb.append(base64Table[c]); - notleading = true; + public static byte[] generateSeed(int numBytes) + { + return psuedoRng.generateSeed(numBytes); + } + + public static byte[] calculatePasswordHash(String username, String password, + byte[] salt) + { + // Calculate x = H(s | H(U | ':' | password)) + MessageDigest xd = newDigest(); + // Try to convert the username, password to a byte[] using UTF-8 + byte[] user = null; + byte[] pass = null; + try + { + user = username.getBytes("UTF-8"); + pass = password.getBytes("UTF-8"); } - c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >>> 6); - if(notleading || c != 0) { - sb.append(base64Table[c]); - notleading = true; + catch(UnsupportedEncodingException e) + { + e.printStackTrace(); + // Use the default platform encoding + user = username.getBytes(); + pass = password.getBytes(); } - c = b2 & 0x3f; - if(notleading || c != 0) { - sb.append(base64Table[c]); - notleading = true; + xd.update(user); + xd.update(":".getBytes()); + xd.update(pass); + byte[] h = xd.digest(); + xd.reset(); + xd.update(salt); + xd.update(h); + byte[] xb = xd.digest(); + return xb; + } + + /** Calculate x = H(s | H(U | ':' | password)) verifier + v = g^x % N + described in RFC2945. + */ + public static byte[] calculateVerifier(String username, String password, + byte[] salt, byte[] Nb, byte[] gb) + { + BigInteger g = new BigInteger(1, gb); + BigInteger N = new BigInteger(1, Nb); + return calculateVerifier(username, password, salt, N, g); + } + /** Calculate x = H(s | H(U | ':' | password)) verifier + v = g^x % N + described in RFC2945. + */ + public static byte[] calculateVerifier(String username, String password, + byte[] salt, BigInteger N, BigInteger g) + { + byte[] xb = calculatePasswordHash(username, password, salt); + BigInteger x = new BigInteger(1, xb); + BigInteger v = g.modPow(x, N); + return v.toByteArray(); + } + + /** Perform an interleaved even-odd hash on the byte string + */ + public static byte[] sessionKeyHash(byte[] number) + { + int i, offset; + + for(offset = 0; offset < number.length && number[offset] == 0; ++offset) + ; + + byte[] key = new byte[2 * HASH_LEN]; + byte[] hout; + + int klen = (number.length - offset) / 2; + byte[] hbuf = new byte[klen]; + + for(i = 0; i < klen; ++i) + hbuf[i] = number[number.length - 2 * i - 1]; + hout = newDigest().digest(hbuf); + for(i = 0; i < HASH_LEN; ++i) + key[2 * i] = hout[i]; + + for(i = 0; i < klen; ++i) + hbuf[i] = number[number.length - 2 * i - 2]; + hout = newDigest().digest(hbuf); + for(i = 0; i < HASH_LEN; ++i) + key[2 * i + 1] = hout[i]; + + return key; + } + + /** Treat the input as the MSB representation of a number, + and lop off leading zero elements. For efficiency, the + input is simply returned if no leading zeroes are found. + */ + public static byte[] trim(byte[] in) + { + if(in.length == 0 || in[0] != 0) + return in; + + int len = in.length; + int i = 1; + while(in[i] == 0 && i < len) + ++i; + byte[] ret = new byte[len - i]; + System.arraycopy(in, i, ret, 0, len - i); + return ret; + } + + public static byte[] xor(byte[] b1, byte[] b2, int length) + { + byte[] result = new byte[length]; + for(int i = 0; i < length; ++i) + result[i] = (byte) (b1[i] ^ b2[i]); + return result; + } + + // These functions assume that the byte array has MSB at 0, LSB at end. + // Reverse the byte array (not the String) if this is not the case. + // All base64 strings are in natural order, least significant digit last. + + public static String tob64(byte[] buffer) + { + boolean notleading = false; + int len = buffer.length, pos = len % 3, c; + byte b0 = 0, b1 = 0, b2 = 0; + StringBuffer sb = new StringBuffer(); + + switch(pos) + { + case 1: + b2 = buffer[0]; + break; + case 2: + b1 = buffer[0]; + b2 = buffer[1]; + break; } - if(pos >= len) - break; + do + { + c = (b0 & 0xfc) >>> 2; + if(notleading || c != 0) + { + sb.append(base64Table[c]); + notleading = true; + } + c = ((b0 & 3) << 4) | ((b1 & 0xf0) >>> 4); + if(notleading || c != 0) + { + sb.append(base64Table[c]); + notleading = true; + } + c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >>> 6); + if(notleading || c != 0) + { + sb.append(base64Table[c]); + notleading = true; + } + c = b2 & 0x3f; + if(notleading || c != 0) + { + sb.append(base64Table[c]); + notleading = true; + } + if(pos >= len) + break; + else + try + { + b0 = buffer[pos++]; + b1 = buffer[pos++]; + b2 = buffer[pos++]; + } catch(ArrayIndexOutOfBoundsException e) + { break; } + } while(true); + + if(notleading) + return sb.toString(); else - try { - b0 = buffer[pos++]; - b1 = buffer[pos++]; - b2 = buffer[pos++]; - } catch(ArrayIndexOutOfBoundsException e) { break; } - } while(true); - - if(notleading) - return sb.toString(); - else - return "0"; - } - - public static byte[] fromb64(String str) throws NumberFormatException { - int len = str.length(); - if(len == 0) - throw new NumberFormatException("Empty Base64 string"); - - byte[] a = new byte[len + 1]; - char c; - int i, j; - - for(i = 0; i < len; ++i) { - c = str.charAt(i); - try { - for(j = 0; c != base64Table[j]; ++j) - ; - } catch(Exception e) { - throw new NumberFormatException("Illegal Base64 character"); + return "0"; + } + + public static byte[] fromb64(String str) throws NumberFormatException + { + int len = str.length(); + if(len == 0) + throw new NumberFormatException("Empty Base64 string"); + + byte[] a = new byte[len + 1]; + char c; + int i, j; + + for(i = 0; i < len; ++i) + { + c = str.charAt(i); + try + { + for(j = 0; c != base64Table[j]; ++j) + ; + } catch(Exception e) + { + throw new NumberFormatException("Illegal Base64 character"); + } + a[i] = (byte) j; } - a[i] = (byte) j; - } - - i = len - 1; - j = len; - try { - while(true) { - a[j] = a[i]; - if(--i < 0) - break; - a[j] |= (a[i] & 3) << 6; - --j; - a[j] = (byte) ((a[i] & 0x3c) >>> 2); - if(--i < 0) - break; - a[j] |= (a[i] & 0xf) << 4; - --j; - a[j] = (byte) ((a[i] & 0x30) >>> 4); - if(--i < 0) - break; - a[j] |= (a[i] << 2); - - // Nasty, evil bug in Microsloth's Java interpreter under - // Netscape: The following three lines of code are supposed - // to be equivalent, but under the Windows NT VM (Netscape3.0) - // using either of the two commented statements would cause - // the zero to be placed in a[j] *before* decrementing j. - // Weeeeird. - a[j-1] = 0; --j; - // a[--j] = 0; - // --j; a[j] = 0; - - if(--i < 0) - break; + + i = len - 1; + j = len; + try + { + while(true) + { + a[j] = a[i]; + if(--i < 0) + break; + a[j] |= (a[i] & 3) << 6; + --j; + a[j] = (byte) ((a[i] & 0x3c) >>> 2); + if(--i < 0) + break; + a[j] |= (a[i] & 0xf) << 4; + --j; + a[j] = (byte) ((a[i] & 0x30) >>> 4); + if(--i < 0) + break; + a[j] |= (a[i] << 2); + + // Nasty, evil bug in Microsloth's Java interpreter under + // Netscape: The following three lines of code are supposed + // to be equivalent, but under the Windows NT VM (Netscape3.0) + // using either of the two commented statements would cause + // the zero to be placed in a[j] *before* decrementing j. + // Weeeeird. + a[j-1] = 0; --j; + // a[--j] = 0; + // --j; a[j] = 0; + + if(--i < 0) + break; + } + } catch(Exception e) + {} + + try + { + while(a[j] == 0) + ++j; + } catch(Exception e) + { + return new byte[1]; } - } catch(Exception e) {} - - try { - while(a[j] == 0) - ++j; - } catch(Exception e) { - return new byte[1]; - } - - byte[] result = new byte[len - j + 1]; - System.arraycopy(a, j, result, 0, len - j + 1); - return result; - } - + + byte[] result = new byte[len - j + 1]; + System.arraycopy(a, j, result, 0, len - j + 1); + return result; + } + }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development