unit DbSNSEncrypt;

interface

uses
  Windows, SysUtils, Forms, Classes;

function SimpleSNSCheck: Integer;
function CheckSNSTimes(AIsOnOpen: Boolean = False): Integer;
function CheckSNSHours: Integer;
function CheckSNSAdditionEdition: Integer;
function CheckSNSEdition: Integer;
function CheckSNSData: Integer;
function CheckSNSLimitDate: Integer;

function GetSNSReportOprNum(AOpr: string): Integer;

function GetSNSReportFuncNum(AOpr: string): Integer;

function OpenSNSDog: Integer;

procedure SaveSNSDog;

function SNSUserAuthorize(AAuthorize: array of Byte): Boolean;

function SNSUserUpdateLock(AUpdateData: array of Byte): Boolean;

implementation

uses
  Math, CommonMessages, ScUtils, DbEncryptPWD, S4CryptUtils, ScConfig,
  DbEncryptUnit, DbS4Utils, DbEncryptTypes, DbEncryptEditions, DbConnectEncrypt,
  ScPHPWeb;

var
  DogAddr: integer;
  DogBytes: integer;
  DogData: ^byte;

  IsNet: Boolean;
  RefCount: Integer;  

const
  SDSerialNo: array [0..9] of Byte = ($00, $00, $00, $06, $FB, $FB, $F7, $FB, $FD, $FF);

function WriteDog: LongInt; external;
function ReadDog: LongInt; external;
{$L rgdlw32d.obj}

// 检查软件狗厂家序列号
function SimpleSNSCheck: Integer;
var
  dwRetCode: longint;
  dwSerialNumber: Longint;
  aSDSN: array [0..9] of Byte;
  strSN: string[6];
  aStrSN: array [0..5] of Byte;
  I: Integer;
begin
  Result := -1;
  DogBytes := 0;     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := 0;
  DogData := @dwSerialNumber;

  if not IsNet then
    dwRetCode := ReadDog
  else
  begin
    if ReadDogData(DogAddr, DogBytes, DogData) then
      dwRetCode := 0
    else dwRetCode := 1;
  end;
  
  if dwRetCode = 0 then
  begin
    strSN := IntToStr(dwSerialNumber);//IntToHex(dwSerialNumber, 6);

    for I := Low(aStrSN) to High(aStrSN) do
      aStrSN[I] := StrToInt(strSN[I + 1]);

    Encrypt_Simple(aStrSN, Length(aStrSN), aSDSN{, Length(aSDSN)});

    Result := DT_SN_SD;
    for I := 0 to Length(aSDSN) - 1 do
    begin
      if aSDSN[I] <> SDSerialNo[I] then
        Result := -1;
    end;
  end;
end;

function CheckSNSTimes(AIsOnOpen: Boolean): Integer;
var
  aData: array [0..11] of Byte;
  iTimes, iRunTimes: Word;
begin
  if IsNet then
  begin
    Result := CS_Success;
    Exit;
  end;

  Result := CS_Error;
  if SimpleSNSCheck < 0 then
    Exit;

  iTimes := 0;
  ZeroMemory(@aData[0], Length(aData));
  // 实际是$10-$11，$12-$13，为迷惑，取$0E-$19
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $0E;
  DogData := @aData[0];
  if ReadDog = 0 then
  begin
    iTimes := aData[2] shl 8 + aData[3];
    iRunTimes := aData[4] shl 8 + aData[5];
  end;

  if iTimes = 0 then
    Exit;

  if iTimes = $FFFF then
  begin
    Result := CS_Success;
    Exit;
  end;

  bAuthorized := False;

  Activations := iRunTimes;

  if AIsOnOpen then
  begin
    if iRunTimes >= iTimes then
      Result := CS_NeedAuthorize
    else
      Result := CS_WantAuthorize;
  end
  else
  begin
    if iRunTimes > iTimes then
      Result := CS_NeedAuthorize
    else
      Result := CS_WantAuthorize;
  end;
