Lauren wrote:
> I am looking for good ideas on how to best do the following: We have two
> different applications running that need to pass authentication information
> ... I was thinking of encrypting the information and then passing it ...
Hi Lauren,
There are a few ways you can do this.
1. The easiest is if both servers can access the same database.
If so, you can just stick any user info into the database,
along with some kind of long random number for an identifier.
Send the long random number to the second server, which can
then retrieve the database user info row and delete it.
2. Shared-key encryption, where both servers share the same key.
This is a fine solution if both servers are similarly secure,
and you can trust both website apps to "be in on the secret".
This is sometimes called symmetric (or single key) encryption.
3. Public-private-key encryption, where there are four keys:
Server1 public & private, and Server2 public & private.
This is sometimes called asymmetric with signatures.
Server1 encrypts the user info using Server2 public,
and signs the resulting message using Server1 private.
Then Server2 uses Server1 public to authenticate the
message, and finally decrypts it using Server2 private.
As you might imagine, this approach is more complex.
I assume you understand how to do #1.
I am attaching a demo solution to #2.
I am guessing that you don't need #3,
but if so, I can build it up for you.
When you pass your string, be sure to include a timestamp
and some kind of random ID. These will prevent a hacker
from copying the URL string and "replaying" the URL later.
Your second server should keep track of expired IDs.
Cheers,
Joel
work: [EMAIL PROTECTED]
home: [EMAIL PROTECTED]
/****************************************************************
*
* CUT HERE
*
* com/sun/netdynamics/demo/DesDemo.java
*
****************************************************************/
/**
*
* DesDemo is an example of how to use DES, and the Acme DesCipher class.
* By [EMAIL PROTECTED] Please send feedback with your suggestions.
*
* Special thanks to Jef and Acme.com for providing the crypto classes.
* This is not supported by Sun or NetDynamics. Use it at your own risk.
*
*
* Syntax: DesDemo yourkey yourtext
*
* yourkey is any 8 letter string. It is converted to a 64-bit DES key.
* In any real implmentation, you should use a SecureRandom 64-bit key.
*
* yourtext is any text, as short or as long as you want to make it.
* If the text is not a multiple of 8 letters, it will be padded for you.
*
*
* Example: DesDemo qwertyui NowIsTheTime
*
* input length 16 string NowIsTheTime base64 Tm93SXNUaGVUaW1lAAAAAA==
* crypt length 16 string (unprintable) base64 IH+v+686s7/bq7/Ri+/TRg==
* clear length 16 string NowIsTheTime base64 Tm93SXNUaGVUaW1lAAAAAA==
*
*
* Required: classes from http://www.acme.com/java/
*
* com.acme.crypto.DesCipher
* com.acme.crypto.BlockCipher
* com.acme.crypto.Cipher
* com.acme.crypto.CryptoUtils
* com.acme.Utils
*
**/
package com.sun.netdynamics.demo;
public class DesDemo {
public DesDemo (String key, String text) {
com.acme.crypto.DesCipher des = new com.acme.crypto.DesCipher(key.getBytes());
int padlength = padlength(text);
int i;
byte[]
inputBytes = new byte[padlength], // The input text bytes.
cryptBytes = new byte[padlength], // The encrypted bytes.
clearBytes = new byte[padlength]; // The decrypted bytes.
System.arraycopy(text.getBytes(),0,inputBytes,0,text.getBytes().length);
p("input",inputBytes);
for (i=0; i<padlength; i+=8) { des.encrypt(inputBytes,i,cryptBytes,i); }
p("crypt",cryptBytes);
for (i=0; i<padlength; i+=8) { des.decrypt(cryptBytes,i,clearBytes,i); }
p("clear",clearBytes);
}
// To use block ciphers like DES, you need input that is in 8-byte blocks.
// If your input byte length isn't divisible by 8, we will need to pad it.
public static int padlength (String s) {
int len = s.getBytes().length;
int mod = len % 8;
return len + ((mod==0) ? 0 : 8-mod);
}
public static void p (String s) {
System.out.println(s);
}
public static void p (String s, byte[] b) {
System.out.println(s
+" length "+b.length
+" string "+new String(b)
+" base64 "+com.acme.Utils.base64Encode(b)
);
}
public static void main (String[] args) {
try {
DesDemo demo = new DesDemo (args[0], args[1]);
}
catch (Throwable t) {
System.out.println("uncaught exception: " + t);
t.printStackTrace();
}
}
}
/****************************************************************
*
* CUT HERE
*
* com/acme/crypto/DesCipher.java
*
****************************************************************/
// DesCipher - the DES encryption method
//
// The meat of this code is by Dave Zimmerman <[EMAIL PROTECTED]>, and is:
//
// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
//
// Permission to use, copy, modify, and distribute this software
// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
// without fee is hereby granted, provided that this copyright notice is kept
// intact.
//
// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
//
// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
// HIGH RISK ACTIVITIES.
//
//
// The rest is:
//
// Copyright (C) 1996 by Jef Poskanzer <[EMAIL PROTECTED]>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package com.acme.crypto;
import java.io.*;
/// The DES encryption method.
// <P>
// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
// in com.acme.crypto.EncryptedOutputStream or com.acme.crypto.EncryptedInputStream,
// it does around 7000 bytes/second.
// <P>
// Most of this code is by Dave Zimmerman <[EMAIL PROTECTED]>, and is
// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
// <P>
// <A HREF="/resources/classes/com/acme/crypto/DesCipher.java">Fetch the
software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
// <P>
// @see Des3Cipher
// @see EncryptedOutputStream
// @see EncryptedInputStream
public class DesCipher extends BlockCipher
{
// Constructor, string key.
public DesCipher( String keyStr )
{
super( 8, 8 );
setKey( keyStr );
}
// Constructor, byte-array key.
public DesCipher( byte[] key )
{
super( 8, 8 );
setKey( key );
}
// Key routines.
private int[] encryptKeys = new int[32];
private int[] decryptKeys = new int[32];
/// Set the key.
public void setKey( byte[] key )
{
// Have to tweak the parity bits so that each byte has odd parity.
// This imposition of odd parity is required by the standard.
for ( int i = 0; i < 8; ++i )
if ( com.acme.Utils.even( com.acme.Utils.countOnes( key[i] ) ) )
key[i] ^= 0x80;
deskey( key, true, encryptKeys );
deskey( key, false, decryptKeys );
}
// Turn an 8-byte key into internal keys.
private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL )
{
int i, j, l, m, n;
int[] pc1m = new int[56];
int[] pcr = new int[56];
int[] kn = new int[32];
for ( j = 0; j < 56; ++j )
{
l = pc1[j];
m = l & 07;
pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0;
}
for ( i = 0; i < 16; ++i )
{
if ( encrypting )
m = i << 1;
else
m = (15-i) << 1;
n = m+1;
kn[m] = kn[n] = 0;
for ( j = 0; j < 28; ++j )
{
l = j+totrot[i];
if ( l < 28 )
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l-28];
}
for ( j=28; j < 56; ++j )
{
l = j+totrot[i];
if ( l < 56 )
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l-28];
}
for ( j = 0; j < 24; ++j )
{
if ( pcr[pc2[j]] != 0 )
kn[m] |= bigbyte[j];
if ( pcr[pc2[j+24]] != 0 )
kn[n] |= bigbyte[j];
}
}
cookey( kn, KnL );
}
private void cookey( int[] raw, int KnL[] )
{
int raw0, raw1;
int rawi, KnLi;
int i;
for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i )
{
raw0 = raw[rawi++];
raw1 = raw[rawi++];
KnL[KnLi] = (raw0 & 0x00fc0000) << 6;
KnL[KnLi] |= (raw0 & 0x00000fc0) << 10;
KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
++KnLi;
KnL[KnLi] = (raw0 & 0x0003f000) << 12;
KnL[KnLi] |= (raw0 & 0x0000003f) << 16;
KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4;
KnL[KnLi] |= (raw1 & 0x0000003f);
++KnLi;
}
}
// Block encryption routines.
private int[] tempInts = new int[2];
/// Encrypt a block of eight bytes.
public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int
cipherOff )
{
squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
des( tempInts, tempInts, encryptKeys );
spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
}
/// Decrypt a block of eight bytes.
public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int
clearOff )
{
squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
des( tempInts, tempInts, decryptKeys );
spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
}
// The DES function.
private void des( int[] inInts, int[] outInts, int[] keys )
{
int fval, work, right, leftt;
int round;
int keysi = 0;
leftt = inInts[0];
right = inInts[1];
work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >>> 16) ^ right) & 0x0000ffff;
right ^= work;
leftt ^= (work << 16);
work = ((right >>> 2) ^ leftt) & 0x33333333;
leftt ^= work;
right ^= (work << 2);
work = ((right >>> 8) ^ leftt) & 0x00ff00ff;
leftt ^= work;
right ^= (work << 8);
right = (right << 1) | ((right >>> 31) & 1);
work = (leftt ^ right) & 0xaaaaaaaa;
leftt ^= work;
right ^= work;
leftt = (leftt << 1) | ((leftt >>> 31) & 1);
for ( round = 0; round < 8; ++round )
{
work = (right << 28) | (right >>> 4);
work ^= keys[keysi++];
fval = SP7[ work & 0x0000003f ];
fval |= SP5[(work >>> 8) & 0x0000003f ];
fval |= SP3[(work >>> 16) & 0x0000003f ];
fval |= SP1[(work >>> 24) & 0x0000003f ];
work = right ^ keys[keysi++];
fval |= SP8[ work & 0x0000003f ];
fval |= SP6[(work >>> 8) & 0x0000003f ];
fval |= SP4[(work >>> 16) & 0x0000003f ];
fval |= SP2[(work >>> 24) & 0x0000003f ];
leftt ^= fval;
work = (leftt << 28) | (leftt >>> 4);
work ^= keys[keysi++];
fval = SP7[ work & 0x0000003f ];
fval |= SP5[(work >>> 8) & 0x0000003f ];
fval |= SP3[(work >>> 16) & 0x0000003f ];
fval |= SP1[(work >>> 24) & 0x0000003f ];
work = leftt ^ keys[keysi++];
fval |= SP8[ work & 0x0000003f ];
fval |= SP6[(work >>> 8) & 0x0000003f ];
fval |= SP4[(work >>> 16) & 0x0000003f ];
fval |= SP2[(work >>> 24) & 0x0000003f ];
right ^= fval;
}
right = (right << 31) | (right >>> 1);
work = (leftt ^ right) & 0xaaaaaaaa;
leftt ^= work;
right ^= work;
leftt = (leftt << 31) | (leftt >>> 1);
work = ((leftt >>> 8) ^ right) & 0x00ff00ff;
right ^= work;
leftt ^= (work << 8);
work = ((leftt >>> 2) ^ right) & 0x33333333;
right ^= work;
leftt ^= (work << 2);
work = ((right >>> 16) ^ leftt) & 0x0000ffff;
leftt ^= work;
right ^= (work << 16);
work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f;
leftt ^= work;
right ^= (work << 4);
outInts[0] = right;
outInts[1] = leftt;
}
// Tables, permutations, S-boxes, etc.
private static byte[] bytebit = {
(byte)0x80, (byte)0x40, (byte)0x20, (byte)0x10,
(byte)0x08, (byte)0x04, (byte)0x02, (byte)0x01
};
private static int[] bigbyte = {
0x800000, 0x400000, 0x200000, 0x100000,
0x080000, 0x040000, 0x020000, 0x010000,
0x008000, 0x004000, 0x002000, 0x001000,
0x000800, 0x000400, 0x000200, 0x000100,
0x000080, 0x000040, 0x000020, 0x000010,
0x000008, 0x000004, 0x000002, 0x000001
};
private static byte[] pc1 = {
(byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8,
(byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17,
(byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26,
(byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35,
(byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14,
(byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21,
(byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28,
(byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3
};
private static int[] totrot = {
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
};
private static byte[] pc2 = {
(byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4,
(byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9,
(byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7,
(byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1,
(byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54,
(byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47,
(byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52,
(byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,
};
private static int[] SP1 = {
0x01010400, 0x00000000, 0x00010000, 0x01010404,
0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400,
0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400,
0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004,
0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000,
0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004,
0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404,
0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000,
0x00010004, 0x00010400, 0x00000000, 0x01010004
};
private static int[] SP2 = {
0x80108020, 0x80008000, 0x00008000, 0x00108020,
0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000,
0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000,
0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000,
0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000,
0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020,
0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020,
0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020,
0x80000000, 0x80100020, 0x80108020, 0x00108000
};
private static int[] SP3 = {
0x00000208, 0x08020200, 0x00000000, 0x08020008,
0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000,
0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200,
0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208,
0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208,
0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200,
0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208,
0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000,
0x00020208, 0x00000008, 0x08020008, 0x00020200
};
private static int[] SP4 = {
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080,
0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001,
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000,
0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002000, 0x00802080
};
private static int[] SP5 = {
0x00000100, 0x02080100, 0x02080000, 0x42000100,
0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100,
0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000,
0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000,
0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000,
0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100,
0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100,
0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000,
0x00000000, 0x40080000, 0x02080100, 0x40000100
};
private static int[] SP6 = {
0x20000010, 0x20400000, 0x00004000, 0x20404010,
0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010,
0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000,
0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000,
0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000,
0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010,
0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010,
0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000,
0x20404000, 0x20000000, 0x00400010, 0x20004010
};
private static int[] SP7 = {
0x00200000, 0x04200002, 0x04000802, 0x00000000,
0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002,
0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800,
0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802,
0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802,
0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000,
0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000,
0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800,
0x04000002, 0x04000800, 0x00000800, 0x00200002
};
private static int[] SP8 = {
0x10001040, 0x00001000, 0x00040000, 0x10041040,
0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000,
0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040,
0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040,
0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000,
0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000,
0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040,
0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040,
0x00001040, 0x00040040, 0x10000000, 0x10041000
};
}
/****************************************************************
*
* CUT HERE
*
* com/acme/crypto/BlockCipher.java
*
****************************************************************/
// BlockCipher - a block encryption template
//
// Copyright (C) 1996 by Jef Poskanzer <[EMAIL PROTECTED]>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package com.acme.crypto;
import java.io.*;
/// A block encryption template.
// <P>
// <A HREF="/resources/classes/com/acme/crypto/BlockCipher.java">Fetch the
software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
// <P>
// @see Cipher
// @see StreamCipher
// @see EncryptedOutputStream
// @see EncryptedInputStream
// @see DesCipher
// @see CbcBlockCipher
public abstract class BlockCipher extends Cipher
{
/// Constructor.
public BlockCipher( int keySize, int blockSize )
{
super( keySize );
this.blockSize = blockSize;
}
/// How big a block is.
public int blockSize;
/// Return how big a block is.
public int blockSize()
{
return blockSize;
}
/// Encrypt a block of bytes.
public abstract void encrypt( byte[] clearText, int clearOff, byte[] cipherText,
int cipherOff );
/// Decrypt a block of bytes.
public abstract void decrypt( byte[] cipherText, int cipherOff, byte[] clearText,
int clearOff );
/// Encrypt a block of bytes.
public void encrypt( byte[] clearText, byte[] cipherText )
{
encrypt( clearText, 0, cipherText, 0 );
}
/// Decrypt a block of bytes.
public void decrypt( byte[] cipherText, byte[] clearText )
{
decrypt( cipherText, 0, clearText, 0 );
}
}
/****************************************************************
*
* CUT HERE
*
* com/acme/crypto/Cipher.java
*
****************************************************************/
// Cipher - an encryption template
//
// Copyright (C) 1996 by Jef Poskanzer <[EMAIL PROTECTED]>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package com.acme.crypto;
import java.io.*;
/// An encryption template.
// <P>
// <A HREF="/resources/classes/com/acme/crypto/Cipher.java">Fetch the software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
// <P>
// @see StreamCipher
// @see BlockCipher
// @see EncryptedOutputStream
// @see EncryptedInputStream
public abstract class Cipher extends CryptoUtils
{
/// Constructor.
public Cipher( int keySize )
{
this.keySize = keySize;
}
/// How big a key is. Keyless ciphers use 0. Variable-length-key ciphers
// also use 0.
public int keySize;
/// Return how big a key is.
public int keySize()
{
return keySize;
}
/// Set the key from a block of bytes.
public abstract void setKey( byte[] key );
// Utility routines.
/// Utility routine to set the key from a string.
public void setKey( String keyStr )
{
setKey( makeKey( keyStr ) );
}
/// Utility routine to turn a string into a key of the right length.
public byte[] makeKey( String keyStr )
{
byte[] key;
if ( keySize == 0 )
key = new byte[keyStr.length()];
else
key = new byte[keySize];
int i, j;
for ( j = 0; j < key.length; ++j )
key[j] = 0;
for ( i = 0, j = 0; i < keyStr.length(); ++i, j = (j+1) % key.length )
key[j] ^= (byte) keyStr.charAt( i );
return key;
}
}
/****************************************************************
*
* CUT HERE
*
* com/acme/crypto/CryptoUtils.java
*
****************************************************************/
// CryptoUtils - some cryptography utilities
//
// Copyright (C) 1996 by Jef Poskanzer <[EMAIL PROTECTED]>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package com.acme.crypto;
import java.io.*;
/// Some cryptography utilities.
// <P>
// These are static methods used by a lot of the cryptography classes.
// Most of them operate on byte arrays, which we call blocks.
// They could be encapsulated in a "Block" class, but that would
// mean a big efficiency hit - method calls are a lot more
// expensive than array accesses.
// <P>
// <A HREF="/resources/classes/com/acme/crypto/CryptoUtils.java">Fetch the
software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
public class CryptoUtils
{
/// Utility routine to fill a block with zeros.
public static void zeroBlock( byte[] block, int off, int len )
{
for ( int i = off; i < off + len; ++i )
block[i] = 0;
}
/// Utility routine to fill a block with zeros.
public static void zeroBlock( byte[] block )
{
zeroBlock( block, 0, block.length );
}
/// Utility routine to fill a block with random bytes.
public static void randomBlock( byte[] block, int off, int len )
{
for ( int i = off; i < off + len; ++i )
block[i] = (byte) ( Math.random() * 256.0 );
}
/// Utility routine to fill a block with random bytes.
public static void randomBlock( byte[] block )
{
randomBlock( block, 0, block.length );
}
/// Utility routine to XOR two blocks.
public static void xorBlock( byte[] a, int aOff, byte[] b, int bOff, byte[] dst,
int dstOff, int len )
{
for ( int i = 0; i < len; ++i )
dst[dstOff + i] = (byte) ( a[aOff + i] ^ b[bOff + i] );
}
/// Utility routine to XOR two blocks.
public static void xorBlock( byte[] a, byte[] b, byte[] dst )
{
xorBlock( a, 0, b, 0, dst, 0, a.length );
}
/// Utility routine to copy one block to another.
public static void copyBlock( byte[] src, int srcOff, byte[] dst, int dstOff, int
len )
{
for ( int i = 0; i < len; ++i )
dst[dstOff + i] = src[srcOff + i];
}
/// Utility routine to copy one block to another.
public static void copyBlock( byte[] src, byte[] dst )
{
copyBlock( src, 0, dst, 0, src.length );
}
/// Utility routine to check two blocks for equality.
public static boolean equalsBlock( byte[] a, int aOff, byte[] b, int bOff, int len
)
{
for ( int i = 0; i < len; ++i )
if ( a[aOff + i] != b[bOff + i] )
return false;
return true;
}
/// Utility routine to check two blocks for equality.
public static boolean equalsBlock( byte[] a, byte[] b )
{
return equalsBlock( a, 0, b, 0, a.length );
}
/// Utility routine fill a block with a given byte.
public static void fillBlock( byte[] block, int blockOff, byte b, int len )
{
for ( int i = blockOff; i < blockOff + len; ++i )
block[i] = b;
}
/// Utility routine fill a block with a given byte.
public static void fillBlock( byte[] block, byte b )
{
fillBlock( block, 0, b, block.length );
}
/// Squash bytes down to ints.
public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts,
int outOff, int intLen )
{
for ( int i = 0; i < intLen; ++i )
outInts[outOff + i] =
( ( inBytes[inOff + i * 4 ] & 0xff ) << 24 ) |
( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) |
( ( inBytes[inOff + i * 4 + 2] & 0xff ) << 8 ) |
( inBytes[inOff + i * 4 + 3] & 0xff );
}
/// Spread ints into bytes.
public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes,
int outOff, int intLen )
{
for ( int i = 0; i < intLen; ++i )
{
outBytes[outOff + i * 4 ] = (byte) ( inInts[inOff + i] >>> 24 );
outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 );
outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>> 8 );
outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i];
}
}
/// Squash bytes down to shorts.
public static void squashBytesToShorts( byte[] inBytes, int inOff, int[]
outShorts, int outOff, int shortLen )
{
for ( int i = 0; i < shortLen; ++i )
outShorts[outOff + i] =
( ( inBytes[inOff + i * 2 ] & 0xff ) << 8 ) |
( inBytes[inOff + i * 2 + 1] & 0xff );
}
/// Spread shorts into bytes.
public static void spreadShortsToBytes( int[] inShorts, int inOff, byte[]
outBytes, int outOff, int shortLen )
{
for ( int i = 0; i < shortLen; ++i )
{
outBytes[outOff + i * 2 ] = (byte) ( inShorts[inOff + i] >>> 8 );
outBytes[outOff + i * 2 + 1] = (byte) inShorts[inOff + i];
}
}
/// Convert a block to a String representation.
public static String toStringBlock( byte[] block, int off, int len )
{
String hexits = "0123456789abcdef";
StringBuffer buf = new StringBuffer();
for ( int i = off; i < off + len; ++i )
{
buf.append( hexits.charAt( ( block[i] >>> 4 ) & 0xf ) );
buf.append( hexits.charAt( block[i] & 0xf ) );
}
return "[" + buf + "]";
}
/// Convert a block to a String representation.
public static String toStringBlock( byte[] block )
{
return toStringBlock( block, 0, block.length );
}
}
/****************************************************************
*
* CUT HERE
*
* com/acme/crypto/Utils.java
*
****************************************************************/
// Utils - assorted static utility routines
//
// Copyright (C)1996,1998 by Jef Poskanzer <[EMAIL PROTECTED]>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package com.acme;
import java.util.*;
import java.io.*;
import java.net.*;
/// Assorted static utility routines.
// <P>
// Whenever I come up with a static routine that might be of general use,
// I put it here. So far the class includes:
// <UL>
// <LI> some string routines that were left out of java.lang.String
// <LI> a general array-to-string routine
// <LI> a fixed version of java.io.InputStream's byte-array read routine
// <LI> a bunch of URL-hacking routines
// <LI> some easy-to-use wrappers for Runtime.exec
// <LI> a debugging routine to dump the current call stack
// <LI> a URLDecoder to match java.net.URLEncoder
// </UL>
// and lots more.
// <P>
// <A HREF="/resources/classes/Acme/Utils.java">Fetch the software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
public class Utils
{
/// Returns a date string formatted in Unix ls style - if it's within
// six months of now, Mmm dd hh:ss, else Mmm dd yyyy.
public static String lsDateStr( Date date )
{
Calendar cal = new GregorianCalendar();
cal.setTime( date );
long dateTime = date.getTime();
if ( dateTime == -1L )
return "------------";
long nowTime = (new Date()).getTime();
String[] months = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
String part1 =
months[cal.get(Calendar.MONTH)] +
Fmt.fmt( cal.get(Calendar.DATE), 3 );
if ( Math.abs( nowTime - dateTime ) < 183L * 24L * 60L * 60L * 1000L )
return part1 + Fmt.fmt( cal.get(Calendar.HOUR_OF_DAY), 3 ) + ":" +
Fmt.fmt( cal.get(Calendar.MINUTE), 2, Fmt.ZF );
else
return part1 + Fmt.fmt( cal.get(Calendar.YEAR), 6 );
}
/// Returns "s" for numbers other than one, and "" for one.
public static String pluralStr( long n )
{
if ( n == 1 )
return "";
else
return "s";
}
// Various interval constants. Some are only approximate.
public static final long INT_SECOND = 1000L;
public static final long INT_MINUTE = INT_SECOND * 60L;
public static final long INT_HOUR = INT_MINUTE * 60L;
public static final long INT_DAY = INT_HOUR * 24L;
public static final long INT_WEEK = INT_DAY * 7L;
public static final long INT_MONTH = INT_DAY * 30L;
public static final long INT_YEAR = INT_DAY * 365L;
public static final long INT_DECADE = INT_DAY * 3652L;
/// Returns a string approximately describing a given time interval.
// @param interval the interval, in milliseconds
public static String intervalStr( long interval )
{
long decades, years, months, weeks, days, hours, minutes, seconds, millis;
decades = interval / INT_DECADE;
interval -= decades * INT_DECADE;
years = interval / INT_YEAR;
interval -= years * INT_YEAR;
months = interval / INT_MONTH;
interval -= months * INT_MONTH;
weeks = interval / INT_WEEK;
interval -= weeks * INT_WEEK;
days = interval / INT_DAY;
interval -= days * INT_DAY;
hours = interval / INT_HOUR;
interval -= hours * INT_HOUR;
minutes = interval / INT_MINUTE;
interval -= minutes * INT_MINUTE;
seconds = interval / INT_SECOND;
interval -= seconds * INT_SECOND;
millis = interval;
if ( decades > 0 )
if ( years == 0 )
return decades + " decade" + pluralStr( decades );
else
return
decades + " decade" + pluralStr( decades ) + ", " +
years + " years" + pluralStr( years );
else if ( years > 0 )
if ( months == 0 )
return years + " year" + pluralStr( years );
else
return
years + " year" + pluralStr( years ) + ", " +
months + " month" + pluralStr( months );
else if ( months > 0 )
if ( weeks == 0 )
return months + " month" + pluralStr( months );
else
return
months + " month" + pluralStr( months ) + ", " +
weeks + " week" + pluralStr( weeks );
else if ( weeks > 0 )
if ( days == 0 )
return weeks + " week" + pluralStr( weeks );
else
return
weeks + " week" + pluralStr( weeks ) + ", " +
days + " day" + pluralStr( days );
else if ( days > 0 )
if ( hours == 0 )
return days + " day" + pluralStr( days );
else
return
days + " day" + pluralStr( days ) + ", " +
hours + " hour" + pluralStr( hours );
else if ( hours > 0 )
if ( minutes == 0 )
return hours + " hour" + pluralStr( hours );
else
return
hours + " hour" + pluralStr( hours ) + ", " +
minutes + " minute" + pluralStr( minutes );
else if ( minutes > 0 )
if ( seconds == 0 )
return minutes + " minute" + pluralStr( minutes );
else
return
minutes + " minute" + pluralStr( minutes ) + ", " +
seconds + " second" + pluralStr( seconds );
else if ( seconds > 0 )
if ( millis == 0 )
return seconds + " second" + pluralStr( seconds );
else
return
seconds + " second" + pluralStr( seconds ) + ", " +
millis + " millisecond" + pluralStr( millis );
else
return millis + " millisecond" + pluralStr( millis );
}
/// Returns the length of the initial segment of str which consists
// entirely of characters from charSet.
public static int strSpan( String str, String charSet )
{
return strSpan( str, charSet, 0 );
}
/// Returns the length of the initial segment of str which consists
// entirely of characters from charSet, starting at the given index.
public static int strSpan( String str, String charSet, int fromIdx )
{
int i;
for ( i = fromIdx; i < str.length(); ++i )
if ( charSet.indexOf( str.charAt( i ) ) == -1 )
break;
return i - fromIdx;
}
/// Returns the length of the initial segment of str which consists
// entirely of characters NOT from charSet.
public static int strCSpan( String str, String charSet )
{
return strCSpan( str, charSet, 0 );
}
/// Returns the length of the initial segment of str which consists
// entirely of characters NOT from charSet, starting at the given index.
public static int strCSpan( String str, String charSet, int fromIdx )
{
int i;
for ( i = fromIdx; i < str.length(); ++i )
if ( charSet.indexOf( str.charAt( i ) ) != -1 )
break;
return i - fromIdx;
}
/// Checks whether a string matches a given wildcard pattern.
// Only does ? and *, and multiple patterns separated by |.
public static boolean match( String pattern, String string )
{
for ( int p = 0; ; ++p )
{
for ( int s = 0; ; ++p, ++s )
{
boolean sEnd = ( s >= string.length() );
boolean pEnd = ( p >= pattern.length() ||
pattern.charAt( p ) == '|' );
if ( sEnd && pEnd )
return true;
if ( sEnd || pEnd )
break;
if ( pattern.charAt( p ) == '?' )
continue;
if ( pattern.charAt( p ) == '*' )
{
int i;
++p;
for ( i = string.length(); i >= s; --i )
if ( match(
pattern.substring( p ),
string.substring( i ) ) ) /* not quite right */
return true;
break;
}
if ( pattern.charAt( p ) != string.charAt( s ) )
break;
}
p = pattern.indexOf( '|', p );
if ( p == -1 )
return false;
}
}
// /// Finds the maximum length of a string that matches a given wildcard
// // pattern. Only does ? and *, and multiple patterns separated by |.
// public static int matchSpan( String pattern, String string )
// {
// // !!!
// return 0;
// }
/// Returns the length of the initial segment of str1 that equals str2.
public static int sameSpan( String str1, String str2 )
{
int i;
for ( i = 0;
i < str1.length() && i < str2.length() &&
str1.charAt( i ) == str2.charAt( i );
++i )
;
return i;
}
/// Returns the number of times the given character appears in the string.
public static int charCount( String str, char c )
{
int n = 0;
for ( int i = 0; i < str.length(); ++i )
if ( str.charAt( i ) == c )
++n;
return n;
}
/// Turns a String into an array of Strings, by using StringTokenizer
// to split it up at whitespace.
public static String[] splitStr( String str )
{
StringTokenizer st = new StringTokenizer( str );
int n = st.countTokens();
String[] strs = new String[n];
for ( int i = 0; i < n; ++i )
strs[i] = st.nextToken();
return strs;
}
/// Turns a String into an array of Strings, by splitting it at
// the specified character. This does not use StringTokenizer,
// and therefore can handle empty fields.
public static String[] splitStr( String str, char delim )
{
int n = 1;
int index = -1;
while ( true )
{
index = str.indexOf( delim, index + 1 );
if ( index == -1 )
break;
++n;
}
String[] strs = new String[n];
index = -1;
for ( int i = 0; i < n - 1; ++i )
{
int nextIndex = str.indexOf( delim, index + 1 );
strs[i] = str.substring( index + 1, nextIndex );
index = nextIndex;
}
strs[n - 1] = str.substring( index + 1 );
return strs;
}
/// Turns an array of Strings into a single String, with the components
// separated by spaces.
public static String flattenStrarr( String[] strs )
{
StringBuffer sb = new StringBuffer();
for ( int i = 0; i < strs.length; ++i )
{
if ( i > 0 )
sb.append( ' ' );
sb.append( strs[i] );
}
return sb.toString();
}
/// Sorts an array of Strings.
// Java currently has no general sort function. Sorting Strings is
// common enough that it's worth making a special case.
public static void sortStrings( String[] strings )
{
// Just does a bubblesort.
for ( int i = 0; i < strings.length - 1; ++i )
{
for ( int j = i + 1; j < strings.length; ++j )
{
if ( strings[i].compareTo( strings[j] ) > 0 )
{
String t = strings[i];
strings[i] = strings[j];
strings[j] = t;
}
}
}
}
/// Locates a String in an array of Strings.
// Returns -1 if the String is not found.
public static int indexOfString( String[] strings, String string )
{
for ( int i = 0; i < strings.length; ++i )
if ( string.equals( strings[i] ) )
return i;
return -1;
}
/// Locates a String in an array of Strings, ignoring case.
// Returns -1 if the String is not found.
public static int indexOfStringIgnoreCase( String[] strings, String string )
{
for ( int i = 0; i < strings.length; ++i )
if ( string.equalsIgnoreCase( strings[i] ) )
return i;
return -1;
}
/// Compares two arrays of Strings for equality.
public static boolean equalsStrings( String[] strings1, String[] strings2 )
{
if ( strings1.length != strings2.length )
return false;
for ( int i = 0; i < strings1.length; ++i )
if ( ! strings1[i].equals( strings2[i] ) )
return false;
return true;
}
/// Returns the number a raised to the power of b. Long version
// of Math.pow(). Throws ArithmeticException if b is negative.
public static long pow( long a, long b ) throws ArithmeticException
{
if ( b < 0 )
throw new ArithmeticException();
long r = 1;
while ( b != 0 )
{
if ( odd( b ) )
r *= a;
b >>>= 1;
a *= a;
}
return r;
}
/// Parse an integer, returning a default value on errors.
public static int parseInt( String str, int def )
{
try
{
return Integer.parseInt( str );
}
catch ( Exception e )
{
return def;
}
}
/// Parse a long, returning a default value on errors.
public static long parseLong( String str, long def )
{
try
{
return Long.parseLong( str );
}
catch ( Exception e )
{
return def;
}
}
/// An array-to-String routine. Handles arrays of arbitrary
// type, including nested arrays. Sample output:
// <BLOCKQUOTE><CODE><PRE>
// byte[]: { (byte)0, (byte)1, (byte)2 }
// char[]: { '0', '1', '2' }
// short[]: { (short)0, (short)1, (short)2 }
// int[]: { 0, 1, 2 }
// long[]: { 0L, 1L, 2L }
// float[]: { 0F, 1F, 2F }
// double[]: { 0D, 1D, 2D }
// String[]: { "0", "1", "2" }
// int[][]: { { 0, 1, 2 }, { 3, 4, 5 } }
// </PRE></CODE></BLOCKQUOTE>
public static String arrayToString( Object o )
{
if ( o == null )
return "null";
String cl = o.getClass().getName();
if ( ! cl.startsWith( "[" ) )
// It's not an array; just call its toString method.
return o.toString();
StringBuffer sb = new StringBuffer( "{ " );
if ( o instanceof byte[] )
{
byte[] ba = (byte[]) o;
for ( int i = 0; i < ba.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( "(byte)" );
sb.append( ba[i] );
}
}
else if ( o instanceof char[] )
{
char[] ca = (char[]) o;
for ( int i = 0; i < ca.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( "'" );
sb.append( ca[i] );
sb.append( "'" );
}
}
else if ( o instanceof short[] )
{
short[] sa = (short[]) o;
for ( int i = 0; i < sa.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( "(short)" );
sb.append( sa[i] );
}
}
else if ( o instanceof int[] )
{
int[] ia = (int[]) o;
for ( int i = 0; i < ia.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( ia[i] );
}
}
else if ( o instanceof long[] )
{
long[] la = (long[]) o;
for ( int i = 0; i < la.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( la[i] );
sb.append( "L" );
}
}
else if ( o instanceof float[] )
{
float[] fa = (float[]) o;
for ( int i = 0; i < fa.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( fa[i] );
sb.append( "F" );
}
}
else if ( o instanceof double[] )
{
double[] da = (double[]) o;
for ( int i = 0; i < da.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( da[i] );
sb.append( "D" );
}
}
else if ( o instanceof String )
{
// Special-case Strings so we can surround them with quotes.
String[] sa = (String[]) o;
for ( int i = 0; i < sa.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( "\"" );
sb.append( sa[i] );
sb.append( "\"" );
}
}
else if ( cl.startsWith( "[L" ) )
{
// Some random class.
Object[] oa = (Object[]) o;
for ( int i = 0; i < oa.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( oa[i] );
}
}
else if ( cl.startsWith( "[[" ) )
{
// Nested arrays.
Object[] aa = (Object[]) o;
for ( int i = 0; i < aa.length; ++i )
{
if ( i > 0 ) sb.append( ", " );
sb.append( arrayToString( aa[i] ) );
}
}
else
sb.append( "(unknown array type)" );
sb.append( " }" );
return sb.toString();
}
/// Check if an object extends a given class or one of its superclasses.
// An instanceof that works on Class objects at runtime, instead
// of type descriptors at compile time.
public static boolean instanceOf( Object o, Class cl )
{
// Null check.
if ( o == null || cl == null )
return false;
Class ocl = o.getClass();
// Check if they are the same class.
if ( ocl.equals( cl ) )
return true;
// If the class is not itself an interface, then check its interfaces.
if ( ! cl.isInterface() )
{
Class ifs[] = cl.getInterfaces();
for ( int i = 0; i < ifs.length; ++i )
if ( instanceOf( o, ifs[i] ) )
return true;
}
// And check supeclasses.
Class scl = cl.getSuperclass();
if ( scl != null )
if ( instanceOf( o, scl ) )
return true;
// Guess not.
return false;
}
/// Test is a number is even.
public static boolean even( long n )
{
return ( n & 1 ) == 0;
}
/// Test is a number is odd.
public static boolean odd( long n )
{
return ( n & 1 ) != 0;
}
/// Count the number of 1-bits in a byte.
public static int countOnes( byte n )
{
return countOnes( n & 0xffL );
}
/// Count the number of 1-bits in an int.
public static int countOnes( int n )
{
return countOnes( n & 0xffffffffL );
}
/// Count the number of 1-bits in a long.
public static int countOnes( long n )
{
// There are faster ways to do this, all the way up to looking
// up bytes in a 256-element table. But this is not too bad.
int count = 0;
while ( n != 0 )
{
if ( odd( n ) )
++count;
n >>>= 1;
}
return count;
}
/// A fixed version of java.io.InputStream.read(byte[], int, int). The
// standard version catches and ignores IOExceptions from below.
// This version sends them on to the caller.
public static int read( InputStream in, byte[] b, int off, int len ) throws
IOException
{
if ( len <= 0 )
return 0;
int c = in.read();
if ( c == -1 )
return -1;
if ( b != null )
b[off] = (byte) c;
int i;
for ( i = 1; i < len ; ++i )
{
c = in.read();
if ( c == -1 )
break;
if ( b != null )
b[off + i] = (byte) c;
}
return i;
}
/// A version of read that reads the entire requested block, instead
// of sometimes terminating early.
// @return -1 on EOF, otherwise len
public static int readFully( InputStream in, byte[] b, int off, int len ) throws
IOException
{
int l, r;
for ( l = 0; l < len; )
{
r = read( in, b, l, len - l );
if ( r == -1 )
return -1;
l += r;
}
return len;
}
/// Make a URL with no ref part and no query string. Also, if it's
// a directory then make sure there's a trailing slash.
public static URL plainUrl( URL context, String urlStr ) throws
MalformedURLException
{
URL url = new URL( context, urlStr );
String fileStr = url.getFile();
int i = fileStr.indexOf( '?' );
if ( i != -1 )
fileStr = fileStr.substring( 0, i );
url = new URL(
url.getProtocol(), url.getHost(), url.getPort(), fileStr );
if ( ( ! fileStr.endsWith( "/" ) ) &&
urlStrIsDir( url.toExternalForm() ) )
{
fileStr = fileStr + "/";
url = new URL(
url.getProtocol(), url.getHost(), url.getPort(), fileStr );
}
return url;
}
/// Make a URL with no ref part and no query string. Also, if it's
// a directory then make sure there's a trailing slash.
public static URL plainUrl( String urlStr ) throws MalformedURLException
{
return plainUrl( null, urlStr );
}
/// Figure out the base URL for a given URL. What this means is
// if the URL points to a directory, you get that directory; if the
// URL points to a file, you get the directory the file is in.
public static String baseUrlStr( String urlStr )
{
if ( urlStr.endsWith( "/" ) )
return urlStr;
if ( urlStrIsDir( urlStr ) )
return urlStr + "/";
return urlStr.substring( 0, urlStr.lastIndexOf( '/' ) + 1 );
}
/// Makes sure if a URL is a directory, it ends with a slash.
public static String fixDirUrlStr( String urlStr )
{
if ( urlStr.endsWith( "/" ) )
return urlStr;
if ( urlStrIsDir( urlStr ) )
return urlStr + "/";
return urlStr;
}
/// Figures out whether a URL points to a directory or not.
// Web servers are lenient and accept directory-URLs without
// the trailing slash. What they actually do is return a
// redirect to the same URL with the trailing slash appended.
// Unfortunately, Java doesn't let us see that such a redirect
// happened. Instead we have to figure out it's a directory
// indirectly and heuristically.
public static boolean urlStrIsDir( String urlStr )
{
// If it ends with a slash, it's probably a directory.
if ( urlStr.endsWith( "/" ) )
return true;
// If the last component has a dot, it's probably not a directory.
int lastSlash = urlStr.lastIndexOf( '/' );
int lastPeriod = urlStr.lastIndexOf( '.' );
if ( lastPeriod != -1 && ( lastSlash == -1 || lastPeriod > lastSlash ) )
return false;
// Otherwise, append a slash and try to connect. This is
// fairly expensive.
String urlStrWithSlash = urlStr + "/";
try
{
URL url = new URL( urlStrWithSlash );
InputStream f = url.openStream();
f.close();
// Worked fine - it's probably a directory.
return true;
}
catch ( Exception e )
{
// Got an error - must not be a directory.
return false;
}
}
// Figures out whether a URL is absolute or not.
public static boolean urlStrIsAbsolute( String urlStr )
{
if ( urlStr.startsWith( "/" ) || urlStr.indexOf( ":/" ) != -1 )
return true;
// Should handle :8000/ and such too.
return false;
}
// Returns an equivalent URL string that is guaranteed to be absolute.
public static String absoluteUrlStr( String urlStr, URL contextUrl ) throws
MalformedURLException
{
URL url = new URL( contextUrl, urlStr );
return url.toExternalForm();
}
/// URLDecoder to go along with java.net.URLEncoder. Why there isn't
// already a decoder in the standard library is a mystery to me.
public static String urlDecoder( String encoded )
{
StringBuffer decoded = new StringBuffer();
int len = encoded.length();
for ( int i = 0; i < len; ++i )
{
if ( encoded.charAt( i ) == '%' && i + 2 < len )
{
int d1 = Character.digit( encoded.charAt( i + 1 ), 16 );
int d2 = Character.digit( encoded.charAt( i + 2 ), 16 );
if ( d1 != -1 && d2 != -1 )
decoded.append( (char) ( ( d1 << 4 ) + d2 ) );
i += 2;
}
else if ( encoded.charAt( i ) == '+' )
decoded.append( ' ' );
else
decoded.append( encoded.charAt( i ) );
}
return decoded.toString();
}
/// A base-64 encoder, necessary for doing the client side of Basic
// Authentication. This encodes binary data as printable ASCII
// characters. Three 8-bit binary bytes are turned into four 6-bit
// values, like so:
//
// [11111111] [22222222] [33333333]
//
// [111111] [112222] [222233] [333333]
//
// Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
public static String base64Encode( byte[] src )
{
StringBuffer encoded = new StringBuffer();
int i, phase = 0;
char c = 0;
for ( i = 0; i < src.length; ++i )
{
switch ( phase )
{
case 0:
c = b64EncodeTable[( src[i] >> 2 ) & 0x3f];
encoded.append( c );
c = b64EncodeTable[( src[i] & 0x3 ) << 4];
encoded.append( c );
++phase;
break;
case 1:
c = b64EncodeTable[
( b64DecodeTable[c] | ( src[i] >> 4 ) ) & 0x3f];
encoded.setCharAt( encoded.length() - 1, c );
c = b64EncodeTable[( src[i] & 0xf ) << 2];
encoded.append( c );
++phase;
break;
case 2:
c = b64EncodeTable[
( b64DecodeTable[c] | ( src[i] >> 6 ) ) & 0x3f];
encoded.setCharAt( encoded.length() - 1, c );
c = b64EncodeTable[src[i] & 0x3f];
encoded.append( c );
phase = 0;
break;
}
}
/* Pad with ='s. */
while ( phase++ < 3 )
encoded.append( '=' );
return encoded.toString();
}
private static char b64EncodeTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 00-07
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 08-15
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16-23
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24-31
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32-39
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40-47
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48-55
'4', '5', '6', '7', '8', '9', '+', '/' // 56-63
};
private static int b64DecodeTable[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0F
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1F
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, // 20-2F
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, // 30-3F
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, // 40-4F
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, // 50-5F
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, // 60-6F
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, // 70-7F
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 80-8F
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 90-9F
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // A0-AF
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // B0-BF
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // C0-CF
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // D0-DF
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // E0-EF
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // F0-FF
};
/// A base-64 encoder that takes a String, for convenience.
public static String base64Encode( String srcString )
{
byte[] src;
src = srcString.getBytes();
return base64Encode( src );
}
/// Check if an array contains a given element.
public static boolean arraycontains( Object[] array, Object element )
{
for ( int i = 0; i < array.length; ++i )
if ( array[i].equals( element ) )
return true;
return false;
}
/// Run a program on the host system.
// <P>
// This routine runs the specified command, waits for it to
// finish, and returns the exit status.
// This is like the Unix system() routine. Unlike the Unix version,
// though, stdout and stderr get thrown away unless you redirect them.
public static int system( String cmd )
{
try
{
return runCommand( cmd ).waitFor();
}
catch ( IOException e )
{
return -1;
}
catch ( InterruptedException e )
{
return -1;
}
}
/// Run a program on the host system, and capture the output.
// <P>
// This routine runs the specified command, and returns an InputStream
// for reading the output of the program.
// <P>
// <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
// IO routines, such that reading all the way to the end of a process's
// output will invariably get you an IOException( "read error" ).
// In some cases you will also <B>lose</B> the last bufferload of
// the output. The workaround is to add a " ; sleep 1" to the end of
// your command, and to ignore the "read error" IOException.
public static InputStream popenr( String cmd )
{
try
{
return runCommand( cmd ).getInputStream();
}
catch ( IOException e )
{
return null;
}
}
/// Run a program on the host system, and send it some input.
// <P>
// This routine runs the specified command, and returns an OutputStream
// for writing the program's input.
public static OutputStream popenw( String cmd )
{
try
{
return runCommand( cmd ).getOutputStream();
}
catch ( IOException e )
{
return null;
}
}
/// Run a program on the host system.
// <P>
// This routine runs the specified command, and returns a Process
// object so you can do what you like with it.
// <P>
// <B>WARNING:</B> In JDK1.0.2 there is a serious bug in the process
// IO routines, such that reading all the way to the end of a process's
// output will invariably get you an IOException( "read error" ).
// In some cases you will also <B>lose</B> the last bufferload of
// the output. The workaround is to add a " ; sleep 1" to the end of
// your command, and to ignore the "read error" IOException.
public static Process runCommand( String cmd ) throws IOException
{
Runtime runtime = Runtime.getRuntime();
String[] shCmd = new String[3];
shCmd[0] = "/bin/sh";
shCmd[1] = "-c";
shCmd[2] = cmd;
return runtime.exec( shCmd );
}
/// Copy the input to the output until EOF.
public static void copyStream( InputStream in, OutputStream out ) throws
IOException
{
byte[] buf = new byte[4096];
int len;
while ( ( len = in.read( buf ) ) != -1 )
out.write( buf, 0, len );
}
/// Copy the input to the output until EOF.
public static void copyStream( Reader in, Writer out ) throws IOException
{
char[] buf = new char[4096];
int len;
while ( ( len = in.read( buf ) ) != -1 )
out.write( buf, 0, len );
}
/// Copy the input to the output until EOF.
public static void copyStream( InputStream in, Writer out ) throws IOException
{
byte[] buf1 = new byte[4096];
char[] buf2 = new char[4096];
int len, i;
while ( ( len = in.read( buf1 ) ) != -1 )
{
for ( i = 0; i < len; ++i )
buf2[i] = (char) buf1[i];
out.write( buf2, 0, len );
}
}
/// Copy the input to the output until EOF.
public static void copyStream( Reader in, OutputStream out ) throws IOException
{
char[] buf1 = new char[4096];
byte[] buf2 = new byte[4096];
int len, i;
while ( ( len = in.read( buf1 ) ) != -1 )
{
for ( i = 0; i < len; ++i )
buf2[i] = (byte) buf1[i];
out.write( buf2, 0, len );
}
}
/// Dump out the current call stack.
public static void dumpStack( PrintStream p )
{
(new Throwable()).printStackTrace( p );
}
/// Dump out the current call stack onto System.err.
public static void dumpStack()
{
(new Throwable()).printStackTrace();
}
}
_________________________________________________________________________
For help in using, subscribing, and unsubscribing to the discussion
forums, please go to: http://www.netdynamics.com/support/visitdevfor.html
For dire need help, email: [EMAIL PROTECTED]