Problem with the implementation of the "Grasshopper" cipher"

Hello everyone I'm writing an encryption program. I read the data from the file, turn it into an array of bytes, divide it into blocks, encrypt it, combine it, add the resulting array to a string and save it in another file. The problem manifests itself in the conversion of the array to a string. First, I read the data with UTF-8 encoding (respectively, I also gave it), in this case, when casting, half of the characters turned out to be "EF BF BD". I tried different ways of concatenation/translation, different encodings, in as a result, half of the characters were still "EF BF BD". The last encoding I tried was Windows-1251. In this case, there are no broken characters, but they are different and there are more of them! I don't know what to do with it. Tell me what to do!

Вывод до приведения (Windows-1251):
C4 3C C9 AB 6D 17 73 E0 4D 97 3D 38 5C D6 7A 92 
7D B0 A3 99 6F 76 05 A2 AE 76 C7 D2 B2 72 2C EF 
82 13 00 D2 FF 7B 81 9A 28 45 E6 2A 7A 84 39 72 
D7 70 D3 02 A0 1F 6D 2D 51 F1 74 A7 1B 1B DD DB 
D3 2C FF E1 AF 2E 47 1E EE 79 05 13 D5 DA D3 4A 
64 9C EF CD DE 3D 3C D3 62 9D EE F6 CA 56 0E 5A 
14 36 22 3B 1E 4A 35 D2 C5 E7 84 F2 F7 B3 C8 DA 
99 F7 AB 92 34 CC 93 7C 70 C5 8A AB 90 C0 3A 0F 
73 A2 02 91 91 6B 6B 59 44 28 FD 68 73 90 D6 D3 
D5 EA E6 A1 F5 E2 07 72 0D C8 37 97 16 0E 48 43 
5F F7 2A A2 E6 26 7B 86 84 EC B4 9E AB 74 EC F1

Вывод после приведения (Windows-1251):
D0 94 3C D0 99 C2 AB 6D 17 73 D0 B0 4D E2 80 94 
3D 38 5C D0 A6 7A E2 80 99 7D C2 B0 D0 88 E2 84 
A2 6F 76 05 D1 9E C2 AE 76 D0 97 D0 A2 D0 86 72 
2C D0 BF E2 80 9A 13 00 D0 A2 D1 8F 7B D0 83 D1 
99 28 45 D0 B6 2A 7A E2 80 9E 39 72 D0 A7 70 D0 
A3 02 C2 A0 1F 6D 2D 51 D1 81 74 C2 A7 1B 1B D0 
AD D0 AB D0 A3 2C D1 8F D0 B1 D0 87 2E 47 1E D0 
BE 79 05 13 D0 A5 D0 AA D0 A3 4A 64 D1 9A D0 BF 
D0 9D D0 AE 3D 3C D0 A3 62 D1 9C D0 BE D1 86 D0 
9A 56 0E 5A 14 36 22 3B 1E 4A 35 D0 A2 D0 95 D0 
B7 E2 80 9E D1 82 D1 87 D1 96 D0 98 D0 AA E2 84 
A2 D1 87 C2 AB E2 80 99 34 D0 9C E2 80 9C 7C 70 
D0 95 D0 89 C2 AB D1 92 D0 90 3A 0F 73 D1 9E 02 
E2 80 98 E2 80 98 6B 6B 59 44 28 D1 8D 68 73 D1 
92 D0 A6 D0 A3 D0 A5 D0 BA D0 B6 D0 8E D1 85 D0 
B2 07 72 0D D0 98 37 E2 80 94 16 0E 48 43 5F D1 
87 2A D1 9E D0 B6 26 7B E2 80 A0 E2 80 9E D0 BC 
D2 91 D1 9B C2 AB 74 D0 BC D1 81 00 00 00 00 00 