end;

function CheckSNSHours: Integer;
var
  aData: array [0..11] of Byte;
  iSeconds, iRunSeconds: Cardinal;
begin
  if IsNet then
  begin
    Result := CS_Success;
    Exit;
  end;
  
  Result := CS_Error;
  if SimpleSNSCheck < 0 then
    Exit;

  iSeconds := 0;
  ZeroMemory(@aData[0], Length(aData));
  // 实际是$08-$0B，$0C-$0F，为迷惑，取$07-$12
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $07;
  DogData := @aData[0];
  if ReadDog = 0 then
  begin
    iSeconds := ((aData[1] shl 8 + aData[2]) shl 8 + aData[3]) shl 8 + aData[4];
    iRunSeconds := ((aData[5] shl 8 + aData[6]) shl 8 + aData[7]) shl 8 + aData[8];
  end;

  if iSeconds = 0 then
    Exit;

  if iSeconds = $FFFFFFFF then
  begin
    Result := CS_Success;
    Exit;
  end;

  bAuthorized := False;

  LastTime := iRunSeconds;

  if iRunSeconds > iSeconds then
    Result := CS_NeedAuthorize
  else
    Result := CS_WantAuthorize;
end;

function CheckSNSLimitDate: Integer;
var
  aData: array [0..11] of Byte;
  iType: Byte;
  iUserDate, iLimitDate: Cardinal;
  fDate, fCompileDate: TDateTime;

begin
  if IsNet then
  begin
    Result := CS_Success;
    Exit;
  end;

  Result := CS_Error;
  if SimpleSNSCheck < 0 then
    Exit;

  // 先判断是否时间限制狗
  ZeroMemory(@aData[0], Length(aData));
  // 实际是$51，为迷惑，取$48-$53
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $48;
  DogData := @aData[0];
  if (ReadDog = 0) and (aData[9] <> Ord(etDate)) then
  begin
    Result := CS_Ignore;
    Exit;
  end;
  bAuthorized := False;
  ZeroMemory(@aData[0], Length(aData));
  // 实际是$20-$23，$24-$27，为迷惑，取$1E-$29
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $1E;
  DogData := @aData[0];
  if ReadDog = 0 then
  begin
    iUserDate := ((aData[2] shl 8 + aData[3]) shl 8 + aData[4]) shl 8 + aData[5];
    iLimitDate := ((aData[6] shl 8 + aData[7]) shl 8 + aData[8]) shl 8 + aData[9];
  end;

  fDate := PHPWeb.SystemDateTime;
  fCompileDate := CompileDateTime;
  if fCompileDate > iLimitDate then
  begin
    Result := CS_EndDate;
    Exit;
  end;

  if fDate > iLimitDate then
    Result := CS_EndDate
  else if iLimitDate - fDate < 7 then
    Result := CS_CloseToLimitDate
  else
    Result := CS_Success;
end;

function CheckSNSAdditionEdition: Integer;
var
  aData: array [0..15] of Byte;
  iEdition: Byte;
  dwRetCode: Integer;
begin
  Result := CS_NoDog;
  if SimpleSNSCheck < 0 then
    Exit;
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $4E;
  DogData := @aData[0];

  if not IsNet then
    dwRetCode := ReadDog
  else
  begin
    if ReadDogData(DogAddr, DogBytes, DogData) then
      dwRetCode := 0
    else dwRetCode := 1;
  end;  

  if dwRetCode = 0 then
  begin
    {$IFDEF _ScBills}
    if aData[0] = $08 then
    {$ENDIF}
    {$IFDEF _ScBudget}
      {$IFDEF _ScEstimate}
    if aData[2] = $24 then
      {$ELSE}
    if aData[1] = $16 then
      {$ENDIF}
    {$ENDIF}
      Result := CS_Success
    else
      Result := CS_NeedUpdate;
  end;
