Problema encripción AES

Que tal pandilla !!!

Tengo una aplicación móvil en java y ando teniendo problemas, cuando encripto un buffer muy largo me marca la siguiente excepción(desde el emulador del wtk)
y no entiendo porqué funciona encripta/desencripta correctamente con un buffer pequeño pero no con uno grande (tal vez no sea el tamaño, pero ya busqué si no traigo caracteres extraños y todo está bien)

org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at org.bouncycastle.crypto.paddings.PKCS7Padding.padCount(Unknown Source)
at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(Unknown Source)
at com.ls.tt.commons.security.MotorCriptografico.decryptByAES(MotorCriptografico.java:76)
at com.ls.tt.web.net.ServidorSincronizacion.sincronizar(ServidorSincronizacion.java:119)
at com.ls.tt.web.net.impl.ServicioEnvioRespuestas.doPost(ServicioEnvioRespuestas.java:29)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.apache.tapestry5.TapestryFilter.doFilter(TapestryFilter.java:129)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:842)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:730)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:450)

Mi clase es la siguiente: La llave de encripción/desencripción y el vector de inicialización estan en código duro para hacer más simple el ejemplo

public class MotorCriptografico {

    private byte[] keyAES;
    private byte[] initVAES;
    BufferedBlockCipher cipher;
    ParametersWithIV piv;

    public MotorCriptografico() {
        // Llave para encriptar/desencriptar los mensajes (32 bytes)
        keyAES = "EWRTX0vV6HJKLTREPLTTX1aVBAJKLyR8".getBytes();

        // Vector de inicialización
        // CBCBlockCipher = block size 16 bytes
        initVAES = "PLRTXSQVBHJKLTRE".getBytes();

        cipher = new PaddedBufferedBlockCipher(
                new CBCBlockCipher(new AESLightEngine()));

        piv = new ParametersWithIV(
                (new KeyParameter(keyAES)), initVAES);
    }

    /**
     * Encripta un array de bytes
     */

    public byte[] encryptByAES(byte[] toEncrypt) throws Exception {
        cipher.init(true, piv);
        byte[] result = new byte[cipher.getOutputSize(toEncrypt.length)];
        int len = cipher.processBytes(toEncrypt, 0, toEncrypt.length, result, 0);
        cipher.doFinal(result, len);

        return result;
    }

    /**
     * Desencripta un array de bytes que fué encriptado con la
     */

    public byte[] decryptByAES(byte[] toDecrypt) throws Exception {
        cipher.init(false, piv);
        byte[] result = new byte[cipher.getOutputSize(toDecrypt.length)];
        int len = cipher.processBytes(toDecrypt, 0, toDecrypt.length, result, 0);

        // Throws
        // InvalidCipherTextException - is thrown whenever we find something we don't expect in a message.
        cipher.doFinal(result, len);

        return result;
    }
}

Desde ahora gracias
Un abrazo

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

Tamaños?

Define "largo" y "corto". Te refieres a que encripta bien un bloque (16 bytes) pero ya no encripta más de un bloque? Puedes encriptar bloques exactos, por ejemplo 32, 48, 160 bytes? el problema es solamente con bloques inexactos que necesitan padding (que la longitud de los datos no sea múltiplo de 16)?

Esa clase PaddedBufferedBlockCipher de dónde la sacaste? Extiende javax.crypto.Cipher o es un rollo aparte? No entiendo por qué tienes que llamar el doFinal después del processBytes...

Imagen de iberck

Fixed

PaddedBufferedBlockCipher es una clase de bouncycastle y sirve como wrapper para crear el cipher.
doFinal() lo utilizo para rellenar el último bloque para que quede como múltiplo de 16 bytes (longitud de bloque de CBCBlockCipher)

Después de un rato encontré que el problema no es en la clase que se encarga de encriptar/desencriptar si no que cuando mando un buffer largo (no se que tamaño) el content length de la cabecera http aunque lo ponga explicitamente me lo pone como -1. Entonces en el servidor estoy reconstruyendo el array de bytes con una longitud incorrecta y cuando intento desencriptar el motor truena....

El problema esta en el else, me está dando la longitud de array de manera incorrecta.

if (len != -1) {// El tamaño de la petición está definido

                // InputStream -> buffer[]
                is = request.getInputStream();
                encrypted = new byte[len];
                int total = 0;
                while (total < len) {
                    total += is.read(encrypted, total, len - total);
                }
            } else { // No está definido el tamaño de la petición o es demasiado grande

                // DataInputStream -> buffer[]
                dis = new DataInputStream(request.getInputStream());
                len = dis.available(); // TODO:
                encrypted = new byte[len];
                dis.readFully(encrypted);
            }

Gracias por tu tiempo enrique, nos vemos pronto

Imagen de iberck

pd fixed

El else final quedó así:

else {
                    is = conn.openInputStream();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int ch;
                    while ((ch = is.read()) != -1) {
                        baos.write(ch);
                    }
                    encrypted = baos.toByteArray();
                    len = encrypted.length;
                }

Saludos

Imagen de ezamudio

Límite

Estás leyendo de una página o algo así por lo que entendí (mencionaste algo de HTTP). Sería bueno ponerle un límite a los datos que estás leyendo, sobre todo si ya sabes cuánto debe medir en promedio lo que vas a leer; así evitar de repente leer demasiada info y acabarte la memoria del teléfono. Simplemente ve revisando el tamaño de baos para ver cuánto has estado leyendo.

Y puedes optimizar usando un buffer pequeño; en vez de leer byte por byte, es mucho mejor si lees un buffer, digamos de 16K:

byte[] buf = new byte[16384];
int ch = is.read(buf);
while (ch > 0) {
  if (ch == -1 ) { //ya no hay más que leer, se ha terminado el stream o te cerraron la conexión
  } else {
    baos.write(buf, 0, ch);
    ch = is.read(buf);
  }
}
Imagen de iberck

Re: Límite

Los datos que viajan realmente son pocos (a lo mucho 2 Kb), sin embargo tomaré el consejo...
gracias