

/*

 * CryptoUtil.java

 *

 * Created on 22 de agosto de 2001, 8:28

 */

package q02b.exe.arquitectura.utils.crypto;

/**

 *

 * @author Beatriz.Iglesias

 * @version 

 */



import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.security.AlgorithmParameters;

import java.security.Provider;

import java.security.Security;



import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;



public class Q02bCryptoUtil 

{   

    /**

     * Crea el stream encriptado out encriptando el stream original in

     *

     * @param in stream original ( a encriptar )

     * @param out stream encriptado a partir del stream original

     * @exception Exception si hay algun error

     */

    

    public static void encryptFile(InputStream in, OutputStream enc) throws Exception

    {

        cryptoStream( in, enc, Cipher.ENCRYPT_MODE);

    }



    /**

     * Crea el stream desencriptado dec desencriptando el stream encriptado enc

     *

     * @param enc stream encriptado

     * @param dec stream desencriptado a partir del stream enc

     * @exception Exception si hay algun error

     */

    

    public static void decryptFile(InputStream enc, OutputStream dec) throws Exception

    {

        cryptoStream( enc, dec, Cipher.DECRYPT_MODE);

    }   



    

    /**

     * Convierte una cadena Hexadecimal en su correspondientes bytes en ascii

     *

     * @param cadena Cadena en representacion Hexadecimal.

     * @return byte con los caracteres en ascii.

     */

    public static byte[] hexaToByte( String cadena) {

        byte bytes[] = new byte[ cadena.length() / 2];

        int i, x;

        for ( x = i = 0; i < cadena.length(); i += 2) {

            String data = "" + cadena.charAt( i) + cadena.charAt( i + 1);

            bytes[ x++] = ( byte) Integer.parseInt( data, 16);

        }

        return bytes;

    }

    

    /**

    * Encripta/Desencripta streams con el método DES.<br>

    * Encriptar: <br>

    * El primer parametro es el stream original (sin encriptar).<br>

    * El segundo parametro es el stream encriptado resultante de encriptar el stream original.<br>

    * El tercer parametro es el modo, Cipher.ENCRYPT_MODE para encriptar.<br>

    *

    * Desencriptar:<br>

    * El primer parametro es el stream encriptado.<br>

    * El segundo parametro es el stream desencriptado resultante de desencriptar el stream encriptado.<br>

    * El tercer parametro es el modo, Cipher.DECRYPT_MODE para desencriptar.<br>

    * <br>

    * Cuando se encripta, se hace de 8 en 8 bytes, así que el tamaño del stream encriptado será siempre múltiplo de 8. <br>

    * Al desencriptar un stream, aparecerán caracteres 0Ah al final de stream.

    * @param in Stream de entrada

    * @param out Stream de salida

    * @exception Exception si hay algun error

    */

    public static void cryptoStream( InputStream in, OutputStream out, int mode) throws Exception {

        cryptoStream( in , out , mode , null);

    }

    

    

    /**

    * Encripta/Desencripta streams con el método DES.<br>

    * Encriptar: <br>

    * El primer parametro es el stream original (sin encriptar).<br>

    * El segundo parametro es el stream encriptado resultante de encriptar el stream original.<br>

    * El tercer parametro es el modo, Cipher.ENCRYPT_MODE para encriptar.<br>

    *

    * Desencriptar:<br>

    * El primer parametro es el stream encriptado.<br>

    * El segundo parametro es el stream desencriptado resultante de desencriptar el stream encriptado.<br>

    * El tercer parametro es el modo, Cipher.DECRYPT_MODE para desencriptar.<br>

    * <br>

    * Cuando se encripta, se hace de 8 en 8 bytes, así que el tamaño del stream encriptado será siempre múltiplo de 8. <br>

    * Al desencriptar un stream, aparecerán caracteres 0Ah al final de stream.

    * @param in Stream de entrada

    * @param out Stream de salida

    * @param claveEncriptacion Clave de encriptación en formato hexadecimal

    * @exception Exception si hay algun error

    */    



    public static void cryptoStream( InputStream in, OutputStream out, int mode , String claveEncriptacion) throws Exception 

    {

        Provider sunJCE = new com.sun.crypto.provider.SunJCE();

        Security.addProvider( sunJCE);

                    

        //parametros de inicialicion de la clave

        byte [] key      = { ( byte) '2', ( byte) '0', ( byte) '9', ( byte) '5', 

                             ( byte) '2', ( byte) '0', ( byte) '9', ( byte) '5'};



        if(claveEncriptacion!=null){                         

            key = hexaToByte( claveEncriptacion );
        }
                             

        //parametros de inicialicion del algoritmo

        byte [] initKey  = { ( byte) 0x00, ( byte) 0x00, ( byte) 0x00, ( byte) 0x00, 

                             ( byte) 0x00, ( byte) 0x00, ( byte) 0x00, ( byte) 0x00};            

                             

        IvParameterSpec     parameters = new IvParameterSpec( initKey);

        AlgorithmParameters algorithm  = AlgorithmParameters.getInstance( "DES", "SunJCE");

        algorithm.init( parameters);



        //inicializacion del algoritmo

        SecretKeySpec secretKey = new SecretKeySpec( key, "DES");

        Cipher        cipher    = Cipher.getInstance( "DES/CBC/NoPadding");

        cipher.init( mode, secretKey, algorithm);

                

        //desencriptacion

        byte data[] = new byte[ 4096];

        int  length = 0;

        

        ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();

        

        while( ( length = in.read( data)) != -1) {

            if ( ( length % 8) > 0) {

                int  tmpLength  = length + ( 8 - ( length % 8));

                byte tmpData[]  = new byte[ tmpLength];

                byte tmpCR[]    = { ( byte) 0x0A, ( byte) 0x0A, ( byte) 0x0A, ( byte) 0x0A, 

                                    ( byte) 0x0A, ( byte) 0x0A, ( byte) 0x0A, ( byte) 0x0A};            

                System.arraycopy( data, 0, tmpData, 0, length);

                System.arraycopy( tmpCR, 0, tmpData, length, ( 8 - ( length % 8)));

                data   = tmpData;

                length = tmpLength;

            }

            outBuffer.write( cipher.update( data, 0, length), 0, length);

        }

        cipher.doFinal();

        

        /* Esto habrá que ponerlo algún día...

        if(mode==Cipher.DECRYPT_MODE){//Si estamos desencriptando, quitamos la posible morralla...

            ByteArrayOutputStream aux = new ByteArrayOutputStream();

            byte[] b = outBuffer.toByteArray();

            

            for (int i = b.length-1; i >=0; i--) {

                if(b[i]!=(byte) 0x0A){

                    out.write(b,0,i+1);

                    break;

                }

            }

        }else{

            out.write(outBuffer.toByteArray());

        }*/

        

        out.write(outBuffer.toByteArray());

        out.close();

        in.close();

        

    }   



    public static void main(String args[]) {

	if (args.length < 3) {

	    System.exit(0);

	}

	if (args[0].equals("-encrypt")) {

	    try {

		Q02bCryptoUtil.encryptFile(new FileInputStream(args[1]), new FileOutputStream(args[2]));

	   } catch (Exception e) { e.printStackTrace(); }

	}

	if (args[0].equals("-decrypt")) {

	    try {

		Q02bCryptoUtil.decryptFile(new FileInputStream(args[1]), new FileOutputStream(args[2]));

	   } catch (Exception e) { e.printStackTrace(); }

	}



	System.exit(1);

        

    }//end of main

    

} // end of class