end;

function CheckSNSEdition: Integer;
var
  aData: array [0..11] of Byte;
  iEdition: Byte;
  dwRetCode: Integer;
begin
  Result := CS_NoDog;
  if SimpleSNSCheck < 0 then
    Exit;

  iEdition := 0;
  // 实际是$07，为迷惑，取$02-$0D
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $02;
  DogData := @aData[0];

  if not IsNet then
    dwRetCode := ReadDog
  else
  begin
    if ReadDogData(DogAddr, DogBytes, DogData) then
      dwRetCode := 0
    else dwRetCode := 1;
  end;

  if dwRetCode = 0 then
    iEdition := aData[5];

  if iEdition = 0 then
    Exit;

  DogEdition := iEdition;
  if CheckEncryptEdition(iEdition) then
(*  if iEdition in {$IFDEF _ScPersonal}
                   [164]                          // 个人版
                 {$ENDIF}
                 {$IFDEF _ScBillsForArch}
                   {$IFDEF _ScBills}
                   [178, 162]                     // 建筑版 ，招投标版
                   {$ELSE}
                   [178]                          // 建筑版
                   {$ENDIF}
                 {$ELSE}
                   {$IFDEF _ScBills}
                     {$IFDEF _ScJiangXi}
                       [34]                       // 江西专业版
                     {$ELSE}
                       {$IFDEF _ScGanSu}
                         {$IFDEF _ScGanSu_XX}
                         [88]                       // 甘肃农村版
                         {$ELSE}
                         [81]                     // 甘肃专业版
                         {$ENDIF}
                       {$ELSE}
                         {$IFDEF _ScHeBei}
                           [61]                   // 河北专业版
                         {$ELSE}
                           [161, 162]             // 专业版/招投标版
                         {$ENDIF}
                       {$ENDIF}
                     {$ENDIF}
                   {$ENDIF}
                   {$IFDEF _ScBudget}
                     {$IFDEF _ScGanSu}
                       {$IFDEF _ScGanSu_XX}
                       [88]                       // 甘肃农村版
                       {$ELSE}
                       [81, 82]                   // 甘肃专业版/甘肃概预估算版
                       {$ENDIF}
                     {$ELSE}
                       {$IFDEF _ScJiangXi}
                         {$IFDEF _ScYangHu_JiangXi}
                         [33]                     // 江西养护预算版
                         {$ELSE}
                         [33, 34]                     // 江西专业版
                         {$ENDIF}
                       {$ELSE}
                         {$IFDEF _ScHeBei}        // 河北专业版
                           [61]
                         {$ELSE}
                           {$IFDEF _ScEstimate}
                           [161, 163]             // 专业版/概预估算版
                           {$ELSE}
                           [161, 163, 33]         // 专业版/概预估算版/江西养护预算版
                           {$ENDIF}
                         {$ENDIF}
                       {$ENDIF}
                     {$ENDIF}
                   {$ENDIF}
                 {$ENDIF} then*)
    Result := CS_Success
  else
    Result := CS_DogTypeError;
end;

function CheckSNSData: Integer;
var
  iCheckData, iOutputLength: Integer;
  pKey: Pointer;
  arrKey: array [0..11] of Byte;
  arrKey2: array [0..11] of Byte;
  arrSN: array [0..11] of Byte;
  I, dwRetCode: Integer;
  bIsZero: Boolean;
