No descifrando lo que encripté

Tengo un extraño problema...

Basando mi solución enDescifrando un archivo codificado como byte []

Entonces, escribí una pequeña clase Cypher para ayudar con el cifrado / descifrado ... Solía ​​simular una clave codificada en algún lugar y otra clave previamente cifrada almacenada en otro lugar. Pero eso es algo irrelevante atm.

El proceso de cifrado fue así:

recuperar la matriz de bytes codificadosúsalo para descifrar la clave2usa key2 para descifrar datosutilizar key1 para descifrar más datoshan descifrado datos

Estaba almacenando los datos encriptados como una cadena hexadecimal, usé estas dos funciones para entrar y salir de allí

private static String byteArrayToHexString(byte[] b)
{
    StringBuffer sb = new StringBuffer(b.length * 2);
    for (int i = 0; i < b.length; i++)
    {
        int v = b[i] & 0xff;
        if (v < 16)
        {
            sb.append('0');
        }
        sb.append(Integer.toHexString(v));
    }
    return sb.toString().toUpperCase();
}

private static byte[] hexStringToByteArray(String s)
{
    byte[] b = new byte[s.length() / 2];
    for (int i = 0; i < b.length; i++)
    {
        int index = i * 2;
        int v = Integer.parseInt(s.substring(index, index + 2), 16); //THIS LINE
        b[i] = (byte) v;
    }
    return b;
}

Eso funcionó a la perfección; de hecho, funcionó tan bien que lo implementé en mi proyecto real. El proyecto no se ejecutó debido a que no lo probé a fondo.

Resulta que encripta / desencripta prácticamente todos los archivos, excepto uno, que no quiere descifrar.

Sin embargo, he identificado el problema: ESTA línea lanza una excepción IllegalNumberFormat; en algún momento me familiaricé con estohttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 también. Me gustaría y puedo volver a este método si alguien describe una forma de omitir un caso cuando una cadena de longitud 2 se convierte en cuatro bytes, lo que arroja una excepción IllegalNumberFormatException.

Entonces, pensé que ya que no puedo decodificar un archivo (y obviamente no puedo compartirlo aquí para que lo prueben) tuve que transformarlo de alguna manera para hacerlo seguro para el transporte. Ingrese a la clase Base64Coder que codifica las cadenas base64 ...

Eso parecía haber introducido un nuevo problema: el relleno se estaba eliminando.

La pregunta es simple: ¿qué estoy haciendo mal? Necesito ajustarme a estos datos y tiene que ser capaz de cifrar / descifrar correctamente y por igual. Me gustaría una propuesta sobre la solución más liviana posible con menos copiar / pegar ... pseudocódigo no funcionará aquí.

Esto es lo que estoy haciendo ahora ...

public static char[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(true);
    System.err.println("encrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters());
    byte[] encrypted = cipher.doFinal(value);

    SecretKeySpec key2 = getSecretKeySpec(false);
    cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.ENCRYPT_MODE, key2, cipher.getParameters());
    byte[] encrypted2 = cipher.doFinal(encrypted);

    return Base64Coder.encode(encrypted2);
}

public static byte[] decrypt2(char[] message) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(false);
    System.err.println("decrypt():\t" + key1.toString());
    Cipher cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.DECRYPT_MODE, key1);
    byte[] decrypted = cipher.doFinal(Base64Coder.decode(message));

    SecretKeySpec key2 = getSecretKeySpec(true);
    cipher = Cipher.getInstance(CRYPTOSYS);
    cipher.init(Cipher.DECRYPT_MODE, key2);
    byte[] decrypted2 = cipher.doFinal(decrypted);

    return decrypted2;
}

Tenga en cuenta que las claves están actualmente totalmente expuestas (codificadas) para fines de prueba.

Aquí está mi caso de prueba

public static void main(String... args) throws Exception
{
    //      byte[] data = "hello".getBytes();
    File PEM = new File(PATH_TO_FILES + SOURCE_PEM);
    File DER = new File(PATH_TO_FILES + SOURCE_DER);
    File cryptoPEM = new File(PATH_TO_FILES + "cryptopem");
    File cryptoDER = new File(PATH_TO_FILES + "cryptoder");

    byte[] cryptokey = encryptA(ASSET_KEY);
    System.out.println(new String(cryptokey));

    //pem key
    System.out.println("PEM");
    byte[] data = getBytesFromFile(PEM);
    char[] crypted = encrypt2(data);
    //      FileOutputStream fos = new FileOutputStream(cryptoPEM);
    FileWriter fw = new FileWriter(cryptoPEM);
    fw.write(crypted);
    fw.flush();

    //der key
    System.out.println("DER");
    data = getBytesFromFile(DER);
    crypted = encrypt2(data);
    fw = new FileWriter(cryptoDER);
    fw.write(crypted);
    fw.flush();

    //opentext
    System.out.println("checking PEM...");
    crypted = Base64Coder.encode(getBytesFromFile(cryptoPEM));
    byte[] decrypted = decrypt2(crypted,  false);
    byte[] decryptedData = decrypted;

    if (!Arrays.equals(getBytesFromFile(PEM), decryptedData)) { throw new Exception("PEM Data was not decrypted successfully"); }

    System.out.println("checking DER...");
    crypted = Base64Coder.encode(getBytesFromFile(cryptoDER));
    decrypted = decrypt2(crypted,  false);
    decryptedData = decrypted;

    if (!Arrays.equals(getBytesFromFile(DER), decryptedData)) { throw new Exception("DER Data was not decrypted successfully"); }
}

Y ahora estoy recibiendo una InvalidBlockSizeException ... Por favor, alguien arroja algo de luz sobre esto, solo quiero que esto funcione ...

Reemplazar 'key2' para un IV que luego se usará en un "AES / CBC / PKCS5Padding" es una opción que estoy considerando ahora. Esencialmente, nada cambiará, excepto el segundo paso de cifrado. Teórica y metodológicamente, mantendría las cosas igual, a menos que, por supuesto, se describa una solución mejor.

Al final, me gustaría señalar que esta es una pregunta del programador, no una pregunta de seguridad del estudiante, por lo que el código correcto se valora más que una respuesta teórica que cubra los casos poco probables.

EDIT: bueno, no puedo darle los números que causan la excepción IllegalNumberFormatException porque perdí el código de esta mañana. Parece que no puedo replicar el problema, así que supongo que tratar de entender esa parte no sirve de nada.

Aquí está la salida de la prueba de muestra:

encrypt():  javax.crypto.spec.SecretKeySpec@15dd7
5@��_׵G�j��!�c;D�i�lR?z�j\
PEM
encrypt():  javax.crypto.spec.SecretKeySpec@15dd7
DER
encrypt():  javax.crypto.spec.SecretKeySpec@15dd7
checking PEM...
decrypt():  javax.crypto.spec.SecretKeySpec@15c78
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

lo que significa que Base64 es un poco desordenado ...

Respuestas a la pregunta(3)

Su respuesta a la pregunta