Solved

Trying to port a function from C++ to Delphi !

Posted on 2009-05-14
9
496 Views
Last Modified: 2012-05-06
i have tried porting this decryption function from a c++ application im trying to port to delphi, but my delphi code shows nothing as output :S
here are both codes C++ and Delphi and a Test Text that the C++ Can Decrypt but the delphi one cant ;'(

[code]
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <wincrypt.h>

#define SEED_CONSTANT 0xba0da71d

unsigned char secretKey[16]={ 0xa3,0x1e,0xf3,0x69,
                              0x07,0x62,0xd9,0x1f,
                              0x1e,0xe9,0x35,0x7d,
                              0x4f,0xd2,0x7d,0x48 };

int Decode(char output[], char passEntry[], DWORD entryLen)
{
    int ret = -1;
    HANDLE hToken;
    char sid[512], name[512],domain[512];
    DWORD SidSize = 0, i, j;
    DWORD cchName,cchDomain;
    SID_NAME_USE peUse;
    TOKEN_USER *SidUser = (TOKEN_USER*)&sid;

    unsigned char staticKey[16];
    unsigned int seed;
    unsigned char *a,*b;

    memcpy(staticKey,secretKey,sizeof(staticKey));

    if((OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)))
    {
        if((GetTokenInformation(hToken,TokenUser,SidUser,sizeof(sid),&SidSize)))
        {
            cchName = cchDomain = sizeof(name);

            if((LookupAccountSid(NULL,SidUser->User.Sid,
                    name,&cchName,domain,&cchDomain,&peUse)))
            {
                seed = SEED_CONSTANT;

                // mix username with key

                for(i = 0;i < cchName;i++)
                {
                    ((unsigned int*)staticKey)[ i % 4 ] ^= name[i] * seed;
                    seed *= 48271;
                }

                // mix domain name with key

                for(j = 0;j < cchDomain;i++,j++)
                {
                    ((unsigned int*)staticKey)[ i % 4 ] ^= domain[j] * seed;
                    seed *= 48271;
                }

                // decode  string

                seed = (((unsigned int*)staticKey)[0] | 1);
                a = (unsigned char*)&passEntry[4];
                b = (unsigned char*)&passEntry[5];

                for(i = 0;i < entryLen;i += 2)
                {
                    passEntry[ i / 2 ] = (((a[i]-1)*16) | (b[i]-33)) - (seed & 0xff);
                    seed *= 69621;
                }

                // use protected storage to decrypt data

                DATA_BLOB   DataIn, DataEntropy, DataOut;

                DataEntropy.cbData = sizeof(staticKey);
                DataEntropy.pbData = (BYTE*)&staticKey;

                DataIn.cbData = (i/2);
                DataIn.pbData = (BYTE*)passEntry;

                //passEntry[(i/2)+4]=0;

                if(CryptUnprotectData(&DataIn,
                                   NULL,
                                   &DataEntropy,
                                   NULL,
                                   NULL,
                                   1,
                                   &DataOut)) {
                    memcpy(output,DataOut.pbData,DataOut.cbData);
                    output[DataOut.cbData] = 0;
                    LocalFree(DataOut.pbData);
                    ret = 0;
                }
            }
        }
        CloseHandle(hToken);
    }
    return(ret);
}

int main(void) {
    char    pwd[1024],
            out[1024],
            *p;

    fgets(pwd, sizeof(pwd), stdin);
    for(p = pwd; *p && (*p != '\n') && (*p != '\r'); p++);
    *p = 0;

    if(!Decode(out, pwd, strlen(pwd))) {
        printf("\nData: %s\n", out);
    } else {
        printf("\nError decrypting data\n");
    }
    printf("\npress return to quit\n");
    fgetc(stdin);
    return(0);
}
[/code]