begin
  Result := CS_NoDog;

  if SimpleSNSCheck < 0 then
    Exit;

  Randomize;
  iCheckData := RandomRange(11000, 11050);
  case iCheckData of
    11011..11020:
    begin
      Result := CS_Ignore;
      Exit;
    end;
  end;

  //strS4SN := '';
  ZeroMemory(@arrKey[0], Length(arrKey));
  // 实际是$00-$05，为迷惑，取$00-$0B
  DogBytes := Length(arrKey);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $00;
  DogData := @arrKey[0];

  if not IsNet then
    dwRetCode := ReadDog
  else
  begin
    if ReadDogData(DogAddr, DogBytes, DogData) then
      dwRetCode := 0
    else dwRetCode := 1;
  end;

  if dwRetCode = 0 then
  begin
    bIsZero := True;
    for I := 0 to 5 do
    begin
      if arrKey[I] <> 0 then
      begin
        bIsZero := False;
        Break;
      end;
    end;
    if bIsZero then
      Exit;
  end
  else
    Exit;
  ZeroMemory(@arrKey2[0], Length(arrKey2));
  ZeroMemory(@arrSN[0], Length(arrSN));
  // 实际是$14-$1F
  DogBytes := Length(arrSN);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $14;
  DogData := @arrSN[0];

  if not IsNet then
    dwRetCode := ReadDog
  else
  begin
    if ReadDogData(DogAddr, DogBytes, DogData) then
      dwRetCode := 0
    else dwRetCode := 1;
  end;

  if dwRetCode = 0 then
  begin
    pKey := nil;
    try
      Decrypt_BlowFish(EncryptKey, @arrSN[0], 12, pKey, iOutputLength);
      CopyMemory(@arrKey2[0], pKey, iOutputLength);
    finally
      if Assigned(pKey) then
        FreeMem(pKey);
    end;
  end;
  for I := 0 to 5 do
  begin
    if arrKey[I] <> arrKey2[I] then
    begin
      Result := CS_VerifyError;
      Exit;
      Break;
    end;
  end;
  strHaspID := '';
  for I := 0 to 5 do
    strHaspID := strHaspID + IntToHex(arrKey[I], 1);
  Result := CS_Success;
end;

function GetSNSReportOprNum(AOpr: string): Integer;
const
  OprStr = '[,-,*,^,:=,/,p,<,<=,>=,>,+,<>,=,or,!=,and,f';
var
  OprStrs: TStringList;
  StrIndex, dwRetCode: Integer;
  OprNum: Byte;
  aData: array [0..19] of Byte;
begin
  Result := -1;
  StrIndex := GetReportOprList.IndexOf(AOpr);
  if StrIndex > -1 then
  begin
    Result := Integer(GetReportOprList.Objects[StrIndex]);
  end
  else
  begin
    OprStrs := TStringList.Create;
    try
      OprStrs.CommaText := OprStr;
      DogBytes := Length(aData);
      DogAddr := $30;
      DogData := @aData[0];

      if not IsNet then
        dwRetCode := ReadDog
      else
      begin
        if ReadDogData(DogAddr, DogBytes, DogData) then
          dwRetCode := 0
        else dwRetCode := 1;
      end;

      if dwRetCode = 0 then
      begin
        StrIndex := OprStrs.IndexOf(AOpr);
        if StrIndex >= 0 then
        begin
          OprNum := aData[StrIndex];
          GetReportOprList.AddObject(AOpr, Pointer(OprNum));
          Result := OprNum;
        end;
      end;
    finally
      OprStrs.Free;
    end;
  end;
end;

function GetSNSReportFuncNum(AOpr: string): Integer;
const
  FuncStr = 'sql,treechapterinsert,getindex,addnull,shrink,copy,'+
            'sorttreechapter,joindata,chapterinsert,'+
            'refcopy,count,refcopyex1';
var
  FuncStrs: TStringList;
  StrIndex, dwRetCode: Integer;
  OprNum: Byte;
  aData: array [0..19] of Byte;
