* * * *
13 Visitatori, 0 Utenti

21 Ott 2011 - Codice di attivazione

Cosa succede quando avete finito un software e volete distribuirlo, previa vostra autorizzazione? Questo How To vi viene incontro e vi spiega come io ho affrontato il problema.

La soluzione a tale problema è composta di due parti, un codice php posizionato nel sito dal quale distribuisco il software e dal quale faccio fare l'attivazione del prodotto.


Quella che segue è la classe PHP che mi genera il mio codice di attivazione nel formato: XXXX-XXXX-XXXX-XXXX


[code]

/*

    Classe realizzata da Sammarco Francesco
    Es:

    $OggettoSN = new Serial_Number;
    $CodSer = $OggettoSN->PKV_MakeKey($IdCod);
*/

class Serial_Number
{

    // Costruttore
    function __construct()
    {
    }

    // Distruttore
      public function __destruct()
    {
            //non faccio niente
    }
    private function Shr($a, $b)
    {
        return ($a/(2^$b));
    }


    private function PKV_GetKeyByte($Seed,$a,$b,$c)
    {
        $a = $a % 25;
        $b = $b % 3;
        if( $a % 2 == 0 )
        {
          $result = ( $Seed >> $a ) ^ ( ( $Seed >> $b ) | $c );
        } else
        {
          $result = ( $Seed >> $a ) ^ ( ( $Seed >> $b ) & $c );
        }
        return $result & 0x000000FF;
       }

       private function IntToHex($Variabile,$Num)
       {
           $result=dechex($Variabile);
           $k=$Num-strlen($result);
           for($i=0;$i<$k;$i++)
           {
               $result="0" . $result;
           }
           return strtoupper($result);
       }

    public function PKV_MakeKey($Seed)
    {
          $KeyBytes[0]=$this->PKV_GetKeyByte($Seed, 24, 3, 200);
          $KeyBytes[1]=$this->PKV_GetKeyByte($Seed, 10, 0, 56);
          $KeyBytes[2]=$this->PKV_GetKeyByte($Seed, 1, 2, 91);
          $KeyBytes[3]=$this->PKV_GetKeyByte($Seed, 7, 1, 100);

          $result=$this->IntToHex($Seed,8);
          for ($i=0;$i<=3;$i++)
          {
              $result=$result . $this->IntToHex($KeyBytes[$i],2);
          }
          $valorecs=$this->PKV_GetChecksum($result);
          $result=$result . $valorecs;
          $app="";
          $j=1;
          for ($i=0;$i

          {
              if (($j == 4)&&($i<(strlen($result)-1)))
              {
                  $app=$app . $result[$i] . "-";
                  $j=1;
              }else
              {
                  $app=$app . $result[$i];
                  $j++;
              }
          }
          return $app;
    }

    private function PKV_GetChecksum($s)
    {
          $left = 0x0056;
          $right = 0x00AF;
        if(strlen($s) > 0 )
        {
            for( $i = 0 ; $i < strlen( $s ) ; $i++ )
            {
                  $right = $right + Ord($s[$i]);
                  if($right > 0x00FF )
                  {
                    $right=$right-0x00FF;
                }
                  $left=$left+$right;
                  if($left > 0x00FF )
                  {
                    $left=$left-0x00FF;
                }
            }
        }
          $sum = ( $left << 8 ) + $right;
          $result = $this->IntToHex($sum, 4 );
        return $result;
    }

}

?>

[/code]




Usare tale classe è molto molto semplice basta usare il codice (sempre in php):

    $OggettoSN = new Serial_Number;
    $CodSer = $OggettoSN->PKV_MakeKey($IdCod);   

Dove $IdCod equivale all'inizializzatore da cui mi ricavo il mio codice di attivazione e $CodSer è il nostro tanto agognato codice di serie.

Per rendere la nostra classe unica e diversa da questo codice di esempio basta cambiare i parametri numerici nella funzione PKV_GetKeyByte

