Encriptacion

hola que tal?, tengo una pequeña duda sobre un parametro en la encripcion aes
para encriptar se utiliza esta instruccion, Cipher: init(int arg0, Key arg1, AlgorithmParameterSpec arg2) pero mi duda es para que sirve el AlgorithmParameterSpec, porque probe el siguiente codigo y aunque modificara el valor de iv me seguia desencriptando correctamente, solo fallaba si cambiaba la cantidad de numeros en iv

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package aes;

/**
 *
 * @author insi
 */

   import java.security.*;
   import javax.crypto.*;
   import javax.crypto.spec.*;
   import java.io.*;
import java.util.Arrays;

   /**
   * This program generates a AES key, retrieves its raw bytes, and
   * then reinstantiates a AES key from the key bytes.
   * The reinstantiated key is used to initialize a AES cipher for
   * encryption and decryption.
   */

   public class AES {

     /**
     * Turns array of bytes into string
     *
     * @param buf    Array of bytes to convert to hex string
     * @return    Generated hex string
     */

     public static String asHex (byte buf[]) {
      StringBuffer strbuf = new StringBuffer(buf.length * 2);
      int i;

      for (i = 0; i < buf.length; i++) {
       if (((int) buf[i] & 0xff) < 0x10)
        strbuf.append("0");

       strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
      }

      return strbuf.toString();
     }

     public static void main(String[] args) throws Exception {

       String message="kljdklsfjkljfklsdj bla bla es una trama";

        char[] pass=new char[6];
        pass="1232a".toCharArray();
        byte[] pass16 = getClave16 (pass);
        Arrays.fill (pass, (char)0);

        byte[] iv = "1234567890123456".getBytes("UTF-8");
        IvParameterSpec extra = new IvParameterSpec(iv);
       
        SecretKeySpec key = new SecretKeySpec (pass16, "AES");
      // Instantiate the cipher

       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

       cipher.init(Cipher.ENCRYPT_MODE, key,extra);

       byte[] encrypted =
         cipher.doFinal(message.getBytes());
       System.out.println(key+" "+extra+"encrypted string: " + asHex(encrypted));

       

       pass="1232a".toCharArray();
        pass16 = getClave16 (pass);
        Arrays.fill (pass, (char)0);
       iv = "2234598890193456".getBytes("UTF-8");
       extra = new IvParameterSpec(iv);
        key = new SecretKeySpec (pass16, "AES");

       cipher.init(Cipher.DECRYPT_MODE, key,extra);
       byte[] original =
         cipher.doFinal(encrypted);
       String originalString = new String(original);
       System.out.println("Original string: " +
         originalString + " " + asHex(original));
     }
     public static byte[] getClave16 (char[] clave)
{
    MessageDigest md = null;
    try
    { md = MessageDigest.getInstance ("SHA-1"); }
    catch (Exception e) {}
    byte[] msg = new byte[clave.length];
    for (int i=0; i<clave.length; ++i)
        { msg[i] = (byte)clave[i]; }
    md.update(msg);

    byte[] msg2 = md.digest();
    Arrays.fill (msg, (byte)0);
    System.out.println (""+System.currentTimeMillis());
    for (int i=0; i<70000; ++i)
    {
        msg = new byte[msg2.length+1];
        System.arraycopy (msg2, 0, msg, 0, msg2.length);
        msg[msg2.length] = (byte)(i%128);
        md.update (msg);
        Arrays.fill (msg2, (byte)0);
        msg2 = md.digest();
        Arrays.fill (msg, (byte)0);
    }
    byte[] clave16 = new byte[16];
    for (int i=0; i<16; ++i)
        { clave16[i] = msg2[i]; }
    Arrays.fill (msg2, (byte)0);

    return clave16;
}
   }

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

no son iguales

Fíjate bien, el primer caracter difiere. Por eso no hay que dejar la comparación al ojo humano, es más fácil agregar algo como

assert originalString.equals(message)

con eso te das cuenta de que no son iguales:

kljdklsfjkljfklsdj bla bla es una trama
hljdkc|fjklafklsdj bla bla es una trama

Cambian varios caracteres del primer bloque.

Solamente hay dos bits de diferencia entre ambos IV's: uno empieza con "1" el otro empieza con "2", sus valores ASCII con 49 y 50, en binario son 00110001 y 00110010. En modo CBC, el IV se XORea con el primer bloque a cifrar. Con esos dos bits que cambias, tal vez no se nota un cambio muy drástico, y dado que los datos que estás cifrando son muy simples (puro texto), puede que el cambio solamente afecte de manera visible al primer bloque, pero definitivamente importa que el IV sea distinto.

Imagen de ezamudio

otras cadenas

Modifiqué la primera línea de tu main para hacerlo más flexible y probar varias cadenas:

String message=args.length == 0 ? "kljdklsfjkljfklsdj bla bla es una trama":args[0];

Y con eso probé varias cadenas distintas donde la diferencia es más obvia:

"javaMexico  "
"iavaMjwico +"

Enrique Zamudio Lopez
Fnriqzj Zam~dio Lopez

1234567890ABCDEF
2234598890AICDEF

bloque1 bloque2 bloque3 bloque4 bloque4 bloque6 bloque7 bloque8
aloquj> blozue2 bloque3 bloque4 bloque4 bloque6 bloque7 bloque8

Y si ves los bytes directamente en vez de convertir a cadena, seguramente hay más diferencias que no se notan al convertir a cadena.

buena observacion

si, ya note lo que mencionas, a simple vista parece que son iguales, pero como mencionas si cambian, mi duda principal era que hacia ese parametro, al principio creí que funcionaba incorrectamente, pero con tu explicación de que es una xor ya me quedo bastante claro, por cierto, he visto que hay mas métodos aparte del cbc, cual me recomiendas y porque?
y muchas gracias por contestar mis dudas, seguiré experimentando con la encriptacion aes, y gracias por contestar tan rápido :D

Imagen de ezamudio

Modos de cifrado

El artículo en Wikipedia tiene información bastante útil al respecto.

Gracias

gracias ezamudio, muy buena la explicación que trae el articulo y gracias por tu ayuda de la duda y por contestar tan rápido :D

Problema al convertir a string

Hola, denuevo de regreso, trate de convertir el arreglo de bytes a string para poder guardarlo en mi bd y posteriormente cuando lo necesite extraerlo convertirlo a bytes y desencriptarlo, pero me muestra el siguiente error
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
y no entiendo porque si lo que hago es convertirlo a string y luego de regreso a bytes, en teoria deberia de seguir en miltiplos de 16, o hay alguna forma de convertirlo a multiplos de 16?
el codigo que agregue despues de encriptar es este

String encriptada_string = new String(encrypted);

y al momento de desencriptar recibo una string y hago la siguiente operacion

byte[] encrypted2 =encriptada_string.getBytes();
byte[] original =cipher.doFinal(encrypted2);