begin
  Result := -1;
  StrIndex := GetReportFuncList.IndexOf(AOpr);
  if StrIndex > -1 then
  begin
    Result := Integer(GetReportFuncList.Objects[StrIndex]);
  end
  else
  begin
    FuncStrs := TStringList.Create;
    try
      FuncStrs.CommaText := FuncStr;
      DogBytes := Length(aData);
      DogAddr := $42;
      DogData := @aData[0];

      if not IsNet then
        dwRetCode := ReadDog
      else
      begin
        if ReadDogData(DogAddr, DogBytes, DogData) then
          dwRetCode := 0
        else dwRetCode := 1;
      end;

      if dwRetCode = 0 then
      begin
        StrIndex := FuncStrs.IndexOf(AOpr);
        if StrIndex >= 0 then
        begin
          OprNum := aData[StrIndex];
          GetReportFuncList.AddObject(AOpr, Pointer(900 + OprNum));
          Result := 900 + OprNum;
        end;
      end;
    finally
      FuncStrs.Free;
    end;
  end;
end;

function OpenSNSDog: Integer;
var
  aData: array [0..11] of Byte;
  iTimes: Word;
  iTimes1, iTimes2: Byte;
begin
  if IsNet then
  begin
    Result := CS_Success;
    Exit;
  end;

  Result := CS_Error;
  // 实际是$10-$11，$12-$13，为迷惑，取$0C-$17
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $0C;
  DogData := @aData[0];
  if ReadDog = 0 then
  begin
    iTimes := aData[6] shl 8 + aData[7];
  end
  else
    Exit;

  iTimes := iTimes + 1;
  iTimes1 := iTimes shr 8;
  iTimes2 := iTimes and $00FF;
  DogBytes := 1;     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $12;
  DogData := @iTimes1;
  if WriteDog <> 0 then
    Exit;
  DogBytes := 1;     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $13;
  DogData := @iTimes2;
  if WriteDog <> 0 then
    Exit;

  Result := CS_Success;
end;

procedure SaveSNSDog;
var
  aData: array [0..11] of Byte;
  aSecData: array [0..3] of Byte;
  iLastTime, iRunSeconds: LongWord;
  iBytesReturned: Cardinal;
begin
  if IsNet then Exit;

  RunTime := GetTickCount div 1000;
  if RunTime < StartTime then
  begin
    iLastTime := High(LongWord) div 1000 + RunTime - StartTime;
  end
  else
    iLastTime := RunTime - StartTime;

  // 实际是$08-$0B，$0C-$0F，为迷惑，取$04-$0F
  DogBytes := Length(aData);     {if you want to Read SerialNo DogBytes must be 0}
  DogAddr := $04;
  DogData := @aData[0];
  if ReadDog = 0 then
  begin
    iRunSeconds := ((aData[$08] shl 8 + aData[$09]) shl 8 + aData[$0A]) shl 8 + aData[$0B];
    iLastTime := iLastTime + iRunSeconds;

    aSecData[$00] := iLastTime shr 24;
    aSecData[$01] := (iLastTime shr 16) and $00FF;
    aSecData[$02] := (iLastTime and $0000FFFF) shr 8;
    aSecData[$03] := iLastTime and $000000FF;

    DogBytes := Length(aSecData);     {if you want to Read SerialNo DogBytes must be 0}
    DogAddr := $0C;
    DogData := @aSecData[0];
    WriteDog;
  end;
end;

function _SNSUserAuthorize10(AAuthorize: array of Byte): Boolean;
var
  iOutputLength: Integer;
  arrSN: array [0..5] of Byte;
  arrSN2: array [0..5] of Byte;
  arrKey: array [0..11] of Byte;
  pEncryptKey: Pointer;
  pKey: Pointer;
  pSN: Pointer;
  bRightKey: Boolean;
  strS4SNDC, strS4SN: string[6];
  pData: _PEncryptData10;
  iFileSize, iDataSize: Integer;
  iBytesReturned: Cardinal;
  aData2002: array [0..1] of Byte;
  aData2003: array [0..11] of Byte;
  I: Integer;