and the Delphi One
[code]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  _CREDENTIAL_ATTRIBUTEA = record
    Keyword: LPSTR;
    Flags: DWORD;
    ValueSize: DWORD;
    Value: PBYTE;
  end;
  PCREDENTIAL_ATTRIBUTE = ^_CREDENTIAL_ATTRIBUTEA;

 _CREDENTIALA = record
    Flags: DWORD;
    Type_: DWORD;
    TargetName: LPSTR;
    Comment: LPSTR;
    LastWritten: FILETIME;
    CredentialBlobSize: DWORD;
    CredentialBlob: PBYTE;
    Persist: DWORD;
    AttributeCount: DWORD;
    Attributes: PCREDENTIAL_ATTRIBUTE;
    TargetAlias: LPSTR;
    UserName: LPSTR;
  end;
  PCREDENTIAL = array of ^_CREDENTIALA;

  _CRYPTPROTECT_PROMPTSTRUCT = record
    cbSize: DWORD;
    dwPromptFlags: DWORD;
    hwndApp: HWND;
    szPrompt: LPCWSTR;
  end;
  PCRYPTPROTECT_PROMPTSTRUCT = ^_CRYPTPROTECT_PROMPTSTRUCT;

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


function CredEnumerate(Filter: LPCSTR; Flags: DWORD; var Count: DWORD; var Credential: PCREDENTIAL): BOOL; stdcall;
function CredFree(Buffer: Pointer): BOOL; stdcall;
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;

implementation

function CredEnumerate(Filter: LPCSTR; Flags: DWORD; var Count: DWORD; var Credential: PCREDENTIAL): BOOL; stdcall; external 'advapi32.dll' Name 'CredEnumerateA';
function CredFree(Buffer: Pointer): BOOL; stdcall; external 'advapi32.dll' Name 'CredFree';
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'crypt32.dll' Name 'CryptUnprotectData';

{$R *.dfm}

type
 TOKEN_USER = record
  User: TSidAndAttributes;
 end;
 PTOKEN_USER = ^TOKEN_USER;

const
 secretKey : Array [1..16] of byte = ($a3,$1e,$f3,$69,
                                      $07,$62,$d9,$1f,
                                      $1e,$e9,$35,$7d,
                                      $4f,$d2,$7d,$48);
 SEED_CONSTANT = $ba0da71d;


 function GetCurrentUserAndDomain(szUser : PChar;   pcchUser : DWORD;
       szDomain : PChar;  pcchDomain: DWORD) : boolean;

var
   fSuccess : boolean;
   hToken   : THandle;
   ptiUser  : PSIDAndAttributes;
   cbti     : DWORD;
   snu      : SID_NAME_USE;
   ProcessHandle:THandle;
begin
   ptiUser := nil;
   Result := false;
   ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, GetCurrentProcessId);

   try
      // Get the calling thread's access token.
      if (not OpenThreadToken(ProcessHandle, TOKEN_QUERY, TRUE,
            hToken)) then

       begin
         if (GetLastError() <> ERROR_NO_TOKEN) then
            exit;

         // Retry against process token if no thread token exists.
         if (not OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
               hToken)) then
            exit;
       end;

      // Obtain the size of the user information in the token.
      if (GetTokenInformation(hToken, TokenUser, nil, 0, cbti)) then

         // Call should have failed due to zero-length buffer.
         Exit

       else

         // Call should have failed due to zero-length buffer.
         if (GetLastError() <> ERROR_INSUFFICIENT_BUFFER) then
            Exit;


      // Allocate buffer for user information in the token.
      ptiUser :=  HeapAlloc(GetProcessHeap(), 0, cbti);
      if (ptiUser= nil) then
         Exit;

      // Retrieve the user information from the token.
      if ( not GetTokenInformation(hToken, TokenUser, ptiUser, cbti, cbti)) then
         Exit;

      // Retrieve user name and domain name based on user's SID.
      if ( not LookupAccountSid(nil, ptiUser.Sid, szUser, pcchUser,
            szDomain, pcchDomain, snu)) then
         Exit;

      fSuccess := TRUE;

   finally

      // Free resources.
    //  if (hToken > 0) then
      //   CloseHandle(hToken);

