这一篇的内容是一个简单的对字符串加解密的类:
Then call its encrypt or decrypt method with an authenticator byte array (the parameter Auth which is a 16 octet byte array) and the data which is wanted to be encoded or decoded, the result is a byte array you wanted.
package org.kyle.util;
import java.security.*;
import java.io.*;
import java.text.*;
import java.util.*;
import java.math.*;
/* Call the shared secret S and the pseudo-random 128-bit
Authenticator RA. Break the password into 16-octet chunks p1, p2,
etc. with the last one padded at the end with nulls to a 16-octet
boundary. Call the ciphertext blocks c(1), c(2), etc. We'll need
intermediate values b1, b2, etc.
b1 = MD5(S + RA) c(1) = p1 xor b1
b2 = MD5(S + c(1)) c(2) = p2 xor b2
. .
. .
. .
bi = MD5(S + c(i-1)) c(i) = pi xor bi
The String will contain c(1)+c(2)+...+c(i) where + denotes
concatenation.
On receipt, the process is reversed to yield the original
password.
*/
public class Cryptology
{
/** hidden secret data for encryption and decryption. */
private byte[] m_secret;
/** default secret length. */
private int m_defaultSecretLength = 256;
/**
* Default constructor to create object with default hidden secret.
*/
public Cryptology()
{
m_secret = createSecret( m_defaultSecretLength, normalize( getClass().getName() ) );
}
/**
* Allow to use user desired hidden secret to instantiate this object.
* @param specSecret the user desired hidden secret string.
* @param secretLen the length of secret in bytes.
*/
public Cryptology( String specSecret, int secretLen )
{
if ( specSecret == null )
specSecret = getClass().getName();
m_secret = createSecret( secretLen, normalize( specSecret ) );
}
/**
* Set a new Shared Secret for encryption and decryption.
* @param newSecret byte[] the new shared secret.
*/
public void setSecret( byte[] newSecret )
{
m_secret = newSecret;
}
/**
* Set a string for shared secret.
*/
public void setSecret( String theSecret )
{
m_secret = normalize( theSecret );
}
public byte[] getSecret()
{
return m_secret;
}
/**
Encrypting the rawData with random auth value.
*/
public byte[] encrypt(byte[] rawData, byte[] auth)
{
//if no secret or no authenticator data, don't encrypt the rawData.
if ( rawData == null ||
auth == null ||
auth.length != 16 ||
m_secret == null )
return rawData;
ArrayList cBlocks = getCipherBlocks( getChunks( rawData ), auth, true );
return concatChunks( cBlocks );
}
/**
Decoding the encoded data ( encData ) with given authenticator array ( auth ). The result is the byte array of plain value.
*/
public byte[] decrypt(byte[] encData, byte[] auth)
{
//if no secret or no authenticator data, don't decrypt the encData.
if ( encData == null ||
auth == null ||
auth.length != 16 ||
m_secret == null )
return encData;
ArrayList cBlocks = getCipherBlocks( getChunks( encData ), auth, false );
return concatChunks( cBlocks );
}
/**
* Data to be encrypted should be normalized to multiple 16 octets first.
* Origin string should be encoded to bytes in UTF-8. If UTF-8 not supported, * null will be returned.
*/
public static byte[] normalize( String wData )
{
try
{
byte oData[] = wData.getBytes("UTF-8");
//return bNormalize( oData );
return oData;
}
catch( UnsupportedEncodingException uee )
{
//Debug.println( new DbgMsg( uee, 3 ) );
Debug.warning("normalize UnsupportedEncodingException in Class Cryptology");
}
return null;
}
/**
* Get the UTF-8 encoded string of a decrypted byte array.
* @param oData byte array which was decrypted from an encrypted byte array.
* @return String encoded in UTF-8. If oData length is zero,
* empty string returned, if UTF-8 not supported, null returned.
*/
public static String rNormalize( byte oData[] )
{
int wdLen = oData.length;
//Debug.println("raw data length: " + wdLen );
if ( wdLen == 0 ) return "";
try
{
return new String( oData, "UTF-8" );
}
catch(UnsupportedEncodingException uee)
{
Debug.warning("normalize UnsupportedEncodingException in Class Cryptology");
}
return null;
}
private byte[] concatChunks( ArrayList chunks )
{
if ( chunks == null ) return new byte[0];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for( int i = 0; i < chunks.size(); i ++ )
{
BigInteger bgInt = (BigInteger)chunks.get( i );
byte[] cBytes = bgInt.toByteArray();
baos.write( cBytes , 0, cBytes.length );
}
return baos.toByteArray();
}
//
private ArrayList getCipherBlocks( ArrayList pChunks, byte[] raBytes, boolean cipher)
{
if ( m_secret == null || raBytes == null || pChunks == null ) return null;
byte[] ss = new byte[ m_secret.length ];
System.arraycopy(m_secret, 0, ss, 0, m_secret.length );
Iterator iPs = pChunks.iterator();
ArrayList cipherBlocks = new ArrayList( pChunks.size() );
BigInteger bi = getIntMediValue( ss, raBytes );
String inter = "intermedium integer: " + bi.intValue() + "/n" ;
String ciph = "";
while( iPs.hasNext() )
{
BigInteger pi = (BigInteger)iPs.next();
BigInteger ci = cipherBlock( pi, bi );
//error occurred, invalid password not necessary to be creatDebug.println("intermedium integer: " + bi.intValue() );ed.
if ( ci == null ) return null;
cipherBlocks.add( ci );
//ciph += "Created ciphered integer: " + ci.intValue() + "(bitLen:" + ci.bitLength() + ")/n";
if ( cipher )
bi = getIntMediValue( ss, ci.toByteArray() );
else
bi = getIntMediValue( ss, pi.toByteArray() );
//inter += "intermedium integer: " +( bi == null ? "null" : bi.intValue() + "(bitLen:" + bi.bitLength() + ")/n") ;
}
//Debug.println( new DbgMsg( inter, Debug.TRACE_IN ) );
//Debug.println( new DbgMsg( ciph, Debug.TRACE_IN ) );
return cipherBlocks;
}
private ArrayList getChunks( byte[] rawPwd )
{
if ( rawPwd == null ) return null;
int chunkCnt = (rawPwd.length + 15) / 16 ;
ArrayList chunks = new ArrayList( chunkCnt );
ByteArrayInputStream bais = new ByteArrayInputStream( rawPwd );
String msg = "";
for( int i = 0; i < chunkCnt; i++)
{
int len = bais.available();
if ( len > 16 ) len = 16;
byte[] chunk = new byte[ 16 ];
int bitLen = bais.read(chunk, 0, len );
//Debug.println("read bytes:" + bitLen +"; value:" + (new String( chunk ) ) );
if ( bitLen != -1 )
{
if ( len < 16 )
Arrays.fill( chunk, len, 15, (byte)0x00 );
BigInteger bi = new BigInteger( chunk );
chunks.add( bi );
}
}
//Debug.println( new DbgMsg( msg, Debug.TRACE_IN ) );
return chunks;
}
private BigInteger getIntMediValue(byte[] secret, byte[] raOrct )
{
if ( secret == null || raOrct == null || raOrct.length < 16 ) return null;
try
{
MessageDigest msgDgt = MessageDigest.getInstance("MD5");
byte[] input = new byte[ secret.length + raOrct.length ];
System.arraycopy(secret,0, input, 0, secret.length );
System.arraycopy(raOrct,0, input, secret.length, raOrct.length );
return new BigInteger( msgDgt.digest( input ) );
}
catch(NoSuchAlgorithmException nsae)
{
Debug.warning("normalize NoSuchAlgorithmException in Class Cryptology");
}
return null;
}
private BigInteger cipherBlock( BigInteger pi, BigInteger bi )
{
if ( pi == null || bi == null ) return null;
BigInteger cpbk = pi.xor( bi );
return cpbk;
}
/**
* If a password's length is less than 16, it will be padded
* to 16 with null. This makes its decrypted value have a
* invalid tail encoded in the nulls. This method will compare
* the string from decrypted bytes and stored origin string
* with the padding nulls tail considered.
* @param decryptedPwd the restored password string
* created from decrypted bytes.
* @param storedPwd the origin password stored
* for authentication.
* @return boolean true if and only if the decryptedPwd
* is started with storedPwd and appended
* by a serias of nulls or none.
*/
public static boolean equals( String decryptedPwd, String storedPwd )
{
try
{
if ( decryptedPwd.length() < storedPwd.length() ) return false;
byte[] dp = decryptedPwd.getBytes("ISO-8859-1");
byte[] sp = storedPwd.getBytes("ISO-8859-1");
if ( dp.length > sp.length )
{
int tLen = dp.length - sp.length;
byte [] spe = new byte[ tLen ];
Arrays.fill( spe, (byte)0x00 );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write( sp );
baos.write( spe );
sp = baos.toByteArray();
}
return Arrays.equals( dp, sp );
}
catch( Exception e )
{
Debug.warning("normalize Exception in Class Cryptology");
}
return false;
}
private byte[] createSecret( int len, byte[] seed )
{
if ( seed == null )
{
seed = normalize( getClass().getName() );
}
if ( len <= 0 ) len = m_defaultSecretLength;
SecureRandom scRdm = new SecureRandom( seed );
byte[] aSec = new byte[ len ];
scRdm.nextBytes( aSec );
return aSec;
}
/**
* If a password's length is less than 16, it will be padded
* to 16 with null. This makes its decrypted value have a
* invalid tail encoded in the nulls. This method will cut the
* invalid tail and return the "CLEAR" data.
* @param data byte[] the origin decrypted byte array.
* @return byte[] bytes from data without the nulls tail.
* if any exception occurred, null returned.
*/
public static byte[] getClearData( byte[] data)
{
try
{
StringBuffer sb = new StringBuffer();
sb.append( new String(data, "ISO-8859-1") );
sb.reverse();
BigInteger rBi = new BigInteger( sb.toString().getBytes("ISO-8859-1") );
sb = new StringBuffer();
sb.append( new String( rBi.toByteArray(), "ISO-8859-1") );
sb.reverse();
return sb.toString().getBytes("ISO-8859-1") ;
}
catch(Exception e)
{
Debug.warning("normalize Exception in Class Cryptology");
}
return null;
}
/*
//for test
public static void main( String argv[] )
{
Cryptology crypto = new Cryptology();
if ( argv.length < 1 )
{
System.exit(0);
}
//Store default secret to file default.sec
try
{
FileOutputStream fos = new FileOutputStream("default.sec");
fos.write( crypto.getSecret() );
fos.close();
}
catch(IOException e){}
if ( argv.length == 2 )
crypto.setSecret( argv[1] );
SecureRandom scRdm = new SecureRandom( SecureRandom.getSeed( 16 ) );
byte[] auth = new byte[16];
scRdm.nextBytes( auth );
String rawStr = argv[0];
System.out.println("Origin String: " + rawStr );
byte[] scStr = crypto.normalize( rawStr );
if ( scStr == null )
{
System.out.println(" Normalization of origin string failed.");
System.exit(0);
}
try
{
scStr = crypto.encrypt( scStr, auth );
System.out.println( "Encrypted string: " + crypto.rNormalize( scStr ) + "; bytesCount: " + scStr.length );
scStr = crypto.decrypt( scStr, auth );
System.out.println( "Decrypted string: " + crypto.rNormalize(scStr) );
System.out.println( "Cleared Decrypted password: " + ( new String( Cryptology.getClearData( scStr ) ) ) );
}
catch( Exception uee)
{}
}
*/
}