Solved

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

Posted on 2009-05-14
9
505 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
Industry Leaders: 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

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…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…

707 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