//      if (ptiUser <> nil) then
  //       HeapFree(GetProcessHeap(), 0, ptiUser);
   end;

   Result :=  fSuccess;
end;


function Decode(output :pchar;passEntry :Pchar; entryLen :DWORD):Integer;
var
 ret:Integer;
 hToken:Cardinal;
 sid,name,domain:PAnsiChar;
 i,j:DWORD;
 SidSize:PDWORD;
 cchName,cchDomain : Cardinal;
 peUse:SID_NAME_USE;
 SidUser:^TOKEN_USER;

 staticKey:array[0..16] of byte;
 seed:Integer;
 a,b:PByteArray;
  DataIn, DataEntropy, DataOut:DATA_BLOB;
begin
 // move(statickey,secretkey,length(statickey);
 for i := 1 to High(staticKey) do staticKey[i] := secretKey[i];
 //  if LookupAccountSid(nil,SidUser.User.Sid, pChar(String(name)),cchName,pChar(String(domain)),cchDomain,peUse) then
 //  begin
   GetCurrentUserAndDomain(name,cchName,domain,cchdomain);
    seed := SEED_CONSTANT;
   // mix username with key
    for i := 0 to cchName -1 do
    begin
     staticKey[i mod 4] := (staticKey[i mod 4]) XOR (integer(name[i]) * Seed);
     seed := seed * 48271;
    end;

    I := 0;
    // mix domain name with key
    for j := 0 to cchdomain -1 do
    begin
      statickey[i mod 4] := statickey[i mod 4] xor (integer(domain[j]) * Seed);
      seed := seed * 48271;
      Inc(i);
    end;
   // decode  string

     seed := statickey[0] or 1;
     a := @passentry[4];
     b := @passentry[5];

     for i := 0 to entrylen - 1 do
     begin
        passentry[i div 2] := Char((((a[i]-1)*16) or (b[i]-33)) - (seed and $0ff));
        seed := seed * 69621;
     end;
     // use protected storage to decrypt data

     DataEntropy.cbData := sizeof(staticKey);
     DataEntropy.pbData := PByte(@staticKey);

     DataIn.cbData := (i div 2);
     DataIn.pbData := PBYTE(passEntry);

     if CryptUnprotectData(@DataIn,nil,@DataEntropy, nil, nil, 1, @DataOut) then
     begin
      CopyMemory(@output,DataOut.pbData,DataOut.cbData);
     // output[DataOut.cbData] := 0;
     end;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
 pwd:pChar;
 output:pchar;
begin
 pwd := pChar(memo1.Text);
 Decode(@output, pwd, StrLen(pwd));
 Memo1.Text := Output;
end;

end.
[/code]

and the encrypted text
[code]
%%"$('0*%.,"$&$&&+-!&''/0/##.")$*.!")%(,+%&-#''*(.+"+(%!##'#&/&!0!%/)$.0#,%%+%+&..!+.&.*+.*"-()*".-",&$**!&(+&/*+&#"*&**(.&")&%*!.,,"-&()0,/!)+$%(*%)*#"+00&$.+/*.%"$&,*""0"#&'*".+""&"*0.."!&-*!#$'!-'!*#.$!!'$&+&#0)"')0+&,,%)#.-",&$*#!/0!)/%''("0$/$,.)$0(&&$%/.##!#'","'&+*&,!*"#&(,,,$+(%+.&$,)*0/0'#/#(/"(#*%((("
[/code]

i hope anyone can help
0
Comment
Question by:KillerCode
  • 5
  • 3
9 Comments
 
LVL 13

Expert Comment

by:ThievingSix
ID: 24383275
I can't test this because you need to have the same login credentials to decode. It works the same way as the C++ version and you have to send the encrypted text through the Parameters. No idea if it works.
program Project2;
 
{$APPTYPE CONSOLE}
 
uses
  Windows,
  SysUtils,
  Dialogs;
 