begin
  Result := False;

  iDataSize := SizeOf(_TEncryptData10);
  iFileSize := iDataSize;
  if iFileSize mod 8 <> 0 then
    iFileSize :=  8 * (iFileSize div 8 + 1);


  pEncryptKey := AllocMem(iFileSize);
  pKey := nil;
  New(pData);
  try
    CopyMemory(pEncryptKey, @AAuthorize[0], iFileSize);
    Decrypt_BlowFish(AuthorizeKey, pEncryptKey, iFileSize, pKey, iDataSize);

    CopyMemory(pData, pKey, iDataSize);

    CopyMemory(@arrKey[0], @(pData^.Key[0]), Length(arrKey));

    pSN := nil;
    try
      Decrypt_BlowFish(AuthorizeKey, @arrKey[0], Length(arrKey), pSN, iOutputLength);
      ZeroMemory(@arrSN2[0], Length(arrSN2));
      CopyMemory(@arrSN2[0], pSN, Length(arrSN2));
    finally
      if Assigned(pSN) then
        FreeMem(pSN);
    end;

    strS4SNDC := '';
    for I := Low(arrSN2) to High(arrSN2) do
      strS4SNDC := strS4SNDC + IntToHex(arrSN2[I], 1);

    // 读出序列号
    DogBytes := Length(arrSN);
    DogAddr := $00;
    DogData := @arrSN[0];
    ZeroMemory(@arrSN[0], Length(arrSN));
    if ReadDog = 0 then
    begin
      strS4SN := '';
      for I := Low(arrSN) to High(arrSN) do
        strS4SN := strS4SN + IntToHex(arrSN[I], 1);
    end
    else
      Exit;

    // 如果验证序列号相同，设置允许时间和允许次数
    if SameText(strS4SN, strS4SNDC) then
    begin
      DogBytes := Length(aData2003);
      DogAddr := $08;
      DogData := @aData2003[0];
      ZeroMemory(@aData2003[0], Length(aData2003));
      if ReadDog = 0 then
      begin
        {do nothing}
      end
      else
        Exit;
      // 允许时间
      aData2003[0] := pData^.LimitSeconds shr 24;
      aData2003[1] := (pData^.LimitSeconds shr 16) and $00FF;
      aData2003[2] := (pData^.LimitSeconds and $0000FFFF) shr 8;
      aData2003[3] := pData^.LimitSeconds and $000000FF;
      // 允许次数
      aData2003[8] := pData^.LimitTimes shr 8;
      aData2003[9] := pData^.LimitTimes and $00FF;

      DogBytes := Length(aData2003);
      DogAddr := $08;
      DogData := @aData2003[0];
      if WriteDog = 0 then
      begin

      end
      else
        Exit;

      // 版本
      DogBytes := Length(aData2002);
      DogAddr := $06;
      DogData := @aData2002[0];
      aData2002[0] := pData^.ProductID;
      aData2002[1] := pData^.Editon;
      if WriteDog = 0 then
      begin

      end
      else
        Exit;
    end
    else
      Exit;

    bAuthorized := True;
    Result := True;
  finally
    Dispose(pData);
    if Assigned(pKey) then
      FreeMem(pKey);
    if Assigned(pEncryptKey) then
      FreeMem(pEncryptKey);
  end;
end;

function _SNSUserAuthorize20(AAuthorize: array of Byte): Boolean;
var
  iOutputLength: Integer;
  arrSN: array [0..5] of Byte;
  arrSN2: array [0..5] of Byte;
  arrKey: array [0..11] of Byte;
  pEncryptKey: Pointer;
  pKey: Pointer;
  pSN: Pointer;
  bRightKey: Boolean;
  strS4SNDC, strS4SN: string[6];
  pData: PEncryptData;
  iFileSize, iDataSize: Integer;
  iBytesReturned: Cardinal;
  aData2002: array [0..1] of Byte;
  aData2003: array [0..11] of Byte;
  aDataLimitDate: array [0..3] of Byte;
  I: Integer;
