Recent

Author Topic: OnGuard troubles with TOgDateCode and Machine Modifier  (Read 672 times)

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
OnGuard troubles with TOgDateCode and Machine Modifier
« on: February 16, 2025, 02:09:45 pm »
Hello. I am using OnGUard CodeGen demo (modified with other secret product key) to generate license codes of various code types (Date, Day,  Reg, S/N, Usage, Special).
Without using machine modifier, it works for: Day, Reg, S/N, Usage and Special, while it does not work with Date.
With using machine modifier it fails with all code types.

My code:
Code: Pascal  [Select][+][-]
  1. unit ULicenseManager;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Classes, IniFiles,
  9.   OnGuard, OGUtil;
  10.  
  11. type
  12.   TLicenseActivationMethod = (
  13.     lamUnknown,
  14.     lamDate,
  15.     lamDays,
  16.     lamRegistration,
  17.     lamSerialNumber,
  18.     lamUsage,
  19.     // lamNetwork,  // Reserved for future use
  20.     lamSpecial
  21.   );
  22.  
  23.   TMyKeyProvider = class(TObject)
  24.   private
  25.     FPreparedKey: TKey;
  26.     FLicenseCode: string;
  27.   public
  28.     constructor Create(APreparedKey: TKey; const ALicenseCode: string);
  29.     procedure DoGetKey(Sender: TObject; var Key: TKey);
  30.     procedure DoGetCode(Sender: TObject; var Code: TCode);
  31.     property PreparedKey: TKey read FPreparedKey write FPreparedKey;
  32.     property LicenseCode: string read FLicenseCode write FLicenseCode;
  33.   end;
  34.  
  35. const
  36.   ProductSecretKey: TKey = (
  37.     $C0, $D7, $FE, $88, $05, $23, $20, $F2,
  38.     $80, $E3, $84, $3F, $0F, $53, $E6, $CA
  39.   );
  40.  
  41.   ShortDateFormat = 'yyyy-mm-dd';  //Required for TOgDateCode compatibility!
  42.  
  43. { License Management }
  44. function ReadLicenseCode: string;
  45. procedure WriteLicenseCode(const ACode: string);
  46. procedure DebugLog(const S: string);
  47. function GetMachineModifierString: string;
  48. function ActivateLicense(const LicenseCode, MachineCode: string): Boolean;
  49. function GetLicenseActivationMethod(const LicenseCode, MachineCode: string): TLicenseActivationMethod;
  50. function GetLicenseDetails(const LicenseCode: string): string;
  51. procedure LoadLicenseFromIni(const IniFileName: string);
  52. procedure SaveLicenseToIni(const IniFileName: string);
  53.  
  54. implementation
  55.  
  56. var
  57.   gLicenseCode: string;
  58.  
  59. { TMyKeyProvider }
  60. constructor TMyKeyProvider.Create(APreparedKey: TKey; const ALicenseCode: string);
  61. begin
  62.   inherited Create;
  63.   FPreparedKey := APreparedKey;
  64.   FLicenseCode := ALicenseCode;
  65.   DebugLog('KeyProvider.Create: Key=' + BufferToHex(FPreparedKey, SizeOf(FPreparedKey))
  66.            + ' Code=' + FLicenseCode);
  67. end;
  68.  
  69. procedure TMyKeyProvider.DoGetKey(Sender: TObject; var Key: TKey);
  70. begin
  71.   Key := FPreparedKey;
  72.   DebugLog('KeyProvider.DoGetKey: ' + BufferToHex(Key, SizeOf(Key)));
  73. end;
  74.  
  75. procedure TMyKeyProvider.DoGetCode(Sender: TObject; var Code: TCode);
  76. begin
  77.   DebugLog('KeyProvider.DoGetCode: Converting ' + FLicenseCode);
  78.   if not HexToBuffer(FLicenseCode, Code, SizeOf(Code)) then
  79.     raise Exception.Create('Invalid license code format: ' + FLicenseCode);
  80.   DebugLog('Converted Code: ' + BufferToHex(Code, SizeOf(Code))
  81.            + ' CheckValue=' + IntToHex(Code.CheckValue, 4));
  82. end;
  83.  
  84. { Core Functions }
  85. function ActivateLicense(const LicenseCode, MachineCode: string): Boolean;
  86. var
  87.   DecryptionKey: TKey;
  88.   ModifierValue: LongInt;
  89.   mCode: string;
  90.   KeyProvider: TMyKeyProvider;
  91.   LicenseComp: TOgCodeBase;
  92.   CodeBuffer: TCode;
  93.   CodeType: TCodeType;
  94. begin
  95.   DebugLog('==== ActivateLicense START ====');
  96.   DebugLog('LicenseCode: ' + LicenseCode);
  97.   DebugLog('MachineCode: ' + MachineCode);
  98.  
  99.   { 1. Prepare decryption key }
  100.   if Trim(MachineCode) = '' then
  101.   begin
  102.     DebugLog('Using base product key');
  103.     DecryptionKey := ProductSecretKey;
  104.   end
  105.   else
  106.   begin
  107.     mCode := GetMachineModifierString;
  108.     DebugLog('Expected machine modifier: ' + mCode);
  109.  
  110.     if UpperCase(Trim(MachineCode)) <> mCode then
  111.     begin
  112.       DebugLog('ERROR: Machine code mismatch');
  113.       Exit(False);
  114.     end;
  115.  
  116.     try
  117.       ModifierValue := StrToInt('$' + Copy(mCode, 2, Length(mCode)-1));
  118.       DebugLog('ModifierValue: ' + IntToStr(ModifierValue));
  119.  
  120.       DecryptionKey := ProductSecretKey;
  121.       ApplyModifierToKeyPrim(ModifierValue, DecryptionKey, SizeOf(DecryptionKey));
  122.       DebugLog('Modified key: ' + BufferToHex(DecryptionKey, SizeOf(DecryptionKey)));
  123.     except
  124.       on E: Exception do
  125.       begin
  126.         DebugLog('Modifier Error: ' + E.Message);
  127.         Exit(False);
  128.       end;
  129.     end;
  130.   end;
  131.  
  132.   { 2. Validate license code format }
  133.   if not HexToBuffer(LicenseCode, CodeBuffer, SizeOf(CodeBuffer)) then
  134.   begin
  135.     DebugLog('ERROR: Invalid hex format');
  136.     Exit(False);
  137.   end;
  138.  
  139.   { 3. Detect code type }
  140.   CodeType := GetCodeType(DecryptionKey, CodeBuffer);
  141.   DebugLog('Detected CodeType: ' + IntToStr(Ord(CodeType)));
  142.  
  143.   { 4. Create appropriate validator component }
  144.   case CodeType of
  145.     ctDate:         LicenseComp := TOgDateCode.Create(nil);
  146.     ctDays:         LicenseComp := TOgDaysCode.Create(nil);
  147.     ctRegistration: LicenseComp := TOgRegistrationCode.Create(nil);
  148.     ctSerialNumber: LicenseComp := TOgSerialNumberCode.Create(nil);
  149.     ctUsage:        LicenseComp := TOgUsageCode.Create(nil);
  150.     // ctNetwork:      LicenseComp := TOgNetworkCode.Create(nil);  // Reserved
  151.     ctSpecial:      LicenseComp := TOgSpecialCode.Create(nil);
  152.   else
  153.     begin
  154.       DebugLog('ERROR: Unsupported CodeType: ' + IntToStr(Ord(CodeType)));
  155.       Exit(False);
  156.     end;
  157.   end;
  158.  
  159.   { 5. Perform validation }
  160.   KeyProvider := TMyKeyProvider.Create(DecryptionKey, LicenseCode);
  161.   try
  162.     LicenseComp.OnGetKey := @KeyProvider.DoGetKey;
  163.     LicenseComp.OnGetCode := @KeyProvider.DoGetCode;
  164.  
  165.     DebugLog('Validating ' + LicenseComp.ClassName);
  166.     if LicenseComp.CheckCode(False) = ogValidCode then
  167.     begin
  168.       { Additional type-specific validation }
  169.       case CodeType of
  170.         ctDate:         Result := (TOgDateCode(LicenseComp).GetValue > Now);
  171.         ctDays:         Result := (TOgDaysCode(LicenseComp).GetValue > 0);
  172.         ctRegistration: Result := True;
  173.         ctSerialNumber: Result := True;
  174.         ctUsage:        Result := (TOgUsageCode(LicenseComp).GetValue > 0);
  175.         // ctNetwork:      Result := True;  // Reserved
  176.         ctSpecial:      Result := True;
  177.       else
  178.         Result := False;
  179.       end;
  180.     end
  181.     else
  182.     begin
  183.       DebugLog('CheckCode validation failed');
  184.       Result := False;
  185.     end;
  186.   finally
  187.     LicenseComp.Free;
  188.     KeyProvider.Free;
  189.   end;
  190.   DebugLog('==== ActivateLicense END ====');
  191. end;
  192.  
  193. { Supporting Functions }
  194. function ReadLicenseCode: string;
  195. var
  196.   Ini: TIniFile;
  197. begin
  198.   Ini := TIniFile.Create(GetAppConfigFile(False));
  199.   try
  200.     Result := Ini.ReadString('License', 'Key', '');
  201.     DebugLog('ReadLicenseCode: ' + Result);
  202.   finally
  203.     Ini.Free;
  204.   end;
  205. end;
  206.  
  207. procedure WriteLicenseCode(const ACode: string);
  208. var
  209.   Ini: TIniFile;
  210. begin
  211.   Ini := TIniFile.Create(GetAppConfigFile(False));
  212.   try
  213.     Ini.WriteString('License', 'Key', ACode);
  214.     Ini.UpdateFile;
  215.     DebugLog('WriteLicenseCode: ' + ACode);
  216.   finally
  217.     Ini.Free;
  218.   end;
  219. end;
  220.  
  221. function GetMachineModifierString: string;
  222. var
  223.   Modifier: LongInt;
  224. begin
  225.   Modifier := GenerateMachineModifierPrim;
  226.   Result := '$' + BufferToHex(Modifier, SizeOf(Modifier));
  227.   DebugLog('GetMachineModifierString: ' + Result);
  228. end;
  229.  
  230. function GetLicenseActivationMethod(const LicenseCode, MachineCode: string): TLicenseActivationMethod;
  231. var
  232.   TempResult: Boolean;
  233.   CodeBuffer: TCode;
  234.   CodeType: TCodeType;
  235.   DecryptionKey: TKey;
  236. begin
  237.   DebugLog('GetLicenseActivationMethod: Starting');
  238.   Result := lamUnknown;
  239.  
  240.   TempResult := ActivateLicense(LicenseCode, MachineCode);
  241.   if not TempResult then Exit;
  242.  
  243.   if HexToBuffer(LicenseCode, CodeBuffer, SizeOf(CodeBuffer)) then
  244.   begin
  245.     CodeType := GetCodeType(DecryptionKey, CodeBuffer);
  246.     case CodeType of
  247.       ctDate:         Result := lamDate;
  248.       ctDays:         Result := lamDays;
  249.       ctRegistration: Result := lamRegistration;
  250.       ctSerialNumber: Result := lamSerialNumber;
  251.       ctUsage:        Result := lamUsage;
  252.       // ctNetwork:      Result := lamNetwork;  // Reserved
  253.       ctSpecial:      Result := lamSpecial;
  254.     end;
  255.   end;
  256. end;
  257.  
  258. function GetLicenseDetails(const LicenseCode: string): string;
  259. var
  260.   KeyProvider: TMyKeyProvider;
  261.   LicenseComp: TOgCodeBase;
  262.   CodeBuffer: TCode;
  263.   CodeType: TCodeType;
  264.   DecryptionKey: TKey;
  265. begin
  266.   DebugLog('GetLicenseDetails: Starting');
  267.   Result := 'Unknown license type';
  268.  
  269.   if HexToBuffer(LicenseCode, CodeBuffer, SizeOf(CodeBuffer)) then
  270.   begin
  271.     CodeType := GetCodeType(DecryptionKey, CodeBuffer);
  272.     case CodeType of
  273.       ctDate:         Result := 'Date Code - Expires: ' + DateToStr(TOgDateCode.Create(nil).GetValue);
  274.       ctDays:         Result := 'Days Code - Remaining: ' + IntToStr(TOgDaysCode.Create(nil).GetValue);
  275.       ctRegistration: Result := 'Registration Code - Valid';
  276.       ctSerialNumber: Result := 'Serial Number Code - Valid';
  277.       ctUsage:        Result := 'Usage Code - Remaining: ' + IntToStr(TOgUsageCode.Create(nil).GetValue);
  278.       // ctNetwork:      Result := 'Network Code - Valid';  // Reserved
  279.       ctSpecial:      Result := 'Special Code - Valid';
  280.     end;
  281.   end;
  282. end;
  283.  
  284. procedure LoadLicenseFromIni(const IniFileName: string);
  285. var
  286.   Ini: TIniFile;
  287. begin
  288.   Ini := TIniFile.Create(IniFileName);
  289.   try
  290.     gLicenseCode := Ini.ReadString('License', 'Key', '');
  291.     DebugLog('LoadLicenseFromIni: ' + gLicenseCode);
  292.   finally
  293.     Ini.Free;
  294.   end;
  295. end;
  296.  
  297. procedure SaveLicenseToIni(const IniFileName: string);
  298. var
  299.   Ini: TIniFile;
  300. begin
  301.   Ini := TIniFile.Create(IniFileName);
  302.   try
  303.     Ini.WriteString('License', 'Key', gLicenseCode);
  304.     Ini.UpdateFile;
  305.     DebugLog('SaveLicenseToIni: ' + gLicenseCode);
  306.   finally
  307.     Ini.Free;
  308.   end;
  309. end;
  310.  
  311. procedure DebugLog(const S: string);
  312. var
  313.   F: TextFile;
  314. begin
  315.   try
  316.     AssignFile(F, 'debuglog.txt');
  317.     if FileExists('debuglog.txt') then
  318.       Append(F)
  319.     else
  320.       Rewrite(F);
  321.     WriteLn(F, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now) + ': ' + S);
  322.     CloseFile(F);
  323.   except
  324.     on E: Exception do
  325.       ; // Fail silently if logging fails
  326.   end;
  327. end;
  328.  
  329. initialization
  330.   DebugLog('==== License Manager Initialized ====');
  331.   DebugLog('Product Secret: ' + BufferToHex(ProductSecretKey, SizeOf(ProductSecretKey)));
  332.  
  333. end.
  334.  
  335.  

