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<strlen($result);$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.



SMF 2.0.8 | SMF © 2011, Simple Machines
Privacy Policy
SMFAds for Free Forums
TinyPortal © 2005-2012

Go back to article