begin
  Result := False;

  iDataSize := SizeOf(TEncryptData);
  iFileSize := iDataSize;
  if iFileSize mod 8 <> 0 then
    iFileSize :=  8 * (iFileSize div 8 + 1) + SizeOf(Integer);


  pEncryptKey := AllocMem(iFileSize);
  pKey := nil;
  New(pData);
  try
    CopyMemory(pEncryptKey, @AAuthorize[0], iFileSize);
    Decrypt_BlowFish(AuthorizeKey, pEncryptKey, iFileSize, pKey, iDataSize);

    CopyMemory(pData, pKey, iDataSize);

    CopyMemory(@arrKey[0], @(pData^.Key[0]), Length(arrKey));

    pSN := nil;
    try
      Decrypt_BlowFish(AuthorizeKey, @arrKey[0], Length(arrKey), pSN, iOutputLength);
      ZeroMemory(@arrSN2[0], Length(arrSN2));
      CopyMemory(@arrSN2[0], pSN, Length(arrSN2));
    finally
      if Assigned(pSN) then
        FreeMem(pSN);
    end;

    strS4SNDC := '';
    for I := Low(arrSN2) to High(arrSN2) do
      strS4SNDC := strS4SNDC + IntToHex(arrSN2[I], 1);

    // 读出序列号
    DogBytes := Length(arrSN);
    DogAddr := $00;
    DogData := @arrSN[0];
    ZeroMemory(@arrSN[0], Length(arrSN));
    if ReadDog = 0 then
    begin
      strS4SN := '';
      for I := Low(arrSN) to High(arrSN) do
        strS4SN := strS4SN + IntToHex(arrSN[I], 1);
    end
    else
      Exit;

    // 如果验证序列号相同，设置允许时间和允许次数
    if SameText(strS4SN, strS4SNDC) then
    begin
      DogBytes := Length(aData2003);
      DogAddr := $08;
      DogData := @aData2003[0];
      ZeroMemory(@aData2003[0], Length(aData2003));
      if ReadDog = 0 then
      begin
        {do nothing}
      end
      else
        Exit;
      // 允许时间
      aData2003[0] := pData^.LimitSeconds shr 24;
      aData2003[1] := (pData^.LimitSeconds shr 16) and $00FF;
      aData2003[2] := (pData^.LimitSeconds and $0000FFFF) shr 8;
      aData2003[3] := pData^.LimitSeconds and $000000FF;
      // 允许次数
      aData2003[8] := pData^.LimitTimes shr 8;
      aData2003[9] := pData^.LimitTimes and $00FF;

      DogBytes := Length(aData2003);
      DogAddr := $08;
      DogData := @aData2003[0];
      if WriteDog = 0 then
      begin

      end
      else
        Exit;

      // 版本
      DogBytes := Length(aData2002);
      DogAddr := $06;
      DogData := @aData2002[0];
      aData2002[0] := pData^.ProductID;
      aData2002[1] := pData^.Editon;
      if WriteDog = 0 then
      begin

      end
      else
        Exit;

      // 限制时间
      aDataLimitDate[$0] := pData^.LimitDate shr 24;
      aDataLimitDate[$1] := (pData^.LimitDate shr 16) and $00FF;
      aDataLimitDate[$2] := (pData^.LimitDate and $0000FFFF) shr 8;
      aDataLimitDate[$3] := pData^.LimitDate and $000000FF;
      DogBytes := Length(aDataLimitDate);
      DogAddr := $24;
      DogData := @aDataLimitDate[0];
      if WriteDog = 0 then
      begin

      end
      else
        Exit;


    end
    else
      Exit;

    bAuthorized := True;
    Result := True;
  finally
    Dispose(pData);
    if Assigned(pKey) then
      FreeMem(pKey);
    if Assigned(pEncryptKey) then
      FreeMem(pEncryptKey);
  end;
end;