Log will be provided in the next message.

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #1 on: February 16, 2025, 02:10:18 pm »
My debugging log, providing more details and observations:
Code: Pascal  [Select][+][-]
  1. In this test I was using only license codes generated without machine modifier and also verification without machine modifier in the GUI.
  2.  
  3. The test showed that it is working OK for the "Days", "Reg", "S/N", "Usage" and "Special" (executedin that order):
  4. 2025-02-16 13:27:34: ==== ActivateLicense START ====
  5. 2025-02-16 13:27:34: LicenseCode: 607E561A4E5BF4848F29
  6. 2025-02-16 13:27:34: MachineCode:
  7. 2025-02-16 13:27:34: Using base product key
  8. 2025-02-16 13:27:34: Detected CodeType: 1
  9. 2025-02-16 13:27:34: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=607E561A4E5BF4848F29
  10. 2025-02-16 13:27:34: Validating TOgDaysCode
  11. 2025-02-16 13:27:34: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  12. 2025-02-16 13:27:34: KeyProvider.DoGetCode: Converting 607E561A4E5BF4848F29
  13. 2025-02-16 13:27:34: Converted Code: 607E561A4E5BF4848F29 CheckValue=7E60
  14. 2025-02-16 13:27:34: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  15. 2025-02-16 13:27:34: KeyProvider.DoGetCode: Converting 607E561A4E5BF4848F29
  16. 2025-02-16 13:27:34: Converted Code: 607E561A4E5BF4848F29 CheckValue=7E60
  17. 2025-02-16 13:27:34: ==== ActivateLicense END ====
  18. 2025-02-16 13:27:34: GetLicenseDetails: Starting
  19. 2025-02-16 13:27:34: WriteLicenseCode: 607E561A4E5BF4848F29
  20. 2025-02-16 13:27:49: ==== ActivateLicense START ====
  21. 2025-02-16 13:27:49: LicenseCode: FB7827892F227E630000
  22. 2025-02-16 13:27:49: MachineCode:
  23. 2025-02-16 13:27:49: Using base product key
  24. 2025-02-16 13:27:49: Detected CodeType: 2
  25. 2025-02-16 13:27:49: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=FB7827892F227E630000
  26. 2025-02-16 13:27:49: Validating TOgRegistrationCode
  27. 2025-02-16 13:27:49: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  28. 2025-02-16 13:27:49: KeyProvider.DoGetCode: Converting FB7827892F227E630000
  29. 2025-02-16 13:27:49: Converted Code: FB7827892F227E630000 CheckValue=78FB
  30. 2025-02-16 13:27:49: ==== ActivateLicense END ====
  31. 2025-02-16 13:27:49: GetLicenseDetails: Starting
  32. 2025-02-16 13:27:49: WriteLicenseCode: FB7827892F227E630000
  33. 2025-02-16 13:27:59: ==== ActivateLicense START ====
  34. 2025-02-16 13:27:59: LicenseCode: C2712C5A6A7D201A0000
  35. 2025-02-16 13:27:59: MachineCode:
  36. 2025-02-16 13:27:59: Using base product key
  37. 2025-02-16 13:27:59: Detected CodeType: 3
  38. 2025-02-16 13:27:59: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=C2712C5A6A7D201A0000
  39. 2025-02-16 13:27:59: Validating TOgSerialNumberCode
  40. 2025-02-16 13:27:59: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  41. 2025-02-16 13:27:59: KeyProvider.DoGetCode: Converting C2712C5A6A7D201A0000
  42. 2025-02-16 13:27:59: Converted Code: C2712C5A6A7D201A0000 CheckValue=71C2
  43. 2025-02-16 13:27:59: ==== ActivateLicense END ====
  44. 2025-02-16 13:27:59: GetLicenseDetails: Starting
  45. 2025-02-16 13:27:59: WriteLicenseCode: C2712C5A6A7D201A0000
  46. 2025-02-16 13:28:06: ==== ActivateLicense START ====
  47. 2025-02-16 13:28:06: LicenseCode: B03CF591672F6D158F29
  48. 2025-02-16 13:28:06: MachineCode:
  49. 2025-02-16 13:28:06: Using base product key
  50. 2025-02-16 13:28:06: Detected CodeType: 4
  51. 2025-02-16 13:28:06: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=B03CF591672F6D158F29
  52. 2025-02-16 13:28:06: Validating TOgUsageCode
  53. 2025-02-16 13:28:06: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  54. 2025-02-16 13:28:06: KeyProvider.DoGetCode: Converting B03CF591672F6D158F29
  55. 2025-02-16 13:28:06: Converted Code: B03CF591672F6D158F29 CheckValue=3CB0
  56. 2025-02-16 13:28:06: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  57. 2025-02-16 13:28:06: KeyProvider.DoGetCode: Converting B03CF591672F6D158F29
  58. 2025-02-16 13:28:06: Converted Code: B03CF591672F6D158F29 CheckValue=3CB0
  59. 2025-02-16 13:28:06: ==== ActivateLicense END ====
  60. 2025-02-16 13:28:06: GetLicenseDetails: Starting
  61. 2025-02-16 13:28:06: WriteLicenseCode: B03CF591672F6D158F29
  62. 2025-02-16 13:28:15: ==== ActivateLicense START ====
  63. 2025-02-16 13:28:15: LicenseCode: F116C4B2A6AA11B70000
  64. 2025-02-16 13:28:15: MachineCode:
  65. 2025-02-16 13:28:15: Using base product key
  66. 2025-02-16 13:28:15: Detected CodeType: 6
  67. 2025-02-16 13:28:15: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=F116C4B2A6AA11B70000
  68. 2025-02-16 13:28:15: Validating TOgSpecialCode
  69. 2025-02-16 13:28:15: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  70. 2025-02-16 13:28:15: KeyProvider.DoGetCode: Converting F116C4B2A6AA11B70000
  71. 2025-02-16 13:28:15: Converted Code: F116C4B2A6AA11B70000 CheckValue=16F1
  72. 2025-02-16 13:28:15: ==== ActivateLicense END ====
  73. 2025-02-16 13:28:15: GetLicenseDetails: Starting
  74. 2025-02-16 13:28:15: WriteLicenseCode: F116C4B2A6AA11B70000
  75.  
  76. However, it does not work for the first tab "Date". Initially I thought that it is due to wrong ShortDate format, that's why I added in const ShortDateFormat = 'yyyy-mm-dd';  //Required for TOgDateCode compatibility!
  77. However, it didn't help.
  78. What I am noticing is that the CheckValue is different for different entered Start Date, while it seems that changing End Date values does not have impact?
  79.  
  80. Start Date: "2025-02-14", End Date:"2025-02-20"
  81.  
  82. 2025-02-16 13:33:32: ==== ActivateLicense START ====
  83. 2025-02-16 13:33:32: LicenseCode: EC16E2C41AC800549329
  84. 2025-02-16 13:33:32: MachineCode:
  85. 2025-02-16 13:33:32: Using base product key
  86. 2025-02-16 13:33:32: Detected CodeType: 0
  87. 2025-02-16 13:33:32: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=EC16E2C41AC800549329
  88. 2025-02-16 13:33:32: Validating TOgDateCode
  89. 2025-02-16 13:33:32: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  90. 2025-02-16 13:33:32: KeyProvider.DoGetCode: Converting EC16E2C41AC800549329
  91. 2025-02-16 13:33:32: Converted Code: EC16E2C41AC800549329 CheckValue=16EC
  92. 2025-02-16 13:33:32: CheckCode validation failed
  93. 2025-02-16 13:33:32: ==== ActivateLicense END ====
  94.  
  95. Start Date: "2025-02-14", End Date:"2025-02-21"
  96.  
  97. 2025-02-16 13:34:38: ==== ActivateLicense START ====
  98. 2025-02-16 13:34:38: LicenseCode: EC16E2C41AC800549429
  99. 2025-02-16 13:34:38: MachineCode:
  100. 2025-02-16 13:34:38: Using base product key
  101. 2025-02-16 13:34:38: Detected CodeType: 0
  102. 2025-02-16 13:34:38: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=EC16E2C41AC800549429
  103. 2025-02-16 13:34:38: Validating TOgDateCode
  104. 2025-02-16 13:34:38: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  105. 2025-02-16 13:34:38: KeyProvider.DoGetCode: Converting EC16E2C41AC800549429
  106. 2025-02-16 13:34:38: Converted Code: EC16E2C41AC800549429 CheckValue=16EC
  107. 2025-02-16 13:34:38: CheckCode validation failed
  108. 2025-02-16 13:34:38: ==== ActivateLicense END ====
  109. 2025-02-16 13:34:38: ==== ActivateLicense START ====
  110. 2025-02-16 13:34:38: LicenseCode: EC16E2C41AC800549429
  111. 2025-02-16 13:34:38: MachineCode:
  112. 2025-02-16 13:34:38: Using base product key
  113. 2025-02-16 13:34:38: Detected CodeType: 0
  114. 2025-02-16 13:34:38: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=EC16E2C41AC800549429
  115. 2025-02-16 13:34:38: Validating TOgDateCode
  116. 2025-02-16 13:34:38: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  117. 2025-02-16 13:34:38: KeyProvider.DoGetCode: Converting EC16E2C41AC800549429
  118. 2025-02-16 13:34:38: Converted Code: EC16E2C41AC800549429 CheckValue=16EC
  119. 2025-02-16 13:34:38: CheckCode validation failed
  120. 2025-02-16 13:34:38: ==== ActivateLicense END ====
  121.  
  122. Start Date: "2025-02-13", End Date:"2025-02-20"
  123.  
  124. 2025-02-16 13:39:58: ==== ActivateLicense START ====
  125. 2025-02-16 13:39:58: LicenseCode: DFB15FCE62C5DDEF9329
  126. 2025-02-16 13:39:58: MachineCode:
  127. 2025-02-16 13:39:58: Using base product key
  128. 2025-02-16 13:39:58: Detected CodeType: 0
  129. 2025-02-16 13:39:58: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=DFB15FCE62C5DDEF9329
  130. 2025-02-16 13:39:58: Validating TOgDateCode
  131. 2025-02-16 13:39:58: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  132. 2025-02-16 13:39:58: KeyProvider.DoGetCode: Converting DFB15FCE62C5DDEF9329
  133. 2025-02-16 13:39:58: Converted Code: DFB15FCE62C5DDEF9329 CheckValue=B1DF
  134. 2025-02-16 13:39:58: CheckCode validation failed
  135. 2025-02-16 13:39:58: ==== ActivateLicense END ====
  136.  
  137. Start Date: "2025-02-13", End Date:"2025-02-21"
  138.  
  139. 2025-02-16 13:40:36: ==== ActivateLicense START ====
  140. 2025-02-16 13:40:36: LicenseCode: DFB15FCE62C5DDEF9429
  141. 2025-02-16 13:40:36: MachineCode:
  142. 2025-02-16 13:40:36: Using base product key
  143. 2025-02-16 13:40:36: Detected CodeType: 0
  144. 2025-02-16 13:40:36: KeyProvider.Create: Key=C0D7FE88052320F280E3843F0F53E6CA Code=DFB15FCE62C5DDEF9429
  145. 2025-02-16 13:40:36: Validating TOgDateCode
  146. 2025-02-16 13:40:36: KeyProvider.DoGetKey: C0D7FE88052320F280E3843F0F53E6CA
  147. 2025-02-16 13:40:36: KeyProvider.DoGetCode: Converting DFB15FCE62C5DDEF9429
  148. 2025-02-16 13:40:36: Converted Code: DFB15FCE62C5DDEF9429 CheckValue=B1DF
  149. 2025-02-16 13:40:36: CheckCode validation failed
  150. 2025-02-16 13:40:36: ==== ActivateLicense END ====
  151.  
  152.  
  153. ***********************
  154. In the second testing, I was creating license codes of each type, first without machine modifier, then with machine modifier. On my application side, in About form, there was machine modifier present in the GUI.
  155. The test showed that it is NOT WORKING for the "Days", "Reg", "S/N", "Usage" and "Special" (executedin that order):
  156.  
  157. 2025-02-16 13:57:03: ==== ActivateLicense START ====
  158. 2025-02-16 13:57:03: LicenseCode: 1E919350428D64B08F29
  159. 2025-02-16 13:57:03: MachineCode: $34862432
  160. 2025-02-16 13:57:03: GetMachineModifierString: $34862432
  161. 2025-02-16 13:57:03: Expected machine modifier: $34862432
  162. 2025-02-16 13:57:03: ModifierValue: 881206322
  163. 2025-02-16 13:57:03: Modified key: F2F378BC052320F280E3843F0F53E6CA
  164. 2025-02-16 13:57:03: Detected CodeType: 7
  165. 2025-02-16 13:57:03: ERROR: Unsupported CodeType: 7
  166. 2025-02-16 13:57:14: ==== ActivateLicense START ====
  167. 2025-02-16 13:57:14: LicenseCode: CB7347C2EC66E1270000
  168. 2025-02-16 13:57:14: MachineCode: $34862432
  169. 2025-02-16 13:57:14: GetMachineModifierString: $34862432
  170. 2025-02-16 13:57:14: Expected machine modifier: $34862432
  171. 2025-02-16 13:57:14: ModifierValue: 881206322
  172. 2025-02-16 13:57:14: Modified key: F2F378BC052320F280E3843F0F53E6CA
  173. 2025-02-16 13:57:14: Detected CodeType: 7
  174. 2025-02-16 13:57:14: ERROR: Unsupported CodeType: 7
  175. 2025-02-16 13:57:27: ==== ActivateLicense START ====
  176. 2025-02-16 13:57:27: LicenseCode: 91737DAA126FEBD40000
  177. 2025-02-16 13:57:27: MachineCode: $34862432
  178. 2025-02-16 13:57:27: GetMachineModifierString: $34862432
  179. 2025-02-16 13:57:27: Expected machine modifier: $34862432
  180. 2025-02-16 13:57:27: ModifierValue: 881206322
  181. 2025-02-16 13:57:27: Modified key: F2F378BC052320F280E3843F0F53E6CA
  182. 2025-02-16 13:57:27: Detected CodeType: 7
  183. 2025-02-16 13:57:27: ERROR: Unsupported CodeType: 7
  184. 2025-02-16 13:57:39: ==== ActivateLicense START ====
  185. 2025-02-16 13:57:39: LicenseCode: E6235A833D67A9808F29
  186. 2025-02-16 13:57:39: MachineCode: $34862432
  187. 2025-02-16 13:57:39: GetMachineModifierString: $34862432
  188. 2025-02-16 13:57:39: Expected machine modifier: $34862432
  189. 2025-02-16 13:57:39: ModifierValue: 881206322
  190. 2025-02-16 13:57:39: Modified key: F2F378BC052320F280E3843F0F53E6CA
  191. 2025-02-16 13:57:39: Detected CodeType: 7
  192. 2025-02-16 13:57:39: ERROR: Unsupported CodeType: 7
  193. 2025-02-16 13:57:55: ==== ActivateLicense START ====
  194. 2025-02-16 13:57:55: LicenseCode: ED48AE19603333DF0000
  195. 2025-02-16 13:57:55: MachineCode: $34862432
  196. 2025-02-16 13:57:55: GetMachineModifierString: $34862432
  197. 2025-02-16 13:57:55: Expected machine modifier: $34862432
  198. 2025-02-16 13:57:55: ModifierValue: 881206322
  199. 2025-02-16 13:57:55: Modified key: F2F378BC052320F280E3843F0F53E6CA
  200. 2025-02-16 13:57:55: Detected CodeType: 7
  201. 2025-02-16 13:57:55: ERROR: Unsupported CodeType: 7
  202. 2025-02-16 13:58:05: ==== ActivateLicense START ====
  203. 2025-02-16 13:58:05: LicenseCode: 6B438F0D92E1E4550000
  204. 2025-02-16 13:58:05: MachineCode: $34862432
  205. 2025-02-16 13:58:05: GetMachineModifierString: $34862432
  206. 2025-02-16 13:58:05: Expected machine modifier: $34862432
  207. 2025-02-16 13:58:05: ModifierValue: 881206322
  208. 2025-02-16 13:58:05: Modified key: F2F378BC052320F280E3843F0F53E6CA
  209. 2025-02-16 13:58:05: Detected CodeType: 7
  210. 2025-02-16 13:58:05: ERROR: Unsupported CodeType: 7
  211. 2025-02-16 13:58:05: ==== ActivateLicense START ====
  212. 2025-02-16 13:58:05: LicenseCode: 6B438F0D92E1E4550000
  213. 2025-02-16 13:58:05: MachineCode: $34862432
  214. 2025-02-16 13:58:05: GetMachineModifierString: $34862432
  215. 2025-02-16 13:58:05: Expected machine modifier: $34862432
  216. 2025-02-16 13:58:05: ModifierValue: 881206322
  217. 2025-02-16 13:58:05: Modified key: F2F378BC052320F280E3843F0F53E6CA
  218. 2025-02-16 13:58:05: Detected CodeType: 7
  219. 2025-02-16 13:58:05: ERROR: Unsupported CodeType: 7
  220.  
  221.  

