Как узнать размер зашифрованных данных? - PullRequest
3 голосов
/ 22 мая 2011

У меня каверзный вопрос, и я надеюсь, что смогу объяснить это хорошо, Я хочу прочитать значение из реестра Windows, которое сохранено другой программой, источник которой у меня отсутствует, но я уже знаю тип этого значения, и оно выглядит следующим образом:

  _MyData = record
    byteType: Byte;
    encData: PByte;
  end;

byteType указывает тип этих данных в виде целого числа (1,2,3…), вы можете забыть об этом параметре, в то время как encData - это зашифрованные данные с использованием windows crypt32. функция dll (CryptProtectData) Я использую следующий код для чтения значения из реестра:

procedure TForm1.Button2Click(Sender: TObject);
var
  myData: _MyData;
  reg: TRegistry;
  valueSize: Integer;
begin
  reg := TRegistry.Create;
  try
    if reg.OpenKey(KEY_PATH,false) then
      Begin
        valueSize := reg.GetDataSize(VALUE_NAME);
        reg.ReadBinaryData(VALUE_NAME, myData, valueSize);
      End;
  finally
    reg.Free;
  end;
end;

// KEY_PATH, VALUE_NAME являются строковыми символами.

Итак, теперь у меня есть зашифрованные данные в myData.encData , и теперь я хочу расшифровать их, передав ей функцию CryptUnprotectData, которая имеет эту подпись:

function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;

Сначала мне нужно поместить зашифрованные данные в переменную типа DATA_BLOB, которая имеет такую ​​структуру:

  _CRYPTOAPI_BLOB = record
    cbData: DWORD;
    pbData: PBYTE;
  end;
  DATA_BLOB = _CRYPTOAPI_BLOB;
  PDATA_BLOB = ^DATA_BLOB;

pbData - указатель на зашифрованные данные (я читаю их из реестра), а cbData - размер зашифрованных данных, и вот моя проблема У меня есть указатель зашифрованные данные (я уже прочитал их из реестра) в myData.encData, который является PByte, но я не знаю, как получить размер этих данных? и если я не даю функции CryptUnprotectData правильный размер, он всегда дает ноль в выходной, Есть идеи, как это сделать?

Спасибо за вашу помощь.

Редактировать: решение, благодаря Кену Бурассе

  _MyData = packed record
    byteType: Byte;
    encData: array of byte;
  end;

procedure TForm1.Button2Click(Sender: TObject);
var
  myData: ^_MyData;
  reg: TRegistry;
  valueSize: Integer;
  dataIn, dataOut: DATA_BLOB;
begin
  reg := TRegistry.Create;
  try
    if reg.OpenKey(KEY_PATH,false) then
      Begin
        valueSize := reg.GetDataSize(VALUE_NAME);
        GetMem(myData, ValueSize);
        try
          reg.ReadBinaryData(VALUE_NAME, myData^, valueSize);

          dataOut.cbData := 0;
          dataOut.pbData := nil;
          dataIn.cbData := Valuesize - SizeOf(Byte);
          dataIn.pbData := @myData.encData;
          CryptUnprotectData(@dataIn,nil,nil,nil,nil,CRYPTPROTECT_UI_FORBIDDEN,@dataOut);

          //yes, it works, Thank you very much Ken Bourassa


        finally
          FreeMem(myData);
        End;
      End;
  finally
    reg.Free;
  end;

end;

Ответы [ 2 ]

4 голосов
/ 23 мая 2011

Размер данных reg.GetDataSize - SizeOf (Byte)

Но теперь это ваша единственная проблема,

Ваша структура _MyData имеет длину 8 байт. Поэтому, когда вы звоните

reg.ReadBinaryData(VALUE_NAME, myData, valueSize); 

для любого значения ключа длиннее 8 байт происходит переполнение буфера. Даже если вы прочитаете ключ длиной менее 8 байт, EncData будет содержать мусор.

Я бы лучше пошел по этому пути:

_MyData = packed record              
  byteType: Byte;              
  encData: array[0..MaxInt] of byte;            
end    

procedure TForm1.Button2Click(Sender: TObject);    
var      
  myData: ^_MyData;
  reg: TRegistry;      
  valueSize: Integer;    
begin      
  reg := TRegistry.Create;      
  try        
    if reg.OpenKey(KEY_PATH,false) then          
    Begin            
      valueSize := reg.GetDataSize(VALUE_NAME);            
      GetMem(MyData, ValueSize);
      try
        reg.ReadBinaryData(VALUE_NAME, myData^, valueSize); 
        //Do what is needed with MyData. The size of MyData.EncData = Valuesize - SizeOf(Byte)
      finally
        FreeMem(MyData);
      end;

    End;      
  finally        
    reg.Free;      
  end;    
end;

Я добавил ключевое слово packed к определению записи, поскольку, как я полагаю, это наиболее вероятный способ его объявления ... Но тогда все зависит от спецификаций приложения, записывающего значения. Я также объявил EncData как Array[0..MaxInt] of byte. Это делает ОЧЕНЬ плохой идеей объявлять переменную типа _MyData, но это единственный известный мне способ разрешить использование массива переменных в записи без принудительного отключения проверки диапазона. Если в вашем проекте не работает проверка диапазона = False = False (или вы не возражаете включить / выключить его, когда это необходимо в вашем коде), вы можете объявить его как Array[0..0] of byte. Я знаю, что это должно сработать, я не знаю специфики этого метода, так как никогда не использовал его.

РЕДАКТИРОВАТЬ (после принятия):

На самом деле, объявление EncData как Array of byte так же плохо, как объявление его как PByte. Array of byte является ссылочным типом (фактически указатель на 4 байта). Если вы попытаетесь получить доступ к EncByte [0] в своем коде, вы, скорее всего, получите AV. Единственная причина, по которой он работает, заключается в том, что вы используете только @myData.encData (и тот факт, что запись выделяется с помощью GetMem вместо этого) Но при таком использовании вы можете объявить EncData следующим образом:

_MyData = packed record              
  byteType: Byte;              
  encData: Record end;            
end    

и это все равно будет работать, так как, в вашем примере, вы на самом деле не заботитесь о объявленном типе EncData, вы просто заботитесь об адресе памяти, где он находится.

3 голосов
/ 22 мая 2011

Мне кажется странным, что второе поле является значением "PByte".Это хранит указатель?Указатель действителен до тех пор, пока выполняется процесс, если только он не хранит только временное значение во время работы программы (если так, странный выбор).Или он хранит буфер произвольной длины, на который указывает это значение?Если сначала хранится значение типа, то в буфере размер буфера будет просто ValueSize - SizeOf (Byte), если только запись не упакована и она «выгружена» непосредственно из памяти, тогда может быть несколько байтов-заполнителей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...