function SNSUserAuthorize(AAuthorize: array of Byte): Boolean;
var
  pHead: PAuthFileHead20;
  Key: array [0..255] of Byte;
  iPos: Integer;
begin
  iPos := SizeOf(TAuthFileHead20);
  New(pHead);
  try
    CopyMemory(pHead, @AAuthorize[0], iPos);
    if SameText(pHead^.FileInfo, SAuthFileInfo) and
      (pHead^.Version = SAuthFileVer20) then
    begin
      CopyMemory(@Key[0], @AAuthorize[iPos], 255 - iPos);
      _SNSUserAuthorize20(Key);
    end
    else
      _SNSUserAuthorize10(AAuthorize);
  finally
    Dispose(pHead);
  end;
end;

const
  iDataSize: Integer = 16;
  iSNSize: Integer = 6;

function SNSUserUpdateLock(AUpdateData: array of Byte): Boolean;
var
  iOutputLength: Integer;
  arrSN: array [0..5] of Byte;
  arrSN2: array [0..5] of Byte;
  pEncryptKey: Pointer;
  pKey: Pointer;
  strS4SNDC, strS4SN: string[6];
  iFileSize: Integer;
  aData: array [0..21] of Byte;
  aUpdate: array [0..15] of Byte;
  I: Integer;
begin
  if IsNet then
  begin
    Result := True;
    Exit;
  end;

  Result := False;

  iFileSize := iDataSize + 6;
  if iFileSize mod 8 <> 0 then
    iFileSize :=  8 * (iFileSize div 8 + 1);

  iFileSize := iFileSize + 4;

  pEncryptKey := AllocMem(iFileSize);
  pKey := nil;
  try
    ZeroMemory(@aData[0], Length(aData));
    ZeroMemory(@aUpdate[0], Length(aUpdate));

    CopyMemory(pEncryptKey, @AUpdateData[0], iFileSize);
    Decrypt_BlowFish(AuthorizeKey, pEncryptKey, iFileSize, pKey, iFileSize);

    CopyMemory(@aData[0], pKey, Length(aData));

    CopyMemory(@arrSN2[0], @aData[0], iSNSize);

    CopyMemory(@aUpdate[0], @aData[iSNSize], Length(aUpdate));

    strS4SNDC := '';
    for I := Low(arrSN2) to High(arrSN2) do
      strS4SNDC := strS4SNDC + IntToHex(arrSN2[I], 1);

    // 读出序列号
    DogBytes := Length(arrSN);
    DogAddr := $00;
    DogData := @arrSN[0];
    ZeroMemory(@arrSN[0], Length(arrSN));
    if ReadDog = 0 then
    begin
      strS4SN := '';
      for I := Low(arrSN) to High(arrSN) do
        strS4SN := strS4SN + IntToHex(arrSN[I], 1);
    end
    else
      Exit;

    // 如果验证序列号相同，设置允许升级
    if SameText(strS4SN, strS4SNDC) then
    begin
      // 版本
      DogBytes := Length(aUpdate);
      DogAddr := $4E;
      DogData := @aUpdate[0];
      if WriteDog = 0 then
      begin

      end
      else
        Exit;
    end
    else
      Exit;

    Result := True;
  finally
    if Assigned(pKey) then
      FreeMem(pKey);
    if Assigned(pEncryptKey) then
      FreeMem(pEncryptKey);
  end;
end;

initialization

  {$IFDEF _ScNet}
    IsNet := True;
    {$IFDEF _ScBills}
       Open(0);
    {$ELSE}
      {$IFDEF _ScBudget}
         open(1);
      {$ELSE}
        {$IFDEF _ScEstimate}
           open(2);
        {$ENDIF}
      {$ENDIF}

    {$ENDIF}
  {$ENDIF}

finalization

  {$IFDEF _ScNet}
    if IsNet then
      CloseConnection;
  {$ENDIF}

end.