         $KeyBytes[0]=$this->PKV_GetKeyByte($Seed, 24, 3, 200);
         $KeyBytes[1]=$this->PKV_GetKeyByte($Seed, 10, 0, 56);
         $KeyBytes[2]=$this->PKV_GetKeyByte($Seed, 1, 2, 91);
         $KeyBytes[3]=$this->PKV_GetKeyByte($Seed, 7, 1, 100);

Ora questa parte scritta in PHP crea un codice che comunico (tramite mail automatica) all'interessato.

Ora toccherà al programma (scritto in Lazarus) elaborare questa informazione, e io ho scritto una libreria per fare questo:

[code]

unit MySerialNumber;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

  const
  KEY_GOOD = 0;
  KEY_INVALID = 1;
  KEY_BLACKLISTED = 2;
  KEY_PHONY = 3;

  type
      SerialNumber=object
      private
      public
            function PKV_GetKeyByte(const Seed : Int64; a, b, c : Byte) : Byte;
            function PKV_CheckKey(const S : String) : Integer;
            function PKV_CheckKeyChecksum(const Key : String) : Boolean;
            function PKV_MakeKey(const Seed : Int64) : String;
            function PKV_GetChecksum(const s : String) : String;
      end;
var
                BL : array[0..0] of String = ('11111111');
implementation

{ serial number }
function StartsStr(str: string; inizio: string): boolean;
var
    Esci: boolean;
    ret: boolean;
    i: integer;
    len1: integer;
    len2: integer;
begin
    len1:=length(str);
    len2:=length(inizio);
    ret:=false;
    if len1>=len2 then
    begin
        i:=0;
        ret:=TRUE;
        if len1=0 then
            Esci:=TRUE
        else
            Esci:=FALSE;
        while (Esci=False) do
        begin
            if str[i]<>inizio[i] then
            begin
                Esci:=TRUE;
                ret:=FALSE;
            end;
            Inc(i);
            if i>len1 then
                Esci:=TRUE;
        end;
    end;
    StartsStr:=ret;
end;

function SerialNumber.PKV_GetKeyByte(const Seed : Int64; a, b, c : Byte) : Byte;
var
   risultato: byte;
begin
  a := a mod 25;
  b := b mod 3;
 if a mod 2 = 0 then
    risultato := ((Seed shr a) and $000000FF) xor ((Seed shr b) or c)
  else
    risultato := ((Seed shr a) and $000000FF) xor ((Seed shr b) and c);
    PKV_GetKeyByte:=risultato;
end;

function SerialNumber.PKV_GetChecksum(const s : String) : String;
var
  left, right, sum : Word;
  i : Integer;
  app: string;
begin
  left := $0056;
  right := $00AF;
if Length(s) > 0 then
    for i := 1 to Length(s) do
    begin
      right := right + Byte(s[i]);
      //app:= app + 'r: ' + s[i] + '(' + IntToStr(Byte(s[i])) + ')';
      //right := right + Byte(s[i]);
      if right > $00FF then
        Dec(right, $00FF);
      Inc(left, right);
      if left > $00FF then
        Dec(left, $00FF);
    end;
  sum := (left shl 8) + right;
  result := IntToHex(sum, 4);
end;

function SerialNumber.PKV_MakeKey(const Seed : Int64) : String;
var
  KeyBytes : array[0..3] of Byte;
  i : Integer;
  app: string;
begin
  // Fill KeyBytes with values derived from Seed.
  // The parameters used here must be extactly the same
  // as the ones used in the PKV_CheckKey function.
  // A real key system should use more than four bytes.
  KeyBytes[0] := PKV_GetKeyByte(Seed, 24, 3, 200);
  KeyBytes[1] := PKV_GetKeyByte(Seed, 10, 0, 56);
  KeyBytes[2] := PKV_GetKeyByte(Seed, 1, 2, 91);
  KeyBytes[3] := PKV_GetKeyByte(Seed, 7, 1, 100);
   // the key string begins with a hexidecimal string of the seed
  result := IntToHex(Seed, 8);
// then is followed by hexidecimal strings of each byte in the key
  for i := 0 to 3 do
  begin
    result := result + IntToHex(KeyBytes[i], 2);
  end;
// add checksum to key string
  result := result + PKV_GetChecksum(result);
// Add some hyphens to make it easier to type
  i := Length(result) - 3;
  while (i > 1) do
  begin
    Insert('-', result, i);
    Dec(i, 4);
  end;
end;

function SerialNumber.PKV_CheckKeyChecksum(const Key : String) : Boolean;
var
  s, c : String;
begin
  result := False;
 // remove cosmetic hypens and normalize case
  s := UpperCase(StringReplace(Key, '-', '', [rfReplaceAll]));
  if Length(s) <> 20 then
    exit; // Our keys are always 20 characters long
  // last four characters are the checksum
  c := Copy(s, 17, 4);
  SetLength(s, 16);
// compare the supplied checksum against the real checksum for
  // the key string.
  result := c = PKV_GetChecksum(s);
end;


function SerialNumber.PKV_CheckKey(const S : String) : Integer;
var
  Key, kb : String;
  Seed : Int64;
  i : Integer;
  b : Byte;
begin
  result := KEY_INVALID;
  if not PKV_CheckKeyChecksum(S) then
    exit; // bad checksum or wrong number of characters
 // remove cosmetic hypens and normalize case
  Key := UpperCase(StringReplace(S, '-', '', [rfReplaceAll]));
 // test against blacklist
  if Length(BL) > 0 then
    for i := Low(BL) to High(BL) do
      if StartsStr(BL[i], Key) then
      begin
        result := KEY_BLACKLISTED;
        exit;
      end;
// At this point, the key is either valid or forged,
  // because a forged key can have a valid checksum.
  // We now test the "bytes" of the key to determine if it is
  // actually valid.
// When building your release application, use conditional defines
  // or comment out most of the byte checks!  This is the heart
  // of the partial key verification system. By not compiling in
  // each check, there is no way for someone to build a keygen that
  // will produce valid keys.  If an invalid keygen is released, you
  // simply change which byte checks are compiled in, and any serial
  // number built with the fake keygen no longer works.
// Note that the parameters used for PKV_GetKeyByte calls MUST
  // MATCH the values that PKV_MakeKey uses to make the key in the
  // first place!
result := KEY_PHONY;
 // extract the Seed from the supplied key string
  if not TryStrToInt64('$' + Copy(Key, 1, 8), Seed) then
    exit;
{$IFDEF KEY00}
  kb := Copy(Key, 9, 2);
  b := PKV_GetKeyByte(Seed, 24, 3, 200);
  if kb <> IntToHex(b, 2) then
    exit;
  {$ENDIF}
{$IFDEF KEY01}
  kb := Copy(Key, 11, 2);
  b := PKV_GetKeyByte(Seed, 10, 0, 56);
  if kb <> IntToHex(b, 2) then
    exit;
  {$ENDIF}
  {$IFDEF KEY02}
  kb := Copy(Key, 13, 2);
  b := PKV_GetKeyByte(Seed, 1, 2, 91);
  if kb <> IntToHex(b, 2) then
    exit;
  {$ENDIF}
  {$IFDEF KEY03}
  kb := Copy(Key, 15, 2);
  b := PKV_GetKeyByte(Seed, 7, 1, 100);
  if kb <> IntToHex(b, 2) then
    exit;
  {$ENDIF}
 // If we get this far, then it means the key is either good, or was made
  // with a keygen derived from "this" release.
result := KEY_GOOD;
end;

end.


[/code]

Quello che è importante è che i valori numerici della funzione PKV_GetKeyByte siano valorizzati in maniera identica con quelli del codice PHP

