Solved

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

Posted on 2009-05-14
9
488 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
 
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

760 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

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now