unit RplDecode;

interface

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

type

  TRPLRecord = record
    NPC:string;
    CCC:string;
    HWC:string;
    SIMLOCK:string;
    SIMLOCK_KEY:string;
    SUPERDONGLE_KEY:string;
    CMLA_KEY:string;
    WMDRM_PD:string;
  end;

  function DecodeRpl(filename: string; savefile: boolean = false): TRPLRecord;

  
implementation

function GetErrorMessage: string;
var
 ErrMsg: array [0..160] of char;
begin
 ERR_error_string(ERR_get_error, @ErrMsg);
 result := StrPas(@ErrMsg);
end;

procedure InitOpenSSL;
begin
 OpenSSL_add_all_algorithms;
 OpenSSL_add_all_ciphers;
 OpenSSL_add_all_digests;
 ERR_load_crypto_strings;
end;

procedure FreeOpenSSL;
begin
 EVP_cleanup;
end;




function ReadPrivateKey(AFileName: TFileName): pEVP_PKEY;
var
 keyfile: pBIO;
 x: pEVP_PKEY;

 function cb(buffer: PChar; blength: integer; verify: integer; data: pointer): integer; cdecl;
 begin
  result := 0;
 end;

begin
 keyfile := BIO_new(BIO_s_file());
 BIO_read_filename(keyfile, PChar(AFilename));
 x:=nil;
 result := PEM_read_bio_PrivateKey(keyfile, x, @cb, nil);
 if result = nil then
  raise Exception.Create('Unable to read private key. ' + GetErrorMessage);
 BIO_free(keyfile);
end;


procedure RSADecrypt(KeyFile, CleartextFile, CryptedFile: string; padding: integer);
var
 rsa: pRSA;
 keysize: integer;
 key: pEVP_PKEY;
 cleartext, crypted: pBIO;
 rsa_in, rsa_out: pointer;
 rsa_inlen, rsa_outlen: integer;
begin
 key := ReadPrivateKey(KeyFile);
 rsa := EVP_PKEY_get1_RSA(key);
 EVP_PKEY_free(key);
 if rsa = nil then
  raise Exception.Create('Error getting RSA key. ' + GetErrorMessage);
 cleartext := BIO_new_file(PChar(CleartextFile), 'rb');
 if cleartext = nil then
  raise Exception.Create('Error Reading Input File. ' + GetErrorMessage);
 crypted := BIO_new_file(PChar(CryptedFile), 'wb');
 if crypted = nil then
  raise Exception.Create('Error Reading Output File. ' + GetErrorMessage);
 keysize := RSA_size(rsa);
 rsa_in := OPENSSL_malloc(keysize);
 rsa_out := OPENSSL_malloc(keysize);
 rsa_inlen := BIO_read(cleartext, rsa_in, keysize * 2);
 if rsa_inlen <= 0 then
  raise Exception.Create('Error reading input Data.');
 rsa_outlen := RSA_Private_Decrypt(rsa_inlen, rsa_in, rsa_out, rsa, padding);
 if rsa_outlen <= 0 then
  raise Exception.Create('RSA operation error. ' + GetErrorMessage);
 BIO_write(crypted, rsa_out, rsa_outlen);
 RSA_free(rsa);
 BIO_free(cleartext);
 BIO_free_all(crypted);
 if rsa_in <> nil then OPENSSL_free(rsa_in);
 if rsa_out <> nil then OPENSSL_free(rsa_out);
end;






function str2hex(s: string; var buf: array of byte): integer;
var
 i: integer;
begin
 result:=0;
 for i:=1 to length(s) div 2 do begin
  buf[i-1]:= strtoint('$'+copy(s,i*2-1,2));
  inc(result);
 end;
end;



function decodeRC4(source: TFileStream; var dest: TFileStream; enckey: string): boolean;
const
 BLOCKSIZE: Integer = 1024;
var
 RC4: TRC4Context;
 Len: Int64;
 SourceBuffer, DestBuffer: Pointer;
begin
 try
  GetMem(SourceBuffer, BLOCKSIZE);
  GetMem(DestBuffer, BLOCKSIZE);
  try
   RC4Init(RC4, enckey);
   while source.Position < source.Size do begin
    if source.Size - source.Position > BLOCKSIZE then Len := BLOCKSIZE
     else Len := source.Size - source.Position;
    source.ReadBuffer(SourceBuffer^, Len);
    RC4Code(RC4, SourceBuffer^, DestBuffer^, len);
    dest.WriteBuffer(DestBuffer^, Len);
   end;
   RC4Done(RC4);
   result:=true;
  finally
   FreeMemory(SourceBuffer);
   FreeMemory(DestBuffer);
  end;
 finally
 end;
end;



procedure RPLRClear(var source: TRplRecord);
begin
     source.NPC:='';
     source.CCC:='';
     source.HWC:='';
     source.SIMLOCK:='';
     source.SIMLOCK_KEY:='';
     source.SUPERDONGLE_KEY:='';
     source.CMLA_KEY:='';
     source.WMDRM_PD:='';
end;


function PlainRplPar(RS: TStrings): TRPLRecord;
var
 i:integer;
 sn,sv:string;
 RPLRecord: TRplRecord;
