Зашифрованный файл Delphi намного меньше оригинала?

Я загружаю двоичный файл в поток памяти, затем кодирую данные и возвращаю результат в виде строки, затем записываю результат в другой поток памяти и сохраняю его в файл, но когда он сохраняется, файл намного меньше оригинала 25 КБ из 400 КБ ... лол, я почти уверен, что это потому, что я достиг предела того, на что способна строка.

он определенно правильно кодирует, какие данные он сохраняет в новом файле, я расшифровал его и сравнил с началом исходного файла.

Я знаю, что это очень длинный метод и, вероятно, содержит некоторые ненужные шаги, поэтому загрузка его в bStream была бы очень эффективным решением. Мой вопрос заключается в том, как я могу вернуть данные в bStream, а не возвращать их в строку, а затем записывать строку в bStream в этот момент, поскольку я верю, что это решит мою проблему, любые другие предложения также будут оценены. Я использую Делфи 6.

Вот мой код:

function B64Encode(pInput: pointer; pOutput: pointer; Size: longint): longint;
var
  i, iptr, optr: integer;
  Input, Output: PByteArray;
begin
  Input := PByteArray(pInput);
  Output := PByteArray(pOutput);
  iptr := 0;
  optr := 0;
  for i := 1 to (Size div 3) do
  begin
    Output^[optr + 0] := B64[Input^[iptr] shr 2];
    Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)];
    Output^[optr + 2] := B64[((Input^[iptr + 1] and 15) shl 2) + (Input^[iptr + 2] shr 6)];
    Output^[optr + 3] := B64[Input^[iptr + 2] and 63];
    Inc(optr, 4);
    Inc(iptr, 3);
  end;
  case (Size mod 3) of
    1:
      begin
        Output^[optr + 0] := B64[Input^[iptr] shr 2];
        Output^[optr + 1] := B64[(Input^[iptr] and 3) shl 4];
        Output^[optr + 2] := byte('=');
        Output^[optr + 3] := byte('=');
      end;
    2:
      begin
        Output^[optr + 0] := B64[Input^[iptr] shr 2];
        Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)];
        Output^[optr + 2] := B64[(Input^[iptr + 1] and 15) shl 2];
        Output^[optr + 3] := byte('=');
      end;
  end;
  Result := ((Size + 2) div 3) * 4;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  aStream, bStream: TMemoryStream;
  strastream: string;
  szaStream: integer;
begin
  bStream := TMemoryStream.Create;
  aStream := TMemoryStream.Create;
  aStream.LoadFromFile('C:\file1.exe'); 
  szaStream := (astream.size + 2) div (3 * 4);
  SetLength(strastream, szaStream);
  B64Encode(astream.Memory, @strastream[1], Length(strastream));
  bstream.WriteBuffer(strastream[1], szaStream);
  AttachToFile('C:\file2.exe', bStream); 
  bstream.Free;
  aStream.Free;    
end;

Спасибо.


person et3rnal1    schedule 15.08.2013    source источник
comment
К вашему сведению, Base64 - это кодировка, а не шифрование.   -  person Blorgbeard    schedule 15.08.2013
comment
szaStream := (astream.size + 2) div (3 * 4); точно проблема? вы делите на 12 по какой-то причине?   -  person Blorgbeard    schedule 15.08.2013
comment
Я подозреваю, что они хотели умножить на 4/3, но добавили скобки не в том месте.   -  person Móż    schedule 15.08.2013
comment
Я думаю, вы имели в виду ((astream.size * 4) div 3) + 2)   -  person Blorgbeard    schedule 15.08.2013


Ответы (1)


Все ваши расчеты длины неверны, как было указано в комментариях.

szaStream := (astream.size + 2) div (3 * 4);

Это означает, что ваш закодированный поток составляет 1/12 размера входного потока. Но он должен быть больше. Вы имели в виду:

szaStream := ((astream.size * 4) div 3) + 2;

Я также не вижу смысла использовать здесь строку. Вы можете писать прямо в поток.

И стоит повторить, что с базой 64 вы кодируете, а не шифруете.

На мой взгляд, нет смысла писать все это самостоятельно, когда Delphi поставляется с реализацией base 64. Модуль называется EncdDecd или Soap.EncdDecd, если вы используете пространства имен. И единственная функция, которая вам нужна, это

procedure EncodeStream(Input, Output: TStream);

Создайте два файловых потока, один для чтения, один для записи, и передайте их этой функции. Например:

procedure EncodeFileBase64(const InFileName, OutFileName:string);
var
  Input, Output: TStream;
begin
  Input := TFileStream.Create(InFileName, fmOpenRead);
  try
    Output := TFileStream.Create(InFileName, fmCreate);
    try
      EncodeStream(Input, Output);
    finally
      Output.Free;
    end;
  finally
    Input.Free;
  end;
end;

Если вам нужно обратить процесс вспять, сделайте это, как вы уже догадались, с помощью DecodeStream.

Если производительность имеет значение, вам может понадобиться использовать буферизованный поток, а не TFileStream. Например: Буферизованные файлы (для более быстрого доступа к диску)

person David Heffernan    schedule 15.08.2013
comment
Просто к вашему сведению, функции кодирования в Soap.EncdDecd вставляют разрыв строки каждые 75 символов в закодированном выводе. Для сравнения, класс TIdEncoderMIME в Indy, который поставляется с Delphi, не вставляет никаких разрывов строк в свой вывод base64. И он поддерживает кодирование/декодирование данных String, Bytes и TStream. - person Remy Lebeau; 15.08.2013