Can you help me please, what am I doing wrong?

wp

  • Hero Member
  • *****
  • Posts: 12679
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #2 on: February 16, 2025, 05:07:48 pm »
OnGuard is an ancient TurboPower package. I think it has been maintained by Graeme Geldenhuys, but I have not seen him here for a long time. So, I am afraid that you are on your own. But if you find a solution tell me to update the OPM version.

rvk

  • Hero Member
  • *****
  • Posts: 6683
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #3 on: February 17, 2025, 11:51:14 am »
Hello. I am using OnGUard CodeGen demo (modified with other secret product key) to generate license codes of various code types (Date, Day,  Reg, S/N, Usage, Special).
I can't even get de CodeGen example to work in the latest Lazarus (trunk).
So you might want to provide your complete (reproducible) test example so we can test it ourselves.

(You can use Publish project under Project to supply all the relevant files (excluding .res file) in a zip)

Thaddy

  • Hero Member
  • *****
  • Posts: 16643
  • Kallstadt seems a good place to evict Trump to.
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #4 on: February 17, 2025, 03:56:46 pm »
(You can use Publish project under Project to supply all the relevant files (excluding .res file) in a zip)
OnGuard uses some "resources" on purpose as far as I can remember, so be careful giving that advice.
Then again, with test code we may generate our own.