begin
 RPLRClear(RplRecord);
 for i:=0 to RS.Count-1 do begin
  sn:='';
  sv:='';
  if ((Pos('DATA',RS.Strings[i])<> 0) and (Pos('=',RS.Strings[i])<> 0)) then begin
   RS.NameValueSeparator:='=';
   sn:=RS.Names[i];
   sv:=RS.ValueFromIndex[i];
   if Pos ('NPC',sn)<>0 then RPLRecord.NPC:=RPLRecord.NPC+sv;
   if Pos ('CCC',sn)<>0  then RPLRecord.CCC:=RPLRecord.CCC+sv;
   if Pos ('HWC',sn)<>0  then RPLRecord.HWC:=RPLRecord.HWC+sv;
   if Pos ('SIMLOCK_DATA',sn)<>0  then RPLRecord.SIMLOCK:=RPLRecord.SIMLOCK+sv;
   if Pos ('SIMLOCK_KEY',sn)<>0 then RPLRecord.SIMLOCK_KEY:=RPLRecord.SIMLOCK_KEY+sv;
   if Pos ('SUPERDONGLE_KEY',sn)<>0  then RPLRecord.SUPERDONGLE_KEY:=RPLRecord.SUPERDONGLE_KEY+sv;
   if Pos ('CMLA_KEY',sn)<>0  then RPLRecord.CMLA_KEY:=RPLRecord.CMLA_KEY+sv;
   if Pos ('WMDRM_PD',sn)<>0  then RPLRecord.WMDRM_PD:=RPLRecord.WMDRM_PD+sv;
  end;
 end;
 result:=RplRecord;
end;


procedure CreatePrivateKey(key: string);
var
 keyfile: THandle;
 count: Cardinal;
begin
 keyfile:= CreateFile(PChar(key), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 WriteFile(keyfile,datakey,1704,count,nil);
 CloseHandle(keyfile);
end;


function DecodeRPL(filename: string; savefile: boolean = false): TRPLRecord;
var
 stream, temp_stream, stream_rpl: TMemoryStream;
 buff, buff_temp: array of byte;
 tempvalue: byte;
 temp1,temp2: char;
 i, size: integer;
 programdir, tempfilename, enckey: string;
 source, dest: TFileStream;
 recordrpl: TStrings;
begin
 GetDir(0,programdir);
 InitOpenSSL;
 stream:=TMemoryStream.Create;
 stream_rpl:=TMemoryStream.Create;
 temp_stream:=TMemoryStream.Create;

 stream.LoadFromFile(filename);
 stream.Seek($E,soFromBeginning);
 setlength(buff,512);
 enckey:='';
 for i:=0 to 511 do begin
  stream.Read(buff[i],1);
  if buff[i]=$0D then stream.Read(buff[i],1);
  if buff[i]=$0A then stream.Read(buff[i],1);
  enckey:=enckey+chr(buff[i]);
 end;
 setlength(buff_temp,256);
 size:=str2hex(enckey,buff_temp);

 if size=256 then begin
  initopenssl;
  for i:=0 to high(buff_temp) do temp_stream.WriteBuffer(buff_temp[i], 1);
  temp_stream.SaveToFile('temp1.rpl');
  tempfilename:=ExtractFilePath(Application.ExeName)+'flash\ADLREVFFF.adl';
  //tempfilename:='ADLREVFFF.adl';
  CreatePrivateKey(tempfilename);
  rsadecrypt(tempfilename,'temp1.rpl','temp2.rpl',RSA_PKCS1_OAEP_PADDING);
  freeopenssl;
  deletefile(PChar(tempfilename));
  deletefile('temp1.rpl');
  temp_stream.Clear;

  temp_stream.LoadFromFile('temp2.rpl');
  buff:=nil;
  setlength(buff,temp_stream.size);
  enckey:='';
  for i:=0 to temp_stream.size-1 do begin
   temp_stream.Read(buff[i],1);
   enckey:=enckey+chr(buff[i]);
  end;
  deletefile('temp2.rpl');

  temp_stream.Clear;
  size:=stream.Size-stream.Position;
  for i:=1 to size do begin
   stream.Read(tempvalue,1);
   if (tempvalue<>$0D)and(tempvalue<>$0A) then begin
    stream.Seek(-1,soFromCurrent);
    temp_stream.CopyFrom(stream,1);
   end;
  end;
  temp_stream.Seek(0,soFromBeginning);
  buff_temp:=nil;
  stream_rpl.Clear;
  setlength(buff_temp,temp_stream.size div 2);
  for i:=1 to temp_stream.Size div 2 do begin
   temp_stream.Read(temp1,1);
   temp_stream.Read(temp2,1);
   tempvalue:= strtoint('$'+temp1+temp2);
   stream_rpl.WriteBuffer(tempvalue,1);
  end;
  stream_rpl.SaveToFile('prepare.rpl');

  source:=TFileStream.Create('prepare.rpl',fmOpenRead);
  tempfilename:=copy(FileName,1,length(FileName)-4)+'_plain.rpl';
  dest:=TFileStream.Create(tempfilename,fmCreate);
  decodeRC4(source,dest,enckey);
  source.Free;
  dest.Free;
  deletefile('prepare.rpl');

  recordrpl:= TStringList.Create;
  recordrpl.LoadFromFile(tempfilename);
  result:=PlainRplPar(recordrpl);
  //showmessage(copy(result.NPC,1,10));
  if not savefile then deletefile(tempfilename);
 end;
end;





end.

