Как расшифровать бинарные данные на Delphi?

Рейтинг: 0Ответов: 2Опубликовано: 20.01.2023

Есть рабочее приложение, написанное на Java. Она отправляет запрос на сервер и получает запакованные данные.

HTTP/1.1 200 OK 
Server: nginx
Date: Thu, 12 Jan 2023 18:26:21 GMT
Connection: close
Content-Encoding: zip-block
Content-Length: 24640

D @xњіIО+¶іHML±іQЊvvq qЊV°
ВИКМMµURRHN¶U26VиГИС
¶S‚ЌµиС‡(OОЛ¶и V» & D @x.

Полный ответ - Response.txt

При обработке ответа в TidCompressorZlib (Delphi, компонент ZLIB для работы с gzip) получаю ошибку о неправильном формате архивных данных.

Я так понимаю, что при отправке данных происходит еще дополнительно некое их "шифрование".

Я вытащил два блока кода программы на Java:

  1. Модуль CompressedBlockInputStream

     import java.io.*;
     import java.util.zip.DataFormatException;
     import java.util.zip.Inflater;
    
     public class CompressedBlockInputStream extends FilterInputStream
     {
    
     public CompressedBlockInputStream(InputStream inputstream)
         throws IOException
     {
         super(inputstream);
         inBuf = null;
         inLength = 0;
         outBuf = null;
         outOffs = 0;
         outLength = 0;
         inflater = null;
         inflater = new Inflater();
     }
    
     protected void readAndDecompress()
         throws IOException
     {
         int i = in.read();
         int j = in.read();
         int k = in.read();
         int l = in.read();
         if((i | j | k | l) < 0)
             throw new EOFException();
         inLength = (i << 24) + (j << 16) + (k << 8) + (l << 0);
         i = in.read();
         j = in.read();
         k = in.read();
         l = in.read();
         if((i | j | k | l) < 0)
             throw new EOFException();
         outLength = (i << 24) + (j << 16) + (k << 8) + (l << 0);
         if(inBuf == null || inLength > inBuf.length)
             inBuf = new byte[inLength];
         if(outBuf == null || outLength > outBuf.length)
             outBuf = new byte[outLength];
         int j1;
         for(int i1 = 0; i1 < inLength; i1 += j1)
         {
             j1 = in.read(inBuf, i1, inLength - i1);
             if(j1 == -1)
                 throw new EOFException();
         }
    
         inflater.setInput(inBuf, 0, inLength);
         try
         {
             inflater.inflate(outBuf);
         }
         catch(DataFormatException dataformatexception)
         {
             throw new IOException((new StringBuilder()).append("Data format exception - ").append(dataformatexception.getMessage()).toString());
         }
         inflater.reset();
         outOffs = 0;
     }
    
     public int read()
         throws IOException
     {
         if(outOffs >= outLength)
             try
             {
                 readAndDecompress();
             }
             catch(EOFException eofexception)
             {
                 return -1;
             }
         return outBuf[outOffs++] & 0xff;
     }
    
     public int read(byte abyte0[], int i, int j)
         throws IOException
     {
         int k = 0;
     _L3:
         if(k >= j) goto _L2; else goto _L1
     _L1:
         if(outOffs < outLength)
             break MISSING_BLOCK_LABEL_58;
         try
         {
             if(k > 0 && in.available() == 0)
                 return k;
         }
         catch(EOFException eofexception)
         {
             if(k == 0)
                 k = -1;
             return k;
         }
         readAndDecompress();
         int l = Math.min(outLength - outOffs, j - k);
         System.arraycopy(outBuf, outOffs, abyte0, i + k, l);
         outOffs += l;
         k += l;
           goto _L3
     _L2:
         return k;
     }
    
     public int available()
         throws IOException
     {
         return (outLength - outOffs) + in.available();
     }
    
     protected byte inBuf[];
     protected int inLength;
     protected byte outBuf[];
     protected int outOffs;
     protected int outLength;
     protected Inflater inflater;
     }
    
  2. Модуль CompressedBlockOutputStream

     import java.io.*;
     import java.util.zip.Deflater;
    
     public class CompressedBlockOutputStream extends FilterOutputStream
     {
    
     public CompressedBlockOutputStream(OutputStream outputstream, int i)
         throws IOException
     {
         this(outputstream, i, -1, 0);
     }
    
     public CompressedBlockOutputStream(OutputStream outputstream, int i, int j, int k)
         throws IOException
     {
         super(outputstream);
         inBuf = null;
         outBuf = null;
         len = 0;
         deflater = null;
         inBuf = new byte[i];
         outBuf = new byte[i + 64];
         deflater = new Deflater(j);
         deflater.setStrategy(k);
     }
    
     protected void compressAndSend()
         throws IOException
     {
         if(len > 0)
         {
             deflater.setInput(inBuf, 0, len);
             deflater.finish();
             int i = deflater.deflate(outBuf);
             out.write(i >> 24 & 0xff);
             out.write(i >> 16 & 0xff);
             out.write(i >> 8 & 0xff);
             out.write(i >> 0 & 0xff);
             out.write(len >> 24 & 0xff);
             out.write(len >> 16 & 0xff);
             out.write(len >> 8 & 0xff);
             out.write(len >> 0 & 0xff);
             out.write(outBuf, 0, i);
             out.flush();
             len = 0;
             deflater.reset();
         }
     }
    
     public void write(int i)
         throws IOException
     {
         inBuf[len++] = (byte)i;
         if(len == inBuf.length)
             compressAndSend();
     }
    
     public void write(byte abyte0[], int i, int j)
         throws IOException
     {
         int k;
         for(; len + j > inBuf.length; j -= k)
         {
             k = inBuf.length - len;
             System.arraycopy(abyte0, i, inBuf, len, k);
             len += k;
             compressAndSend();
             i += k;
         }
    
         System.arraycopy(abyte0, i, inBuf, len, j);
         len += j;
     }
    
     public void flush()
         throws IOException
     {
         compressAndSend();
         out.flush();
     }
    
     public void close()
         throws IOException
     {
         compressAndSend();
         out.close();
     }
    
     protected byte inBuf[];
     protected byte outBuf[];
     protected int len;
     protected Deflater deflater;
     }
    

Прошу помощи в переносе кода с Java на Delphi или в понимании этой логики "упаковки" и "шифрования" данных

Ответы

▲ 1Принят

Как уже написали в комментариях - там два лишних int в данных. Вот так работает, по крайней мере у меня на полном файле:

var zipBlock := TFile.ReadAllBytes('T:\RadStudio\Response.txt');
ZDecompress(@zipBlock[8], Length(zipBlock) - 8, Data, Size);
▲ 0

Тему закрываю. Вопрос решен. Благодарю Alekcvp, Shaft за помощь.

Код от Shaft

procedure decompress;
var
  s_dec:TDecompressionStream;
  s_in,s_out:TMemoryStream;
const block=64;
      offset=8;
begin
  s_in:=TMemoryStream.Create;
  s_out:=TMemoryStream.Create;
  s_in.LoadFromFile('test.bin');
  repeat
    s_in.Position:=s_in.Position+offset;
    s_dec:=TDecompressionStream.Create(s_in);
    if s_in.Position+block<=s_in.Size then
      s_out.CopyFrom(s_dec,block)
    else
      s_out.CopyFrom(s_dec,s_in.Size-s_in.Position-offset);
    s_dec.Free;
  until s_in.Position>=s_in.Size;
  s_out.SaveToFile('decompress.bin');
  s_in.Free;
  s_out.Free;
end;