Makes me think: maybe runtime patching is no longer allowed by the OS.
I don't use the obfuscation path for many years, because it is clueless and fruitless against real hackers.
I know for sure that versions of OnGuard and specific functionality of it stored executable code as RT_RCDATA.
« Last Edit: February 17, 2025, 04:03:21 pm by Thaddy »
But I am sure they don't want the Trumps back...

rvk

  • Hero Member
  • *****
  • Posts: 6683
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #5 on: February 17, 2025, 05:05:11 pm »
I think I found the problem.
You are getting the ctUnknown (7) in CodeType because you didn't initialize the code correctly during creation.

You want the CodeType to be ctSpecial (6). That corresponds to the magic value SpecialCheckCode to be used in creation of the code.
But the only place the SpecialCheckCode is used for creation is in InitSpecialCode().

That InitSpecialCode() (or any of the other InitXXX procedures) is needed to initialize the code corectly.
This is in onguard.pas:
Code: Pascal  [Select][+][-]
  1. procedure InitSpecialCode(const Key : TKey; Value : LongInt; Expires : TDateTime; var Code : TCode);
  2. begin
  3.   Code.CheckValue := SpecialCheckCode;
  4.   Code.Expiration := ShrinkDate(Expires);
  5.   Code.Value := Value;
  6.   MixBlock(T128bit(Key), Code, True);
  7. end;

