Шифрование. ГОСТ 28147-89. bouncycastle, java

106
02 ноября 2021, 03:20

Нужно реализовать шифрование по госту, нашел пример и на его основе наваял следующее -

public class gost28147_89 {
        final private byte[] key;
        public gost28147_89(String keyString) {
            byte[] key = new byte[0];
            try {
                key = keyString.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new ThrowFabric.ForbiddenException("Кодировка UTF-8 не поддерживается");
            }
            if(key.length == 32)
                this.key = key;
            else{
                this.key = null;
            }
        }
        public String encrypt(String data) {
            if(key.length != 32) return "";
            return encrypt(data, true);
        }
        public String encrypt(String data, Boolean isEncrypt) {
            if(key.length != 32) return "";
            String result;
            byte[] dataBytes;
            try {
                dataBytes = data.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new ThrowFabric.ForbiddenException("Кодировка UTF-8 не поддерживается");
            }
            BufferedBlockCipher cipher = new BufferedBlockCipher(new GOST28147Engine());
            cipher.init(isEncrypt, new KeyParameter(key));
            byte[] dataoOutBytes = new byte[cipher.getOutputSize(dataBytes.length)];
            int len = cipher.processBytes(dataBytes, 0, dataBytes.length, dataoOutBytes, 0);
            try {
                cipher.doFinal(dataoOutBytes, len);
            } catch (InvalidCipherTextException e) {
                throw new ThrowFabric.ForbiddenException("Некорректный текст шифра");
            }
            result = Arrays.toString(dataoOutBytes);
            return result;
        }
        public String decrypt(String data){
            if(key.length != 32) return "";
            return encrypt(data, false);
        }
    }

doFinal вылетает с data not block size aligned\norg.bouncycastle.crypto.BufferedBlockCipher.doFinal(Unknown Source) Кто нибудь работал с этой библиотекой? Не могу найти никакого описания как с ней работать...

UPDATE

Сделал по вашему примеру + подогнал блоки по размеру кратные 8. Шифрование/Дешифрование заработало, но выход после шифрования всегда на один блок(8 байт) больше входного массива.

byte[] dataBytes, tmpBytes;
        tmpBytes = data.getBytes();
        if(tmpBytes.length % 8 != 0){
            dataBytes = new byte[tmpBytes.length + (8 - tmpBytes.length % 8)];
            System.arraycopy(tmpBytes, 0, dataBytes, 0, tmpBytes.length);
        } else{
            dataBytes = tmpBytes;
        }
BlockCipher engine = new GOST28147Engine();
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine));
        cipher.init(isEncrypt, new KeyParameter(key1));
        byte[] cipherText = new byte[cipher.getOutputSize(dataBytes.length)];
        int outputLen = cipher.processBytes(dataBytes, 0, dataBytes.length, cipherText, 0);
        try {
            cipher.doFinal(cipherText, outputLen);
        } catch (InvalidCipherTextException e) {
            throw new ThrowFabric.BadRequestException(e.getMessage());
        }

        result = new String(cipherText);
        return result;
Answer 1

Любой блочный шифр (к каковым также и относится GOST 28147-89) умеет шифровать только 1 блок. Размер блока зависит от шифра, для GOST 28147-89 он равен 64 битам (8 байтам).

Алгоритм шифрования с применением блочного шифра обычно выглядит так:

  1. Разбиваем исходный текст на блоки (в данном случае на блоки по 8 байт)
  2. Если исходный текст не кратен 8 байтам, то проводим процедуру выравнивания блоков (padding) - обычно PKCS#5 или PKCS#7
  3. Далее выбирается алгоритм сцепления блоков - cipher mode - обычно CBC
  4. Далее собственно само шифрование, отдельно каждого блока сцепляя каждый блок с предыдущим выбранным способом сцепления (не забываем еще и про вектора инициализации, которые рандомизируют процесс шифрования)

Чтобы избежать всех этих сложностей придуман механизм простой инициализации, типа:

Cipher cipher = Cipher.getInstance("[Algorithm]/CBC/PKCS5Padding", <CryptoProvider>);

Который читается так: алгоритм [Algorithm], мода сцепления CBC, алгоритм выравнивания PKCS5, правда для этого криптопровайдер должен соответствовать определенным требованиям. Судя по всему у вас провайдер Bouncy Castle, соответственно строка инициализации Cipher должна быть примерно такая:

Cipher cipher=Cipher.getInstance("GOST28147/CBC/PKCS5Padding", "BC");

Почитайте документацию Bouncy Castle или погуглите.

Update

Попробуйте так (аналог GOST28147/CBC/PKCS5Padding):

BlockCipher engine = new GOST28147Engine();
BufferedBlockCipher cipher = new PaddedBlockCipher(new CBCCipher(engine));
byte[] key = keyString.getBytes();
byte[] input = inputString.getBytes();
cipher.init(true, new KeyParameter(key));
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
try
{
    cipher.doFinal(cipherText, outputLen);
}
catch (CryptoException ce)
{
    System.err.println(ce);
    System.exit(1);
}
READ ALSO
Как правильнее преобразовать int в double?

Как правильнее преобразовать int в double?

У меня есть число int = 105; 1 это доллар а 05 в нем это центы, как правильнее преобразовать их? я пробовал через double но в итоге получил 15, а нужно...

86
Объект типа String все таки изменяемый?

Объект типа String все таки изменяемый?

В учебнике Герберта Шилдта "Java Полное руководство", написано, что созданный объект типа String неизменяем, а именно "после того, как объект типа...

95
Wake-on-LAN приложение для Android

Wake-on-LAN приложение для Android

Пытаюсь реализовать Wake On LAN в своем приложенииВот код:

74
Возникает ошибка java.lang.NoClassDefFoundError: Failed resolution of: [Ljava/awt/geom/Line2D$Float;

Возникает ошибка java.lang.NoClassDefFoundError: Failed resolution of: [Ljava/awt/geom/Line2D$Float;

Работаю над андроид игрушкой и вылазит ошибка

129