Как зашифровать / расшифровать текстовые файлы, используя ElGamal

Я пытаюсь зашифровать и расшифровать текстовые файлы, используя ElGamal для моего исследования, но мне кажется, что я не могу заставить его работать правильно. У меня есть группа текстовых файлов в диапазоне от 1 КБ до 1 МБ, и я использую 512 бит для моего размера ключа. Я уже знаю, что так же, как RSA, ELGamal не может зашифровать значения больше, чем его модуль, поэтому в качестве своего первоначального решения я решил разделить каждый файл на куски (которые меньше его модуля), чтобы я мог его зашифровать и, к счастью, это решение работает для шифрования. Моя проблема в том, что, когда я пытался расшифровать его, сгенерированные выходные данные не являются фактическими данными, которые я ожидаю увидеть. Я не знаю, в чем причина моей проблемы, и мне действительно нужно найти решение в течение нескольких дней.

Я покажу вам некоторые мои фрагменты кода, чтобы прояснить ситуацию.

Я сгенерировал свою пару ключей со следующими

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

Я зашифровал, позвонив

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

и я расшифровываю по телефону

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

Вот определение метода encryptDecryptFile (..)

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)...
        }
    }

Для 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;
}

Для энсипта (...)

    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;
}

и расшифровать (..)

   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;

    }

Оригинальный код от Aviran Mondo

Я думаю, что это все, что вам нужно, просто скажите мне, если вы хотите увидеть полный исходный код. Спасибо,

2 ответа

Решение

Наконец-то у меня есть решение, в любом случае, я просто оставлю его здесь на тот случай, если у кого-то возникнет такая же проблема со мной Все, что вам нужно сделать, это заменить

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

в методе encryptDecryptFile(..) с

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

поскольку ElGamal с размером ключа 512 выдает 128b при шифровании 50b. Я надеюсь, что это достаточно ясно.

Это не совсем связано с вашим кодом, но криптографически небезопасно пытаться превратить блочный шифр с размером блока фиксированной ширины в блочный шифр, который может работать в потоке, просто разбивая входные данные на блоки и шифруя каждый из них. Если вы делаете это, вы, по сути, делаете прославленный моноалфавитный шифр замещения, где каждый "символ" имеет ширину в один блок. Это позволяет злоумышленнику восстановить части структуры вашего ввода, что разрушает гарантию, которую вы обычно получаете от этих криптографических примитивов. В качестве примера, посмотрите это обсуждение в Википедии об этом конкретном режиме шифрования и посмотрите, как он шифрует Tux Linux Penguin. Зашифрованное изображение сразу позволяет увидеть структуру ввода.

Если вы хотите использовать блочный шифр, такой как ElGamal, для шифрования потока текста, вы должны использовать более сложную конструкцию, такую ​​как цепочка блоков шифра (CBC) или режим счетчика (CTR), которые надежно криптографически безопасны для входов разумного размера. Злоумышленнику будет очень трудно попытаться сломать вашу безопасность, если вы воспользуетесь одним из этих режимов.

Я извиняюсь за то, что не могу сказать ничего более существенного о вашем коде, но я искренне думаю, что стоит сделать резервную копию и выбрать надежную криптосистему, прежде чем пытаться ее отладить. В противном случае вы получите систему, которую умный злоумышленник может помешать.

Другие вопросы по тегам