So... where did you use InitSpecialCode (or other InitXXX) ?
After the ApplyModifierToKeyPrim you need to use InitSpecialCode (or InitXXX) to create a correct onGuard code.

It's also in the documentation:
Quote
InitSpecialCode

procedure InitSpecialCode (const Key : TKey; Value : LongInt; Expires : TDateTime; var Code : TCode);

InitSpecialCode creates and initializes a special code using Key, Value, and Expires.
Value is stored as part of the Code.
The resulting code is valid until the date stored in Expires is reached.
This routine is defined in the OnGuard unit. (as of 1.15 this routine has been moved to the OgUtil unit)

AND... if you don't want the Expire date... you need to use one of the other InitXXX procudures (like InitSerialNumberCode etc).

BTW. The Online Package Manager seems to have an older version of onGuard. The latest (on svn) is version 1.15 (rev.30).
OPM still has 1.13.
« Last Edit: February 17, 2025, 05:10:04 pm by rvk »

wp

  • Hero Member
  • *****
  • Posts: 12679
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #6 on: February 17, 2025, 06:46:18 pm »
BTW. The Online Package Manager seems to have an older version of onGuard. The latest (on svn) is version 1.15 (rev.30).
OPM still has 1.13.
Now I am confused with the version numbers:
- "OPM still has 1.13." - just installed from OPM, and it says v1.20.1
- "The latest (on svn) is version 1.15 (rev.30)" - installed also this version, and it says 1.0.1. I remember that I spent some time working on the sample project two years ago (https://forum.lazarus.freepascal.org/index.php/topic,62336.msg471392.html), and updated the CCR version. SVN history says that it was v1.0.0 before. Strange - where did the OPM version come from? Is it a CodeTyphon thing? Or did it come from Graeme's original site? Since the OPM version has many issue I am thinking about putting the CCR version on OPM. Which version number should it have?

rvk

  • Hero Member
  • *****
  • Posts: 6683
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #7 on: February 17, 2025, 06:53:10 pm »
BTW. The Online Package Manager seems to have an older version of onGuard. The latest (on svn) is version 1.15 (rev.30).
OPM still has 1.13.
Now I am confused with the version numbers:
- "OPM still has 1.13." - just installed from OPM, and it says v1.20.1
- "The latest (on svn) is version 1.15 (rev.30)" - installed also this version, and it says 1.0.1. I remember that I spent some time working on the sample project two years ago (https://forum.lazarus.freepascal.org/index.php/topic,62336.msg471392.html), and updated the CCR version. SVN history says that it was v1.0.0 before. Strange - where did the OPM version come from? Is it a CodeTyphon thing? Or did it come from Graeme's original site? Since the OPM version has many issue I am thinking about putting the CCR version on OPM. Which version number should it have?
Not sure where you get the 1.0.0 from.
I use this one
https://sourceforge.net/p/tponguard/code/HEAD/tree/
It's 1.15 revision 30
As far as I know that's the official latest one.

korba812

  • Sr. Member
  • ****
  • Posts: 460
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #8 on: February 17, 2025, 07:01:06 pm »
OnGuard package from CCR repository looks like version from Graemes repository. I advise against using this version as it is not very secure:
https://forum.lazarus.freepascal.org/index.php/topic,45410.msg321245.html#msg321245

rvk

  • Hero Member
  • *****
  • Posts: 6683
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #9 on: February 17, 2025, 07:03:54 pm »
Ah. I looked at the source. It said it was 1.13. But OPM says it's 1.20.1.0
But... it's based on the real onguard 1.13.
I don't know what is changed by Lazarus but... it still based on older code.

The real one should also work in Lazarus (I used that one in Delphi).
https://sourceforge.net/p/tponguard/code/HEAD/tree/

Regardless which version... the original problem was not using InitXXX procedures to initialize the code.

wp

  • Hero Member
  • *****
  • Posts: 12679
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #10 on: February 17, 2025, 07:24:20 pm »
I think the latest code is in the CCR svn repository. Quickly scanning through the original source that you linked, I found that there are still {$IFDEF Win32} directives, i.e. this code is not usable under 64-bit Windows. But I had fixed this in the session two years ago...

So, the task is to merge the official sources into the ccr fork, then send this update to the official site and hope that there is still somebody who can update it. And even if this is does not happen OPM should be updated to the then newest version.

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #11 on: February 17, 2025, 07:25:55 pm »
All right, I have some progress, by the virtue of using Perplexity AI! Sorry guys, but I am too bad programmer to do it without some help  O:-)

Anyway, here is the Perplexity AI explanation:
Below is a detailed explanation of the solution and its context for the Lazarus Codetyphon FreePascal community.

## Overview

The ULicenseManager unit is responsible for validating license codes using the OnGuard library. It supports multiple license types such as Date, Days, Usage, Registration, Serial Number, and Special codes. In our solution the unit:

- Reads a license string from an INI file.
- Applies a machine modifier (obtained from a hardware‐dependent function) to a secret key.
- Uses OnGuard components (like TOgDateCode, TOgDaysCode, etc.) to validate the license code.
- Provides detailed human–readable debug logging (with Unicode emojis) to show the entire validation flow.

## Machine Modifier and Key Generation

A key part of the validation process is the application of a machine modifier. The generator produces a modifier from system information and converts it into a hexadecimal string using the function:

```pascal
function GetMachineModifierString: string;
```

Since your generator expects the modifier in a specific byte order, we use a helper function, `SwapEndian`, to convert the machine code (for example, from "$34862432" to "$32248634"). This swapped value is then applied to the secret key with the OnGuard routine `ApplyModifierToKeyPrim`. This ensures that both license generation and validation produce the same modified key.

## Date Code Handling

For Date codes (ctDate), OnGuard’s `TOgDateCode.GetValue` returns a raw expiration date. In your case, your generator produces a raw expiration date of 1929‑02‑19, which is obviously not correct with respect to the intended period. The solution assumes that a 96‑year offset (plus an extra day) is necessary. In our DoChecked procedure, if the raw date is less than January 1, 2000, we add 96 years and 1 day (e.g. 1929‑02‑19 becomes 2025‑02‑20). This adjustment aligns with your license generation parameters (for example, a license with a start date of 2025‑02‑14 and an end date of 2025‑02‑20).

In addition, in the ActivateLicense routine we perform an override check for Date codes. After validating with the OnGuard component, we re-read the raw expiration date, apply our adjustment again, and if the adjusted expiration date is later than the current date, we override the status to valid.

## Debug Logging and Validation Details

The unit includes a robust DebugLog procedure that writes timestamped, human–readable logs to a file. Emojis (such as 🔑, 📜, and 📅) are used to indicate steps in the process. The DoChecked procedure builds a final validation details string that includes:

- The license type (e.g. “Type: Date Code”)
- The expiration date (adjusted if necessary)
- The current system date

For non-Date codes (Days, Usage, etc.), the details are built by casting the Sender to the correct class (e.g. TOgDaysCode, TOgUsageCode). This ensures that each license type shows appropriate information in the GUI.

## Is This a Bug in the OnGuard Package?

The behavior we encountered with Date codes—returning a raw expiration date far in the past that then requires a 96‑year offset—is not typical for many license systems. However, there are two possibilities:

1. **Design Decision:** 
   It is possible that OnGuard was designed to work with a particular date‐encoding scheme that requires an offset when used in conjunction with certain generators. In this case, the behavior is “by design” and our unit simply compensates for it.

2. **Potential Bug or Misalignment:** 
   If the documentation for OnGuard indicates that GetValue should return a proper expiration date (i.e., one that matches the generator’s output directly) and it does not, then this could be considered a bug or misalignment. In our case, our solution adds a manual offset (96 years + 1 day) to correct the output. We recommend checking with the OnGuard documentation and community to see if others have experienced a similar inconsistency.

In summary, while our workaround successfully aligns the Date code validation with your generated license parameters, it is not entirely clear whether this offset requirement is an intentional design decision of the OnGuard package or an unintended bug. If you believe the documentation contradicts this behavior, it might warrant reporting to the OnGuard maintainers.

## Conclusion

The updated unit code:

- Correctly applies the machine modifier using a byte-swapping technique to match the license generator.
- Adjusts Date codes by adding a defined offset (96 years and 1 day) if the raw expiration appears too low.
- Provides extensive debug logging to help diagnose issues.
- Supports all license code types.

While our solution works for your scenario, whether this constitutes a bug in OnGuard depends on its documented behavior. If the behavior is contrary to documentation, it might be worth addressing with the maintainers.

This explanation should serve as a thorough overview for the FreePascal and Lazarus community.

Citations:
[1] https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/12835651/06879245-eaa9-4a65-b696-75953502090b/paste.txt

---
Odgovor od Perplexity: pplx.ai/share

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #12 on: February 17, 2025, 07:26:49 pm »
And here is the code:
Code: Pascal  [Select][+][-]
  1. unit ULicenseManager;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Classes, IniFiles, TypInfo, Dialogs, StrUtils,
  9.   OnGuard, OGUtil;
  10.  
  11. type
  12.   TLicenseActivationMethod = (
  13.     lamUnknown,
  14.     lamDate,
  15.     lamDays,
  16.     lamRegistration,
  17.     lamSerialNumber,
  18.     lamUsage,
  19.     lamSpecial
  20.   );
  21.  
  22.   TMyKeyProvider = class(TObject)
  23.   private
  24.     FPreparedKey: TKey;
  25.     FLicenseCode: string;
  26.     FStatusCode: TCodeStatus;
  27.     FValidationDetails: string;
  28.     FCodeBuffer: TCode;
  29.   public
  30.     constructor Create(APreparedKey: TKey; const ALicenseCode: string);
  31.     procedure DoGetKey(Sender: TObject; var Key: TKey);
  32.     procedure DoGetCode(Sender: TObject; var Code: TCode);
  33.     procedure DoChecked(Sender: TObject; Status: TCodeStatus);
  34.     property PreparedKey: TKey read FPreparedKey write FPreparedKey;
  35.     property LicenseCode: string read FLicenseCode write FLicenseCode;
  36.     property StatusCode: TCodeStatus read FStatusCode;
  37.     property ValidationDetails: string read FValidationDetails;
  38.   end;
  39.  
  40. { License Management }
  41. function ReadLicenseCode: string;
  42. procedure WriteLicenseCode(const ACode: string);
  43. procedure DebugLog(const S: string);
  44. function GetMachineModifierString: string;
  45. function ActivateLicense(const LicenseCode, MachineCode: string; out ValidationDetails: string): Boolean;
  46. function GetLicenseActivationMethod(const LicenseCode, MachineCode: string): TLicenseActivationMethod;
  47. function GetLicenseDetails(const LicenseCode: string): string;
  48. procedure LoadLicenseFromIni(const IniFileName: string);
  49. procedure SaveLicenseToIni(const IniFileName: string);
  50.  
  51. const
  52.   ProductSecretKey: TKey = (
  53.     $C0, $D7, $FE, $88, $05, $23, $20, $F2,
  54.     $80, $E3, $84, $3F, $0F, $53, $E6, $CA
  55.   );
  56.   ShortDateFormat = 'yyyy-mm-dd';
  57.  
  58. implementation
  59.  
  60. uses
  61.   DateUtils;
  62.  
  63. var
  64.   gLicenseCode: string;
  65.  
  66. { Helper Function: SwapEndian }
  67. function SwapEndian(Value: LongInt): LongInt;
  68. begin
  69.   Result := (Value shr 24) or
  70.             ((Value shr 8) and $0000FF00) or
  71.             ((Value shl 8) and $00FF0000) or
  72.             (Value shl 24);
  73. end;
  74.  
  75. { TMyKeyProvider Implementation }
  76. constructor TMyKeyProvider.Create(APreparedKey: TKey; const ALicenseCode: string);
  77. begin
  78.   inherited Create;
  79.   FPreparedKey := APreparedKey;
  80.   FLicenseCode := ALicenseCode;
  81.   DebugLog('&#128273; KeyProvider.Create | Key=' + BufferToHex(FPreparedKey, SizeOf(FPreparedKey)) +
  82.     ' | LicenseCode=' + FLicenseCode);
  83. end;
  84.  
  85. procedure TMyKeyProvider.DoGetKey(Sender: TObject; var Key: TKey);
  86. begin
  87.   Key := FPreparedKey;
  88.   DebugLog('&#128273; KeyProvider.DoGetKey | Key=' + BufferToHex(Key, SizeOf(Key)));
  89. end;
  90.  
  91. procedure TMyKeyProvider.DoGetCode(Sender: TObject; var Code: TCode);
  92. begin
  93.   DebugLog('&#128220; KeyProvider.DoGetCode | Converting LicenseCode: ' + FLicenseCode);
  94.   if not HexToBuffer(FLicenseCode, Code, SizeOf(Code)) then
  95.     raise Exception.Create('❌ Invalid license code format: ' + FLicenseCode);
  96.   FCodeBuffer := Code;
  97.   DebugLog('&#128220; Converted Code=' + BufferToHex(Code, SizeOf(Code)) +
  98.     ' | CheckValue=' + IntToHex(Code.CheckValue, 4));
  99. end;
  100.  
  101. procedure TMyKeyProvider.DoChecked(Sender: TObject; Status: TCodeStatus);
  102. var
  103.   CodeType: TCodeType;
  104.   DetailsStr: string;
  105.   dt: TDateTime;
  106.   days, usages: Integer;
  107. begin
  108.   CodeType := GetCodeType(FPreparedKey, FCodeBuffer);
  109.   case CodeType of
  110.     ctDate:
  111.       begin
  112.         if Sender is TOgDateCode then
  113.         begin
  114.           dt := TOgDateCode(Sender).GetValue;
  115.           DebugLog('&#128197; Raw Expiration Date: ' + FormatDateTime(ShortDateFormat + ' hh:nn:ss', dt));
  116.           if dt < EncodeDate(2000, 1, 1) then
  117.           begin
  118.             DebugLog('⚠️ Date appears low; adding 96 years and 1 day.');
  119.             dt := IncYear(dt, 96) + 1;  // Adjust as needed!
  120.           end;
  121.           DetailsStr := Format('Type: Date Code' + sLineBreak +
  122.             'Expiration: %s' + sLineBreak +
  123.             'Current Date: %s',
  124.             [FormatDateTime(ShortDateFormat, dt),
  125.              FormatDateTime(ShortDateFormat, Now)]);
  126.         end
  127.         else
  128.           DetailsStr := 'Invalid Date Code';
  129.       end;
  130.     ctDays:
  131.       begin
  132.         if Sender is TOgDaysCode then
  133.         begin
  134.           days := TOgDaysCode(Sender).GetValue;
  135.           DetailsStr := Format('Type: Days Code' + sLineBreak +
  136.             'Days Remaining: %d', [days]);
  137.         end
  138.         else
  139.           DetailsStr := 'Invalid Days Code';
  140.       end;
  141.     ctUsage:
  142.       begin
  143.         if Sender is TOgUsageCode then
  144.         begin
  145.           usages := TOgUsageCode(Sender).GetValue;
  146.           DetailsStr := Format('Type: Usage Code' + sLineBreak +
  147.             'Uses Remaining: %d', [usages]);
  148.         end
  149.         else
  150.           DetailsStr := 'Invalid Usage Code';
  151.       end;
  152.     ctRegistration:
  153.       DetailsStr := 'Type: Registration Code';
  154.     ctSerialNumber:
  155.       DetailsStr := 'Type: Serial Number Code';
  156.     ctSpecial:
  157.       DetailsStr := 'Type: Special Code';
  158.   else
  159.     DetailsStr := 'Unknown License Type';
  160.   end;
  161.  
  162.   // Build the final validation string.
  163.   case Status of
  164.     ogValidCode:      FValidationDetails := '✅ Valid License' + sLineBreak + DetailsStr;
  165.     ogPastEndDate:    FValidationDetails := '⚠️ License Expired' + sLineBreak + DetailsStr;
  166.     ogInvalidCode:    FValidationDetails := '❌ Invalid License Code' + sLineBreak + DetailsStr;
  167.     else               FValidationDetails := '❓ Unknown Validation Status' + sLineBreak + DetailsStr;
  168.   end;
  169.   DebugLog('&#128221; Final Validation Status: ' + GetEnumName(TypeInfo(TCodeStatus), Ord(Status)));
  170. end;
  171.  
  172. { Core Function: ActivateLicense }
  173. function ActivateLicense(const LicenseCode, MachineCode: string; out ValidationDetails: string): Boolean;
  174. var
  175.   DecryptionKey: TKey;
  176.   KeyProvider: TMyKeyProvider;
  177.   LicenseComp: TOgCodeBase;
  178.   CodeBuffer: TCode;
  179.   CodeType: TCodeType;
  180.   Modifier: LongInt;
  181.   OriginalModifier: LongInt;
  182.   dtRaw, dtAdj: TDateTime;
  183. begin
  184.   ValidationDetails := '';
  185.   DebugLog(sLineBreak + '==== ActivateLicense START ====');
  186.   DebugLog('&#128190; LicenseCode: ' + LicenseCode);
  187.   DebugLog('&#128190; MachineCode: ' + MachineCode);
  188.  
  189.   { 1. Prepare decryption key using machine modifier }
  190.   DecryptionKey := ProductSecretKey;
  191.   if Trim(MachineCode) <> '' then
  192.   begin
  193.     if not TryStrToInt(MachineCode, OriginalModifier) then
  194.     begin
  195.       DebugLog('❌ ERROR: Invalid machine code format');
  196.       ValidationDetails := 'Invalid machine code format';
  197.       Exit(False);
  198.     end;
  199.     Modifier := SwapEndian(OriginalModifier);
  200.     DebugLog('&#128295; Using swapped machine modifier: $' + IntToHex(Modifier, 8));
  201.     ApplyModifierToKeyPrim(Modifier, DecryptionKey, SizeOf(DecryptionKey));
  202.   end;
  203.  
  204.   { 2. Validate license code format }
  205.   if not HexToBuffer(LicenseCode, CodeBuffer, SizeOf(CodeBuffer)) then
  206.   begin
  207.     DebugLog('❌ ERROR: Invalid license code hex format');
  208.     ValidationDetails := 'Invalid license code format';
  209.     Exit(False);
  210.   end;
  211.  
  212.   { 3. Detect code type using modified key }
  213.   CodeType := GetCodeType(DecryptionKey, CodeBuffer);
  214.   DebugLog('&#128270; Detected CodeType: ' + GetEnumName(TypeInfo(TCodeType), Ord(CodeType)));
  215.  
  216.   { 4. Create validator component based on detected code type }
  217.   case CodeType of
  218.     ctDate:         LicenseComp := TOgDateCode.Create(nil);
  219.     ctDays:         LicenseComp := TOgDaysCode.Create(nil);
  220.     ctUsage:        LicenseComp := TOgUsageCode.Create(nil);
  221.     ctSpecial:      LicenseComp := TOgSpecialCode.Create(nil);
  222.     ctRegistration: LicenseComp := TOgRegistrationCode.Create(nil);
  223.     ctSerialNumber: LicenseComp := TOgSerialNumberCode.Create(nil);
  224.   else
  225.     begin
  226.       DebugLog('❌ ERROR: Unsupported CodeType: ' + IntToStr(Ord(CodeType)));
  227.       ValidationDetails := 'Unsupported license type';
  228.       Exit(False);
  229.     end;
  230.   end;
  231.  
  232.   { 5. Perform validation }
  233.   KeyProvider := TMyKeyProvider.Create(DecryptionKey, LicenseCode);
  234.   try
  235.     LicenseComp.OnGetKey := @KeyProvider.DoGetKey;
  236.     LicenseComp.OnGetCode := @KeyProvider.DoGetCode;
  237.     LicenseComp.OnChecked := @KeyProvider.DoChecked;
  238.     DebugLog('&#128736;️ Validating with: ' + LicenseComp.ClassName);
  239.     Result := LicenseComp.CheckCode(True) = ogValidCode;
  240.     // If the license type is Date, perform an override check.
  241.     if (GetCodeType(DecryptionKey, CodeBuffer) = ctDate) then
  242.     begin
  243.       dtRaw := TOgDateCode(LicenseComp).GetValue;
  244.       if dtRaw < EncodeDate(2000,1,1) then
  245.         dtAdj := IncYear(dtRaw, 96) + 1
  246.       else
  247.         dtAdj := dtRaw;
  248.       if dtAdj > Now then
  249.       begin
  250.         Result := True;
  251.         KeyProvider.FStatusCode := ogValidCode;  // override status
  252.         KeyProvider.FValidationDetails :=
  253.           Format('✅ Valid License (Override)' + sLineBreak +
  254.                  'Type: Date Code' + sLineBreak +
  255.                  'Expiration: %s' + sLineBreak +
  256.                  'Current Date: %s',
  257.                  [FormatDateTime(ShortDateFormat, dtAdj),
  258.                   FormatDateTime(ShortDateFormat, Now)]);
  259.         DebugLog('✅ Override: Adjusted Expiration Date: ' + FormatDateTime(ShortDateFormat, dtAdj));
  260.       end;
  261.     end;
  262.     ValidationDetails := KeyProvider.ValidationDetails;
  263.   finally
  264.     LicenseComp.Free;
  265.     KeyProvider.Free;
  266.   end;
  267.   DebugLog('==== ActivateLicense END ====' + sLineBreak);
  268. end;
  269.  
  270. function ReadLicenseCode: string;
  271. var
  272.   Ini: TIniFile;
  273. begin
  274.   Ini := TIniFile.Create(GetAppConfigFile(False));
  275.   try
  276.     Result := Ini.ReadString('License', 'Key', '');
  277.     DebugLog('&#128229; ReadLicenseCode: ' + Result);
  278.   finally
  279.     Ini.Free;
  280.   end;
  281. end;
  282.  
  283. procedure WriteLicenseCode(const ACode: string);
  284. var
  285.   Ini: TIniFile;
  286. begin
  287.   Ini := TIniFile.Create(GetAppConfigFile(False));
  288.   try
  289.     Ini.WriteString('License', 'Key', ACode);
  290.     Ini.UpdateFile;
  291.     DebugLog('&#128228; WriteLicenseCode: ' + ACode);
  292.   finally
  293.     Ini.Free;
  294.   end;
  295. end;
  296.  
  297. procedure DebugLog(const S: string);
  298. var
  299.   F: TextFile;
  300. begin
  301.   try
  302.     AssignFile(F, 'debuglog.txt');
  303.     if FileExists('debuglog.txt') then
  304.       Append(F)
  305.     else
  306.       Rewrite(F);
  307.     WriteLn(F, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now) + ': ' + S);
  308.     CloseFile(F);
  309.   except
  310.     on E: Exception do ; // Fail silently
  311.   end;
  312. end;
  313.  
  314. function GetMachineModifierString: string;
  315. var
  316.   Modifier: LongInt;
  317. begin
  318.   Modifier := CreateMachineID([midUser, midSystem, midDrives]);
  319.   Result := '$' + BufferToHex(Modifier, SizeOf(Modifier));
  320.   DebugLog('&#128272; GetMachineModifierString: ' + Result);
  321. end;
  322.  
  323. function GetLicenseActivationMethod(const LicenseCode, MachineCode: string): TLicenseActivationMethod;
  324. var
  325.   CodeBuffer: TCode;
  326.   CodeType: TCodeType;
  327.   DecryptionKey: TKey;
  328.   Modifier: LongInt;
  329. begin
  330.   Result := lamUnknown;
  331.   if HexToBuffer(LicenseCode, CodeBuffer, SizeOf(CodeBuffer)) then
  332.   begin
  333.     DecryptionKey := ProductSecretKey;
  334.     if Trim(MachineCode) <> '' then
  335.     begin
  336.       if TryStrToInt(MachineCode, Modifier) then
  337.       begin
  338.         Modifier := SwapEndian(Modifier);
  339.         ApplyModifierToKeyPrim(Modifier, DecryptionKey, SizeOf(DecryptionKey));
  340.       end;
  341.     end;
  342.     CodeType := GetCodeType(DecryptionKey, CodeBuffer);
  343.     case CodeType of
  344.       ctDate:         Result := lamDate;
  345.       ctDays:         Result := lamDays;
  346.       ctRegistration: Result := lamRegistration;
  347.       ctSerialNumber: Result := lamSerialNumber;
  348.       ctUsage:        Result := lamUsage;
  349.       ctSpecial:      Result := lamSpecial;
  350.     end;
  351.   end;
  352. end;
  353.  
  354. function GetLicenseDetails(const LicenseCode: string): string;
  355. var
  356.   KeyProvider: TMyKeyProvider;
  357. begin
  358.   KeyProvider := TMyKeyProvider.Create(ProductSecretKey, LicenseCode);
  359.   try
  360.     Result := KeyProvider.ValidationDetails;
  361.   finally
  362.     KeyProvider.Free;
  363.   end;
  364. end;
  365.  
  366. procedure LoadLicenseFromIni(const IniFileName: string);
  367. var
  368.   Ini: TIniFile;
  369. begin
  370.   Ini := TIniFile.Create(IniFileName);
  371.   try
  372.     gLicenseCode := Ini.ReadString('License', 'Key', '');
  373.     DebugLog('&#128194; LoadLicenseFromIni: ' + gLicenseCode);
  374.   finally
  375.     Ini.Free;
  376.   end;
  377. end;
  378.  
  379. procedure SaveLicenseToIni(const IniFileName: string);
  380. var
  381.   Ini: TIniFile;
  382. begin
  383.   Ini := TIniFile.Create(IniFileName);
  384.   try
  385.     Ini.WriteString('License', 'Key', gLicenseCode);
  386.     Ini.UpdateFile;
  387.     DebugLog('&#128190; SaveLicenseToIni: ' + gLicenseCode);
  388.   finally
  389.     Ini.Free;
  390.   end;
  391. end;
  392.  
  393. initialization
  394.   DebugLog('==== License Manager Initialized ==== &#128512;');
  395.   DebugLog('&#128271; Product Secret: ' + BufferToHex(ProductSecretKey, SizeOf(ProductSecretKey)));
  396.  
  397. end.
  398.  
  399.  

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #13 on: February 17, 2025, 07:28:53 pm »
Now, I need to continue working on how to manage days decrease, usage decrease and similar things...
Anyway, at least verification of license codes now works.
I must emphasize once more, I am using OnGuard version being delivered with CodeTyphon v. 8.50. I have no idea whether it is the same version as being on Github or somewhere else...

rvk

  • Hero Member
  • *****
  • Posts: 6683
Re: OnGuard troubles with TOgDateCode and Machine Modifier
« Reply #14 on: February 17, 2025, 07:30:42 pm »
And here is the code:
Is that code working for you now?

(Because I don't see any InitXXX() calls in there)

Edit: ok, so I guess it is. It's not the correct way to work with it but if it works for you...
(I hope it's 'save' enough)
« Last Edit: February 17, 2025, 07:32:50 pm by rvk »

 

TinyPortal © 2005-2018