  KeyBytes[0] := PKV_GetKeyByte(Seed, 24, 3, 200);
  KeyBytes[1] := PKV_GetKeyByte(Seed, 10, 0, 56);
  KeyBytes[2] := PKV_GetKeyByte(Seed, 1, 2, 91);
  KeyBytes[3] := PKV_GetKeyByte(Seed, 7, 1, 100);


Per poter sfruttare questa libreria bastano poche linee di codice in free pascal

     if length(Codice)=24 then
     begin
          Valore:=MioOggetto.PKV_CheckKey(Codice);
          if Valore=0 then
          begin

                 {CODICE DI ATTIVAZIONE VALIDO}
          end;
     end;

Dove la variabile Codice è valorizzata con il codice che precedentemente avevamo comunicato al nostro cliente.

Bene questa è la soluzione che avevo usato io in uno dei miei progetti. Se avete altre soluzioni non esitate a comunicarmele e vedrò di pubblicarle. Avverto che pubblicherò solo soluzioni che possono essere multipiattaforma.


Share on Twitter! Digg this story! Del.icio.us Share on Facebook! Technorati Reddit StumbleUpon

Articles in « How to »

Comments *

1) Re: Codice di attivazione
Written by antoniog il Ottobre 11, 2013, 02:45:43 am
Molto interessante! mi piacerebbe svilupparlo ed usarlo, è possibile avere un esempio funzionante da scaricare. grazie
Commenting option has been turned off for this article.

