Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

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

Posted on 2009-05-14
9
Medium Priority
?
517 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Suggested Courses

618 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