Pregunta

Estoy tratando de cifrar y descifrar archivos de texto usando Elgamal para mi estudio, pero parece que no pude hacer que funcione correctamente. Tengo un grupo de archivos de texto que van desde 1KB - 1 MB, y estoy usando 512 bits para mi tamaño de clave. Ya sé que al igual que RSA, Elgamal no puede cifrar valores más que su módulo, por lo que, como mi solución inicial, he decidido dividir cada archivo en trozos (que es más pequeño que su módulo) para poder cifrarlo y afortunadamente esta solución funciona para el cifrado. Mi problema es este, cuando intenté descifrarlo, las salidas que se han generado no es la salida real que espero ver. No sé cuál es la causa de mi problema y realmente necesito encontrar una solución en pocos días.

Te mostraré algunos de mis fragmentos de código solo para dejarlo claro.

Había generado mi keypair con lo siguiente

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC";
keyGen.initialize(512);

Cifro llamando llamando

public static void encryptFile(String srcFileName, String destFileName, PublicKey key) throws Exception
{
    encryptDecryptFile(srcFileName,destFileName, key, Cipher.ENCRYPT_MODE);
}

y me descifro llamando

public static void decryptFile(String srcFileName, String destFileName, PrivateKey key) throws Exception
{
    encryptDecryptFile(srcFileName,destFileName, key, Cipher.DECRYPT_MODE);
}

Aquí está la definición del método CiCryPTDECRYPTFILE (..)

public static void encryptDecryptFile(String srcFileName, String destFileName, Key key, int cipherMode) throws Exception
    {
        OutputStream outputWriter = null;
        InputStream inputReader = null;
        try
        {
            Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
            String textLine = null;
    //buffer(my chunks) depends wether it is encyption or decryption
            byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[64]);
            int bufl;
            // init the Cipher object for Encryption...
            cipher.init(cipherMode, key);

            // start FileIO
            outputWriter = new FileOutputStream(destFileName);
            inputReader = new FileInputStream(srcFileName);
            while ( (bufl = inputReader.read(buf)) != -1)
            {
                byte[] encText = null;
                if (cipherMode == Cipher.ENCRYPT_MODE)
                {
                      encText = encrypt(copyBytes(buf,bufl),(PublicKey)key);
                }
                else
                {
                    if (_log.isDebugEnabled())
                    {
                        System.out.println("buf = " + new String(buf));
                    }
                    encText = decrypt(copyBytes(buf,bufl),(PrivateKey)key);
                }
                outputWriter.write(encText);
                if (_log.isDebugEnabled())
                {
                    System.out.println("encText = " + new String(encText));
                }
            }
            outputWriter.flush();

        }
        catch (Exception e)
        {
            _log.error(e,e);
            throw e;
        }
        finally
        {
            try
            {
                if (outputWriter != null)
                {
                    outputWriter.close();
                }
                if (inputReader != null)
                {
                    inputReader.close();
                }
            }
            catch (Exception e)
            {
                // do nothing...
            } // end of inner try, catch (Exception)...
        }
    }

Para CopyBytes:

public static byte[] copyBytes(byte[] arr, int length)
{
    byte[] newArr = null;
    if (arr.length == length)
    {
        newArr = arr;
    }
    else
    {
        newArr = new byte[length];
        for (int i = 0; i < length; i++)
        {
            newArr[i] = (byte) arr[i];
        }
    }
    return newArr;
}

Para encypt (...)

    public static byte[] encrypt(byte[] text, PublicKey key) throws Exception
{
    byte[] cipherText = null;
    try
    {

        Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
        if (_log.isDebugEnabled())
        {
            _log.debug("\nProvider is: " + cipher.getProvider().getInfo());
            _log.debug("\nStart encryption with public key");
        }

        // encrypt the plaintext using the public key
        cipher.init(Cipher.ENCRYPT_MODE, key);
        cipherText = cipher.doFinal(text);
    }
    catch (Exception e)
    {
        _log.error(e, e);
        throw e;
    }
    return cipherText;
}

y descifrar (..)

   public static byte[] decrypt(byte[] text, PrivateKey key) throws Exception
    {
        byte[] dectyptedText = null;
        try
        {
            // decrypt the text using the private key
            Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
              cipher.init(Cipher.DECRYPT_MODE, key);
            dectyptedText = cipher.doFinal(text);
        }
        catch (Exception e)
        {
            _log.error(e, e);
            throw e;
        }
        return dectyptedText;

    }

Código original de Aviran Mondo

Creo que eso es todo lo que necesitas, solo dime si quieres ver el código fuente completo. Gracias,

¿Fue útil?

Solución 2

Finalmente tengo la solución, de todos modos la pondré aquí en caso de que alguien también tenga el mismo problema conmigo. Todo lo que tienes que hacer es reemplazar

byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[64]);

en el método CiRryPtDecryptFile (..) con

byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[128]);

Dado que Elgamal con 512 tamaño clave produce 128B al cifrar 50B. Espero que esto esté lo suficientemente claro.

Otros consejos

Esto no está del todo relacionado con su código, pero no es criptográficamente seguro tratar de convertir un cifrado de bloque con un tamaño de bloque de ancho fijo en un cifrado de bloque que puede funcionar en una secuencia simplemente dividiendo la entrada en bloques y encriptando cada uno de ellos. Si haces esto, esencialmente estás haciendo un cifrado de sustitución monoalfabética glorificada donde cada "carácter" tiene un bloque de ancho. Esto permite que un atacante recupere partes de la estructura de su aporte, lo que arruina la garantía que normalmente obtiene de estas primitivas criptográficas. Como ejemplo, ver Esta discusión de Wikipedia de este modo particular de cifrado Y vea cómo encripta el esmoquin el pingüino de Linux. La imagen encriptada le permite ver la estructura de la entrada.

Si desea usar un cifrado de bloque como Elgamal para cifrar un flujo de texto, debe usar una construcción más compleja como encadenamiento de bloques de cifrado (CBC) o Modo de mostrador (CTR), que son probablemente criptográficamente seguros sobre entradas de tamaño razonable. Un atacante le costaría mucho tratar de romper su seguridad si usara uno de estos modos.

Pido disculpas por no tener nada más sustancial que decir sobre su código, pero honestamente creo que vale la pena hacer una copia de seguridad y elegir un sistema criptográfico fuerte antes de tratar de depurar este. De lo contrario, terminarás con un sistema que un atacante inteligente podría frustrar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top