Solved

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

Posted on 2009-05-14
9
503 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Delphi TcxGrid group footer summary 3 389
how to update exe applicatio from internet ? 6 105
How to convert memory stream to PDF file 6 219
Delphi and Access based Enumeration 9 87
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

739 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