enoeht的Java源码系列(5)--字符串加解密

来源:互联网 发布:哪些智障广告知乎 编辑:程序博客网 时间:2024/05/16 14:59

这一篇的内容是一个简单的对字符串加解密的类:

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)

                    {}

    }

*/

}

原创粉丝点击