const
  SEED_CONSTANT = $BA0DA71D;
  SecretKey : Array[0..15] Of Byte = ($A3,$1E,$F3,$69,
                                      $07,$62,$D9,$1F,
                                      $1E,$E9,$35,$7D,
                                      $4F,$D2,$7D,$48);
 
type
  TCharArray = Array[0..1023] Of Char;
  _TOKEN_USER = record
    User: SID_AND_ATTRIBUTES;
  end;
  TOKEN_USER = _TOKEN_USER;
  TTokenUser = TOKEN_USER;
  PTokenUser = ^TOKEN_USER;
  _CREDENTIAL_ATTRIBUTEA = record
    Keyword: LPSTR;
    Flags: DWORD;
    ValueSize: DWORD;
    Value: PBYTE;
  end;
  PCREDENTIAL_ATTRIBUTE = ^_CREDENTIAL_ATTRIBUTEA;
 _CREDENTIALA = record
    Flags: DWORD;
    Type_: DWORD;
    TargetName: LPSTR;
    Comment: LPSTR;
    LastWritten: FILETIME;
    CredentialBlobSize: DWORD;
    CredentialBlob: PBYTE;
    Persist: DWORD;
    AttributeCount: DWORD;
    Attributes: PCREDENTIAL_ATTRIBUTE;
    TargetAlias: LPSTR;
    UserName: LPSTR;
  end;
  PCREDENTIAL = array of ^_CREDENTIALA;
  _CRYPTPROTECT_PROMPTSTRUCT = record
    cbSize: DWORD;
    dwPromptFlags: DWORD;
    hwndApp: HWND;
    szPrompt: LPCWSTR;
  end;
  PCRYPTPROTECT_PROMPTSTRUCT = ^_CRYPTPROTECT_PROMPTSTRUCT;
  _CRYPTOAPI_BLOB = record
    cbData: DWORD;
    pbData: PBYTE;
  end;
  DATA_BLOB = _CRYPTOAPI_BLOB;
  PDATA_BLOB = ^DATA_BLOB;
 
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PLPWSTR; pOptionalEntropy: PDATA_BLOB; pvReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'crypt32.dll' Name 'CryptUnprotectData';
 
function Decode(Output: TCharArray; PassEntry: TCharArray; EntryLen: DWORD): Boolean;
var
  Ret : Integer;
  hToken : DWORD;
  SID,
  Name,
  Domain : Array[0..511] Of Char;
  SIDSize,
  I,
  J : DWORD;
  CCHName,
  CCHDomain : DWORD;
  PEUse : SID_NAME_USE;
  SIDUser : PTokenUser;
  StaticKey : TByteArray;
  Seed : DWORD;
  A, B : PByteArray;
  DataIn,
  DataEntropy,
  DataOut : DATA_BLOB;
