unit mR1Encrypt; interface uses Windows, SysUtils, Forms, Classes; type ER1Error = class(Exception); function SimpleR1Check: Integer; function CheckR1Times(AIsOnOpen: Boolean = False): Integer; function CheckR1Hours: Integer; function CheckR1AdditionEdition: Integer; function CheckR1Edition(AOpening: Boolean = False): Integer; function CheckR1Data: Integer; function CheckR1LimitDate: Integer; function GetR1ReportOprNum(AOpr: string): Integer; function GetR1ReportFuncNum(AOpr: string): Integer; function OpenR1Dog: Integer; procedure SaveR1Dog; function R1UserAuthorize(AAuthorize: array of Byte): Boolean; function R1UserUpdateLock(AUpdateData: array of Byte): Boolean; implementation uses Math, CommonMessages, ScUtils, mEncryptPWD, CryptUtils, ScConfig, mEncryptUnit, mEncryptTypes, mEncryptEditions, Rockey1, PHPWebDm; const _R1_Key: array [0..16] of Byte = ($00, $00, $00, $0D, $CE, $CE, $CD, $CF, $8C, $8B, $BC, $90, $8D, $8B, $92, $9E, $AC); _R1_PID: array [0..11] of Byte = ($00, $00, $00, $08, $06, $71, $23, $3D, $53, $05, $0A, $78); _R1_UserPin: array [0..19] of Byte = ($00, $00, $00, $10, $39, $EF, $50, $6B, $41, $0D, $CC, $52, $39, $EF, $50, $6B, $41, $0D, $CC, $52); var _R1DogHandle: THandle = 0; _R1DogOpened: Boolean = False; _R1_HID: array [0..15] of Byte; function DecryptKey: string; var arrResult: array of Byte; iOutputLength: Integer; begin iOutputLength := GetOutputLength(_R1_Key); SetLength(arrResult, iOutputLength); Decrypt_Simple(_R1_Key, Length(_R1_Key), arrResult, iOutputLength); SetString(Result, PChar(@arrResult[0]), iOutputLength); end; function DecryptValues(AInput: array of Byte; ALength: Integer; var AOutput: array of Byte): Integer; var pKey: Pointer; begin pKey := nil; Decrypt_BlowFish(DecryptKey, @AInput[0], ALength, pKey, Result); CopyMemory(@AOutput[0], pKey, Result); end; function DecryptPID(var AOutput: array of Byte): Integer; begin Result := DecryptValues(_R1_PID, Length(_R1_PID), AOutput); end; function DecryptUserPin(var AOutput: array of Byte): Integer; begin Result := DecryptValues(_R1_UserPin, Length(_R1_UserPin), AOutput); end; procedure InnerCloseR1Dog; begin if _R1DogOpened then begin R1_Close(_R1DogHandle); end; end; procedure InnerOpenR1Dog; var I: Integer; iResult: Cardinal; iCount: DWORD; aPID: array [0..7] of Byte; aUserPin: array [0..16] of Byte; iTryCount: Byte; begin if _R1DogOpened then Exit; // 如果是插的彩虹锁,飞天锁驱动函数R1_Find没对iCount初始化,搞得循环2亿多次。现在先初始化iCount就可以了。 iCount := 0; // 查找狗 iResult := R1_Find(nil, @iCount); if iResult <> 0 then Exit; if iCount = 0 then Exit; // 解出PID if DecryptPID(aPID) = 0 then Exit; // 解出用户密码 if DecryptUserPin(aUserPin) = 0 then Exit; // 不知为什么在win7 32位下,必须加一个0字符才能正确执行。可能跟C要求字符串以0字符结尾有关 aUserPin[16] := 0; for I := 0 to iCount - 1 do begin // 获取句柄 iResult := R1_Open(@_R1DogHandle, @aPID[0], I); if iResult <> 0 then Continue; // 验证 iResult := R1_VerifyUserPin(_R1DogHandle, @aUserPin[0], @iTryCount); if iResult <> 0 then Continue; // 判断一下版本才决定是否正确的锁 if CheckR1Edition(True) = CS_Success then begin _R1DogOpened := True; Break; end else InnerCloseR1Dog; end; end; const R1EncryptVer = 1; function SimpleR1Check: Integer; var iResult: Cardinal; aData: array [0..15] of Byte; iLength: WORD; begin Result := -1; InnerOpenR1Dog; if not _R1DogOpened then Exit; iResult := R1_Read(_R1DogHandle, 0, 3, @aData[0], @iLength, MEM_PRI); if (iResult = 0) and (aData[2] = R1EncryptVer) then Result := DT_FT_R1; end; function CheckR1Times(AIsOnOpen: Boolean): Integer; var iResult: Cardinal; aData: array [0..11] of Byte; iTimes, iRunTimes, iLength: Word; begin Result := CS_Error; if SimpleR1Check < 0 then Exit; // 允许次数 iTimes := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$07-$08,为迷惑,取$03-$0E iResult := R1_Read(_R1DogHandle, $03, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 0 then iTimes := aData[4] shl 8 + aData[5]; if iTimes = 0 then Exit; if iTimes = $FFFF then begin Result := CS_Success; Exit; end; bAuthorized := False; // 实际次数 iRunTimes := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$04-$05,为迷惑,取$02-$0D iResult := R1_Read(_R1DogHandle, $02, Length(aData), @aData[0], @iLength, MEM_PUB); if iResult = 0 then iRunTimes := aData[2] shl 8 + aData[3]; 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 CheckR1Hours: Integer; var iResult: Cardinal; aData: array [0..11] of Byte; iSeconds, iRunSeconds: Cardinal; iLength: Word; begin Result := CS_Error; if SimpleR1Check < 0 then Exit; // 允许时间 iSeconds := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$03-$06,为迷惑,取$02-$0D iResult := R1_Read(_R1DogHandle, $02, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 0 then 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]; if iSeconds = 0 then Exit; if iSeconds = $FFFFFFFF then begin Result := CS_Success; Exit; end; bAuthorized := False; // 实际运行时间 iRunSeconds := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$00-$03,为迷惑,取$00-$0C iResult := R1_Read(_R1DogHandle, $00, Length(aData), @aData[0], @iLength, MEM_PUB); if iResult = 0 then iRunSeconds := ((aData[0] shl 8 + aData[1]) shl 8 + aData[2]) shl 8 + aData[3]; LastTime := iRunSeconds; if iRunSeconds > iSeconds then Result := CS_NeedAuthorize else Result := CS_WantAuthorize; end; function CheckR1LimitDate: Integer; var iResult: Cardinal; aData: array [0..11] of Byte; iType: Byte; iUserDate, iLimitDate: Cardinal; fDate, fCompileDate: TDateTime; iLength: Word; begin Result := CS_Error; if SimpleR1Check < 0 then Exit; // 加密类型是否时间限制狗 ZeroMemory(@aData[0], Length(aData)); // 实际是$63,为迷惑,取$5B-$66 iResult := R1_Read(_R1DogHandle, $5B, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult <> 0 then Exit; if aData[8] <> Ord(etDate) then begin Result := CS_Ignore; Exit; end; bAuthorized := False; // 允许日期 iLimitDate := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$09-$0C,为迷惑,取$05-$10 iResult := R1_Read(_R1DogHandle, $05, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 0 then iLimitDate := ((aData[4] shl 8 + aData[5]) shl 8 + aData[6]) shl 8 + aData[7]; // 运行日期 iUserDate := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$06-$09,为迷惑,取$05-$10 iResult := R1_Read(_R1DogHandle, $05, Length(aData), @aData[0], @iLength, MEM_PUB); if iResult = 0 then iUserDate := ((aData[1] shl 8 + aData[2]) shl 8 + aData[3]) shl 8 + aData[4]; 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 CheckR1AdditionEdition: Integer; var iResult: Cardinal; aData: array [0..15] of Byte; iLength: Word; begin Result := CS_NoDog; if SimpleR1Check < 0 then Exit; // 附加版本限制 ZeroMemory(@aData[0], Length(aData)); // 实际是$70-$72,为迷惑,取$70-$7F iResult := R1_Read(_R1DogHandle, $70, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 0 then begin if aData[1] = $16 then Result := CS_Success else Result := CS_NeedUpdate; end; end; function CheckR1Edition(AOpening: Boolean): Integer; var iResult: Cardinal; aData: array [0..255] of Byte; iEdition: Byte; iLength: Word; I: Integer; begin Result := CS_NoDog; if (not AOpening) and (SimpleR1Check < 0) then Exit; // 附加版本限制 iEdition := 0; ZeroMemory(@aData[0], Length(aData)); // 实际是$01,为迷惑,取$00-$FE iResult := R1_Read(_R1DogHandle, $00, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 0 then iEdition := aData[1] else Exit; if iEdition = 0 then Exit; DogEdition := iEdition; if CheckEncryptEdition(iEdition) then Result := CS_Success else Result := CS_DogTypeError; if Result = CS_Success then begin _DogEdition := iEdition; // 如果是固话清单限制版,则不退出,继续后面的检查 {$IFNDEF _mEncrypt} if not iEdition in [eidLimitedFixBills] then Exit; {$ENDIF} end; // 读取附加版本ID ZeroMemory(@aData[0], Length(aData)); // 实际是$80-$92,为迷惑,取$77-$175 iResult := R1_Read(_R1DogHandle, $77, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult <> 0 then Exit; for I := Low(aData) + 9 to High(aData) do begin iEdition := aData[I]; if iEdition = 0 then Break; if CheckEncryptEdition(iEdition) then begin Result := CS_Success; _DogEdition := iEdition; // 如果附加版本是固化清单限制版,则不跳出循环,以便检查是否还有固化清单完整版 if iEdition = eidLimitedFixBills then Continue; // 如果是计量支付需要检测所有的功能模块,则在检测到所有功能模块可用前,不可跳出循环 {$IFDEF _mEncrypt} if not (_bHasCompileEdition and _bHasMeasureEdition and _bHasPlanEdition) then Continue; {$ENDIF} Break; end; end; end; function CheckR1Data: Integer; var iResult: Cardinal; iCheckData, iOutputLength: Integer; pKey: Pointer; arrKey: array [0..15] of Byte; arrData: array [0..19] of Byte; I: Integer; bIsZero: Boolean; iLength: Word; begin Result := CS_NoDog; if SimpleR1Check < 0 then Exit; // HID ZeroMemory(@_R1_HID[0], Length(_R1_HID)); iResult := R1_GetHID(_R1DogHandle, @_R1_HID[0]); if iResult <> 0 then Exit; strHaspID := ''; // 注意此处与其他狗不同 for I := 0 to Length(_R1_HID) - 1 do strHaspID := strHaspID + Char(_R1_HID[I]); Randomize; iCheckData := RandomRange(11000, 11050); case iCheckData of 11011..11020: begin Result := CS_Ignore; Exit; end; end; // 校验码 ZeroMemory(@arrKey[0], Length(arrKey)); ZeroMemory(@arrData[0], Length(arrData)); // $10-$23 iResult := R1_Read(_R1DogHandle, $10, Length(arrData), @arrData[0], @iLength, MEM_PRI); if iResult = 0 then begin pKey := nil; try Decrypt_BlowFish(EncryptKey, @arrData[0], 20, pKey, iOutputLength); CopyMemory(@arrKey[0], pKey, iOutputLength); finally if Assigned(pKey) then FreeMem(pKey); end; end; for I := 0 to Length(_R1_HID) - 1 do begin if _R1_HID[I] <> arrKey[I] then begin Result := CS_VerifyError; Exit; Break; end; end; Result := CS_Success; end; function GetR1ReportOprNum(AOpr: string): Integer; const OprStr = '[,-,*,^,:=,/,p,<,<=,>=,>,+,<>,=,or,!=,and,f'; var iResult: Cardinal; OprStrs: TStringList; StrIndex: Integer; OprNum: Byte; aData: array [0..19] of Byte; iLength: Word; 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; iResult := R1_Read(_R1DogHandle, $30, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 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 GetR1ReportFuncNum(AOpr: string): Integer; const FuncStr = 'sql,treechapterinsert,getindex,addnull,shrink,copy,'+ 'sorttreechapter,joindata,chapterinsert,'+ 'refcopy,count,refcopyex1'; var iResult: Cardinal; FuncStrs: TStringList; StrIndex: Integer; OprNum: Byte; aData: array [0..19] of Byte; iLength: Word; 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; iResult := R1_Read(_R1DogHandle, $50, Length(aData), @aData[0], @iLength, MEM_PRI); if iResult = 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 OpenR1Dog: Integer; var iResult: Cardinal; aData: array [0..11] of Byte; iTimes, iLength: Word; begin Result := CS_Error; // 打开狗则运行次数立刻+1 // 实际是$04-$05为迷惑,取$02-$0D iResult := R1_Read(_R1DogHandle, $02, Length(aData), @aData[0], @iLength, MEM_PUB); if iResult = 0 then begin iTimes := aData[2] shl 8 + aData[3]; end else Exit; iTimes := iTimes + 1; ZeroMemory(@aData[0], Length(aData)); aData[0] := iTimes shr 8; aData[1] := iTimes and $00FF; iResult := R1_Write(_R1DogHandle, $04, 2, @aData[0], @iLength, MEM_PUB); if iResult <> 0 then Exit; Result := CS_Success; end; procedure SaveR1Dog; var iResult: Cardinal; aData: array [0..11] of Byte; aSecData: array [0..3] of Byte; iLastTime, iRunSeconds: LongWord; iBytesReturned: Cardinal; iLength: Word; begin RunTime := GetTickCount div 1000; if RunTime < StartTime then begin iLastTime := High(LongWord) div 1000 + RunTime - StartTime; end else iLastTime := RunTime - StartTime; // 实际是$00-$03,为迷惑,取$00-$0B iResult := R1_Read(_R1DogHandle, $00, Length(aData), @aData[0], @iLength, MEM_PUB); if iResult = 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; iResult := R1_Write(_R1DogHandle, $00, 4, @aSecData[0], @iLength, MEM_PUB); end; end; function _R1UserAuthorize30(AAuthorize: array of Byte; ALength: Word): Boolean; var iResult: DWORD; arrUpdateFile: array [0..9999] of Byte; begin Result := False; if _R1DogOpened then begin CopyMemory(@arrUpdateFile[0], @AAuthorize[0], ALength); iResult := R1_Update(_R1DogHandle, @arrUpdateFile[0], ALength); if iResult <> 0 then raise Exception.Create(Format('Can not update, error = %d', [iResult])); Result := True; bAuthorized := True; end; end; function R1UserAuthorize(AAuthorize: array of Byte): Boolean; var pHead: PAuthFileHead; Key: array [0..9999] of Byte; iPos: Integer; begin Result := False; iPos := SizeOf(TAuthFileHead); New(pHead); try CopyMemory(pHead, @AAuthorize[0], iPos); if SameText(pHead^.FileInfo, SAuthFileInfo) and (pHead^.Version = SAuthFileVer) then begin CopyMemory(@Key[0], @AAuthorize[iPos], pHead^.Length); Result := _R1UserAuthorize30(Key, pHead^.Length); end; finally Dispose(pHead); end; end; function R1UserUpdateLock(AUpdateData: array of Byte): Boolean; var pHead: PAuthFileHead; Key: array [0..9999] of Byte; iPos: Integer; begin Result := False; iPos := SizeOf(TAuthFileHead); New(pHead); try CopyMemory(pHead, @AUpdateData[0], iPos); if SameText(pHead^.FileInfo, SUpdateFileInfo) and (pHead^.Version = SUpdateFileVer) then begin CopyMemory(@Key[0], @AUpdateData[iPos], pHead^.Length); Result := _R1UserAuthorize30(Key, pHead^.Length); end; finally Dispose(pHead); end; end; initialization finalization InnerCloseR1Dog; end.