开发者

How to get the size of encrypted data?

I have tricky question and I hope I can explain it well, I want to read value from windows registry which is saved by another program that I don’t have its source, but I already know the type of this value and it’s lik开发者_开发问答e this:

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

byteType indicates the type of this data as integer (1,2,3…) you can forget about this parameter, while encData is an encrypted data using the windows crypt32.dll function (CryptProtectData) I use the next code to read the value from registry:

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 are string Consts.

So, now I have the encrypted data in myData.encData and now I want decrypt it by passing it the CryptUnprotectData function which has this signature:

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

First I need to put the encrypted data in a variable of type DATA_BLOB which has this structure:

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

pbData is the pointer to the encrypted data (I read it from registry), and cbData is the size of the encrypted data, and here is my problem I have the pointer to encrypted data (I already read it from registry ) in myData.encData which is PByte, but I don’t know how to get the size of this data? and if i don't give the function CryptUnprotectData the right size it always gives nil in the outpout, Any idea how to do this?

Thanks for your help.

Edit:the solution, thanks to Ken Bourassa

  _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;


The size of the data is reg.GetDataSize - SizeOf(Byte)

But that is now your only problem,

Your _MyData structure is 8 bytes long. So when you call

reg.ReadBinaryData(VALUE_NAME, myData, valueSize); 

for any key value longer than 8 bytes, you have some buffer overflow happening. Even if you read a key shorter than 8 bytes, EncData will contain garbage.

I'd rather go this way:

_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;

I added the packed keyword to the record definition as I would believe it's the most likely way it should be declared... But then, it's all up to the specifications of the application writting the values. I also declared EncData as Array[0..MaxInt] of byte. That's makes it a VERY bad idea to declare a variable of type _MyData, but is the only way I know of allowing a variable array in a record without forcing to disable range checking. If always running with Range Checking = False in your project is not a concerned (Or you don't mind switching it on/off where needed in your code), you could declare it as Array[0..0] of byte. I know it should work, I don't know the specifics of that method as I never really used it.

EDIT (After being accepted):

Actually, declaring EncData as Array of byte is just as bad as declaring it as PByte. Array of byte is a reference type (effectively a 4 bytes pointer). If you try to access EncByte[0] in your code, you'll most likely get an AV. The only reason it works is that you only use @myData.encData (and the fact the record is allocated using GetMem instead). But used like this, you could declare EncData like this :

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

and this would still work, as, in your example, you don't really care about the type EncData is declared, you just care about the memory address where it is.


It looks strange to me the second field is a "PByte" value. Is it storing a pointer? A pointer is valid as long as a process is running, unless it is storing just a temporary value while the program is running (if so, strange choice). Or is it storing an arbitrary length buffer pointed to by that value? If it's storing first the type value, then the buffer, the buffer size is simply ValueSize - SizeOf(Byte), unless the record is not packed and it is "dumped" directly from memory, then there could be some filler bytes.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