begin
  Ret := 0;
  SIDSize := 0;
  I := 0;
  J := 0;
  SIDUser := PTokenUser(@SID);
  Move(SecretKey,StaticKey,SizeOf(SecretKey));
  If OpenProcessToken(GetCurrentProcess,TOKEN_QUERY,hToken) Then
    begin
    If GetTokenInformation(hToken,TokenUser,SIDUser,SizeOf(SID),SIDSize) Then
      begin
      CCHName := SizeOf(Name);
      CCHDomain := SizeOf(Domain);
      If LookupAccountSID(nil,SIDUser.User.Sid,Name,CCHName,Domain,CCHDomain,PEUse) Then
        begin
        Seed := SEED_CONSTANT;
        For I := 0 To CCHName - 1 Do
          begin
          StaticKey[I MOD 4] := StaticKey[I MOD 4] XOR (Byte(Name[I]) * Seed);
          Seed := Seed * 48271;
        end;
        For J := 0 To CCHDomain - 1 Do
          begin
          StaticKey[I MOD 4] := StaticKey[I MOD 4] XOR (Byte(Domain[J]) * Seed);
          Seed := Seed * 48271;
          Inc(I);
        end;
        Seed := StaticKey[0] OR 1;
        A := PByteArray(@PassEntry[4]);
        B := PByteArray(@PassEntry[5]);
        I := 0;
        While I < EntryLen Do
          begin
          {$WARNINGS OFF}
          PassEntry[I div 2] := Char((((A[I] - 1) * 16) Or (B[I] - 33)) - (Seed AND $FF));
          {$WARNINGS ON}
          Seed := Seed * 69621;
          Inc(I,2);
        end;
        DataEntropy.cbData := SizeOf(SecretKey);
        DataEntropy.pbData := @StaticKey;
        DataIn.cbData := I div 2;
        DataIn.pbData := @PassEntry;
        If CryptUnprotectData(@DataIn,nil,@DataEntropy,nil,nil,1,@DataOut) Then
          begin
          Move(DataOut.pbData,Output,DataOut.cbData);
          Output[DataOut.cbData] := #0;
          LocalFree(DWORD(Pointer(DataOut.pbData)));
          Ret := 1;
        end
        Else
          begin
          ShowMessage(SysErrorMessage(GetLastError));
        end;
      end
      Else
        begin
        ShowMessage(SysErrorMessage(GetLastError));
      end;
    end
    Else
      begin
      ShowMessage(SysErrorMessage(GetLastError));
    end;
    CloseHandle(hToken);
  end
  Else
    begin
    ShowMessage(SysErrorMessage(GetLastError));
  end;
  Result := Boolean(Ret);
end;
 
var
  PWD : TCharArray;
  aOut : TCharArray;
  Param : String;
  P : PChar;
  I : Integer;
begin
  If ParamCount < 1 Then Exit;
  Param := GetCommandLine;
  Param := Copy(Param,Pos('" ',Param) + 2,Length(Param));
  Move(Param[1],PWD[0],Length(Param));
  For I := 0 To High(PWD) Do
    begin
    If (PWD[I] = #13) Or (PWD[I] = #10) Then PWD[I] := #0;
  end;
  If Decode(aOut,PWD,Length(Param)) Then
    begin
    Writeln(String(aOut));
  end
  Else
    begin
    Writeln('Error');
  end;
  Readln;
end.

Open in new window

0
 
LVL 1

Author Comment

by:KillerCode
ID: 24383335
no Matter what i did, it always says "The Data is invalid" :(
i even made it read the encrypted text from a text file directly to avoid (") in the command line, but no hope :(
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 24383559
The only way I see to debug this further would be to have both projects(C++ and Delphi) open and go down line by line until you see something different(Use my code as it is a direct conversion from the C++ code.
0
Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.

 
LVL 1

Author Comment

by:KillerCode
ID: 24384181
nothing that i can find
all what i found was this difference in 2 lines

        DataEntropy.cbData := SizeOf(SecretKey);
        DataEntropy.pbData := @StaticKey;

they should both be StaticKey, but still wont work :S
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 24384342
Well, I suppose you misunderstood. First off I changed the way the keys were loaded a bit to make it easier to port. Second I meant for you to run both programs and go through the code step by step as its running, examining each variable to see where the differences lie.
0
 
LVL 1

Author Comment

by:KillerCode
ID: 24392614
it still wont work, i did everything
can u check again??
it should Recover Saved Google Talk Password Located at
 HKEY_CURRENT_USER\Software\Google\Google Talk\Accounts\[Account Name]\pw
0
 
LVL 1

Author Comment

by:KillerCode
ID: 24448367
no one can help?
0
 
LVL 1

Accepted Solution

by:
KillerCode earned 0 total points
ID: 26118811
fixed :D
0

Featured Post

U.S. Department of Agriculture and Acronis Access

With the new era of mobile computing, smartphones and tablets, wireless communications and cloud services, the USDA sought to take advantage of a mobilized workforce and the blurring lines between personal and corporate computing resources.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

803 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question