Recenti

How To

Trascinare un file nel programma da xinyiman
DB concetti fondamentali e ZeosLib da xinyiman
Recuperare codice HTML da pagina web da xinyiman
Mandare mail con Lazarus da xinyiman
Stabilire il sistema operativo da xinyiman
Esempio lista in pascal da xinyiman
File INI da xinyiman
Codice di attivazione da xinyiman
Realizzare programmi multilingua da xinyiman
Lavorare con le directory da xinyiman
Utilizzare Unità esterne da Loryea
TTreeView da xinyiman
TTreeview e Menu da xinyiman
Generare controlli RUN-TIME da xinyiman
LazReport, PDF ed immagini da xinyiman
Intercettare tasti premuti da xinyiman
Ampliare Lazarus da xinyiman
Lazarus e la crittografia da xinyiman
System Tray con Lazarus da xinyiman
UIB: Unified Interbase da Microges2000
Il file: questo sconosciuto da Microges2000
Conferma di chiusura di un applicazione da xinyiman
Liste e puntatori da Microges2000
Overload di funzioni da Microges2000
Funzioni a parametri variabili da Microges2000
Proprietà da Microges2000
Conversione numerica da Microges2000
TImage su Form e Panel da Maverich
Indy gestiore server FTP lato Client da Maverich
PopUpMenu sotto Pulsante (TSpeedButton) da Maverich
Direttiva $macro da Microges2000
Toolbar da xinyiman
Evidenziare voci TreeView da Maverich
Visualizzare un file Html esterno da Maverich
StatusBar - aggirare l'errore variabile duplicata da Maverich
Da DataSource a Excel da xinyiman
Le permutazioni da xinyiman
Brute force da xinyiman
Indy 10 - Invio email con allegati da Maverich
La gestione degli errori in Lazarus da xinyiman
Pascal Script da xinyiman
Linux + Zeos + Firebird da xinyiman
Dataset virtuale da xinyiman
Overload di operatori da Microges2000
Lavorare con file in formato JSON con Lazarus da nomorelogic
Zeos ... dietro le quinte (prima parte) da Stilgar
Disporre le finestre in un blocco unico (come Delphi) da Maverich
Aspetto retrò (Cmd Line) da xinyiman
Come interfacciare periferica twain da Narciso
Ubuntu - aggiornare free pascal e lazarus da xinyiman
fpcup: installazioni parallele di lazarus e fpc da nomorelogic
Free Pascal e Lazarus sul Raspberry Pi da nomorelogic
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal. da nomorelogic
Creare un server multithread da xinyiman
guida all'installazione di fpc trunk da subversion in linux gentoo da nomorelogic
Indice da nomorelogic
DB concetti fondamentali e connessioni standard da xinyiman
Advanced Record Syntax da nomorelogic
DB concetti fondamentali e DBGrid da xinyiman
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText da xinyiman
Advanced Record Syntax: un esempio pratico da nomorelogic
Superclasse form base per programmi gestionali (e non) da nomorelogic
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox da nomorelogic
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form da nomorelogic
Superclasse form base per programmi gestionali (e non) #4 - wait animation da nomorelogic
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog da nomorelogic
Installare lazarus su mac osx sierra da xinyiman
Utenti
Stats
  • Post in totale: 10493
  • Topic in totale: 1336
  • Online Today: 15
  • Online Ever: 74
  • (Luglio 09, 2012, 11:05:53 am)
Utenti Online
Users: 0
Guests: 13
Total: 13

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.