UPD: the code of the encryption itself (I'm trying to make a "Grasshopper" cipher"):

@Override
//Входной метод
    public void encode() {
        byte[]arrData = getData().getBytes();
        ArrayList<byte[]>dataBlocks = getDataBloks((arrData));//разбиваем данные на блоки
        genKeys();
        switch (encode){
            case "en":
                ArrayList<byte[]>encodeBlocks = new ArrayList<>();
                for (byte[] block:dataBlocks){
                    encodeBlocks.add(encodeBlock(block));
                }
                dataBlocks=encodeBlocks;
                break;
            case "de":
                ArrayList<byte[]>decodeBlocks = new ArrayList<>();
                for (byte[] block:dataBlocks){
                    decodeBlocks.add(decodeBlock(block));
                }
                dataBlocks=decodeBlocks;
                break;
            default:
                break;
        }
        System.out.println("\n");
        //вывожу данные до приведения
        for (int i=0;i<dataBlocks.size();i++){
            printConstant(dataBlocks.get(i));
        }
        System.out.println("\n");
        String result = blocksToData(dataBlocks);
        //вывожу данные после приведения
        byte[]ex=result.getBytes(); 
        ArrayList<byte[]>exx = getDataBloks((ex));
        setResult(result);

    }

//метод, разбивающий на блоки и печатающий их
    private ArrayList<byte[]> getDataBloks (byte[]arrData){
        ArrayList<byte[]>result = new ArrayList<>();
        byte[]arrData16;
        if (arrData.length%BLOCK_SIZE!=0){
            ArrayList<Byte>temp = new ArrayList<>();
            for (int i=0;i<arrData.length;i++) {
                temp.add(arrData[i]);
            }
            while (temp.size()%BLOCK_SIZE!=0) {
                temp.add((byte) 0);
            }
            arrData16 = new byte[temp.size()];
            for (int i=0; i<temp.size(); i++){
                arrData16[i]=temp.get(i);
            }
        }
        else arrData16=arrData;

        int blocksCount = arrData16.length/BLOCK_SIZE;
        for (int i=0; i<blocksCount;i++){
            int offset=BLOCK_SIZE*i;
            byte[]block=new byte[BLOCK_SIZE];
            for (int j=offset;j<offset+BLOCK_SIZE;j++){
                block[j-offset]=arrData16[j];
            }
            result.add(block);
        }
        for (int i=0;i<result.size();i++){
            printConstant(result.get(i));
        }
        return result;
    }

//Метод, собирающий блоки в единый массив и приводящий к строке
    private String blocksToData (ArrayList<byte[]> dataBlocks){
        ArrayList<Byte>alByte=new ArrayList<>();
        for (int i=0;i<dataBlocks.size();i++) {
            for (int j = 0; j < dataBlocks.get(i).length; j++) {
                alByte.add(dataBlocks.get(i)[j]);
            }
        }
        byte[]dataByte=new byte[alByte.size()];
        for(int i=0;i<dataByte.length;i++){
            dataByte[i]= alByte.get(i);
        }
        String result = new String(dataByte, StandardCharsets.UTF_8);
        return result;
    }

//Метод, печатающий массивы в hex формате
    public static void printConstant(byte[]constant) {
        char[] hexChars = new char[constant.length * 2];
        for (int j = 0; j < constant.length; j++) {
            int v = constant[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        for (int i=0; i<hexChars.length;i++){
            System.out.print(hexChars[i]);
            if ((i-1)%2==0) System.out.print(" ");
        }
        System.out.println();
    }

//собственно, сам блок кодировки и 3 функции, которые в него "входят"
    private byte[] encodeBlock(byte[] block){
        byte[]outBlock=block;
        for (int i =0; i<9;i++){
            outBlock=xModify(keys[i],outBlock);
            outBlock=sModify(outBlock);
            outBlock=lModify(outBlock);
        }
        outBlock=xModify(outBlock,keys[9]);
        return outBlock;
    }

    private byte[] xModify(byte[]a, byte[]b){
        byte[]out=new byte[BLOCK_SIZE];
        for (int i=0; i<BLOCK_SIZE;i++){
            out[i]=(byte) (a[i]^b[i]);
        }
        return out;
    }

    private byte[] sModify(byte[]a){
        byte[]out=new byte[BLOCK_SIZE];
        for (int i=0; i<BLOCK_SIZE; i++){
            int data = a[i];
            if (data<0) data+=256;
            out[i]=pi[data];
        }
        return out;
    }

    private byte[] lModify(byte[]in_data){
        byte[]out_data=in_data;
        for (int i=0; i<BLOCK_SIZE;i++){
            out_data=rModify(out_data);
        }
        return out_data;
    }

    private byte[] rModify(byte[]in_data){
        byte[]out_dataR=new byte[BLOCK_SIZE];
        byte a_15=0;
        for (int i=15; i>=0;i--) {
            if (i == 0) out_dataR[15] = in_data[i];
            else out_dataR[i - 1] = in_data[i];
            a_15^=mulGalua(in_data[i], l_vec[i]);
            out_dataR[15]=a_15;
        }
        return out_dataR;
    }

UPD2: Pi table and mulGalua method

    private static final byte[]pi = {(byte) 0xFC, (byte) 0xEE, (byte) 0xDD, 0x11, (byte) 0xCF, 0x6E, 0x31, 0x16,
            (byte) 0xFB, (byte) 0xC4, (byte) 0xFA, (byte) 0xDA, 0x23, (byte) 0xC5, 0x04, 0x4D,
            (byte) 0xE9, 0x77, (byte) 0xF0, (byte) 0xDB, (byte) 0x93, 0x2E, (byte) 0x99, (byte) 0xBA,
            0x17, 0x36, (byte) 0xF1, (byte) 0xBB, 0x14, (byte) 0xCD, 0x5F, (byte) 0xC1,
            (byte) 0xF9, 0x18, 0x65, 0x5A, (byte) 0xE2, 0x5C, (byte) 0xEF, 0x21,
            (byte) 0x81, 0x1C, 0x3C, 0x42, (byte) 0x8B, 0x01, (byte) 0x8E, 0x4F,
            0x05, (byte) 0x84, 0x02, (byte) 0xAE, (byte) 0xE3, 0x6A, (byte) 0x8F, (byte) 0xA0,
            0x06, 0x0B, (byte) 0xED, (byte) 0x98, 0x7F, (byte) 0xD4, (byte) 0xD3, 0x1F,
            (byte) 0xEB, 0x34, 0x2C, 0x51, (byte) 0xEA, (byte) 0xC8, 0x48, (byte) 0xAB,
            (byte) 0xF2, 0x2A, 0x68, (byte) 0xA2, (byte) 0xFD, 0x3A, (byte) 0xCE, (byte) 0xCC,
            (byte) 0xB5, 0x70, 0x0E, 0x56, 0x08, 0x0C, 0x76, 0x12,
            (byte) 0xBF, 0x72, 0x13, 0x47, (byte) 0x9C, (byte) 0xB7, 0x5D, (byte) 0x87,
            0x15, (byte) 0xA1, (byte) 0x96, 0x29, 0x10, 0x7B, (byte) 0x9A, (byte) 0xC7,
            (byte) 0xF3, (byte) 0x91, 0x78, 0x6F, (byte) 0x9D, (byte) 0x9E, (byte) 0xB2, (byte) 0xB1,
            0x32, 0x75, 0x19, 0x3D, (byte) 0xFF, 0x35, (byte) 0x8A, 0x7E,
            0x6D, 0x54, (byte) 0xC6, (byte) 0x80, (byte) 0xC3, (byte) 0xBD, 0x0D, 0x57,
            (byte) 0xDF, (byte) 0xF5, 0x24, (byte) 0xA9, 0x3E, (byte) 0xA8, (byte) 0x43, (byte) 0xC9,
            (byte) 0xD7, 0x79, (byte) 0xD6, (byte) 0xF6, 0x7C, 0x22, (byte) 0xB9, 0x03,
            (byte) 0xE0, 0x0F, (byte) 0xEC, (byte) 0xDE, 0x7A, (byte) 0x94, (byte) 0xB0, (byte) 0xBC,
            (byte) 0xDC, (byte) 0xE8, 0x28, 0x50, 0x4E, 0x33, 0x0A, 0x4A,
            (byte) 0xA7, (byte) 0x97, 0x60, 0x73, 0x1E, 0x00, 0x62, 0x44,
            0x1A, (byte) 0xB8, 0x38, (byte) 0x82, 0x64, (byte) 0x9F, 0x26, 0x41,
            (byte) 0xAD, 0x45, 0x46, (byte) 0x92, 0x27, 0x5E, 0x55, 0x2F,
            (byte) 0x8C, (byte) 0xA3, (byte) 0xA5, 0x7D, 0x69, (byte) 0xD5, (byte) 0x95, 0x3B,
            0x07, 0x58, (byte) 0xB3, 0x40, (byte) 0x86, (byte) 0xAC, 0x1D, (byte) 0xF7,
            0x30, 0x37, 0x6B, (byte) 0xE4, (byte) 0x88, (byte) 0xD9, (byte) 0xE7, (byte) 0x89,
            (byte) 0xE1, 0x1B, (byte) 0x83, 0x49, 0x4C, 0x3F, (byte) 0xF8, (byte) 0xFE,
            (byte) 0x8D, 0x53, (byte) 0xAA, (byte) 0x90, (byte) 0xCA, (byte) 0xD8, (byte) 0x85, 0x61,
            0x20, 0x71, 0x67, (byte) 0xA4, 0x2D, 0x2B, 0x09, 0x5B,
            (byte) 0xCB, (byte) 0x9B, 0x25, (byte) 0xD0, (byte) 0xBE, (byte) 0xE5, 0x6C, 0x52,
            0x59, (byte) 0xA6, 0x74, (byte) 0xD2, (byte) 0xE6, (byte) 0xF4, (byte) 0xB4, (byte) 0xC0,
            (byte) 0xD1, 0x66, (byte) 0xAF, (byte) 0xC2, 0x39, 0x4B, 0x63, (byte) 0xB6};

    private byte mulGalua(byte a, byte b){
        byte c=0;
        byte hi_bit;
        for (int i=0; i<8; i++){
            if ((b&1)==1) c^=a;
            hi_bit=(byte) (a&0x80);
            a<<=1;
            if (hi_bit<0) a^=0xc3;
            b>>=1;
        }
        return c;
    }
Author: Barmaley, 2020-05-21

1 answers

I found a solution to the problem! It really was in the encoding. When translating a string into an array of bytes, it was necessary to explicitly specify the encoding. In UTF-8 encoding, a certain number of bytes (about half) became EF BF BD bits(possibly unreadable characters). In UTF-16, the problem was solved, however, it was necessary to explicitly specify it not only when reading and creating a new string (result), but also every time a string is converted to an array . P.S. the code turned out to be completely working, but at the end in the decrypted text, krakozyabras appear (these are the added zeros).

 0
Author: ferZ, 2020-05-21 12:01:32