Jump to content

Shrinavat

Members
  • Content Count

    73
  • Joined

  • Last visited

  • Days Won

    4

Posts posted by Shrinavat


  1. On 2/18/2025 at 11:07 PM, alejandro.sawers said:

    "Get an exclusive first look at a very exciting and long-anticipated completely new secret preview version of your favorite IDE."

      

    What!?

    My favorite IDE is finally catching up to the current decade? Color me mildly intrigued. It's a 64-bit IDE, the worst-kept secret since someone figured out Clark Kent was Superman.

    • Haha 2

  2. Hi Kas Ob.,

    Thank you so much for your detailed response and for taking the time to look into this. I really appreciate your help and insights!

     

    You're right, the main issue was loading the private key correctly, as TurboPower LockBox 3 doesn't seem to have built-in ASN.1 decoding capabilities. After considering your suggestions, I decided to switch from TurboPower LockBox 3 and use an OpenSSL wrapper instead, along with libeay32.dll. This approach allows me to properly handle the PEM-encoded private key and perform the RSA decryption.

     

    I've managed to get it working, and it seems to be decrypting the string as expected. For anyone interested, I've attached a zip file with a sample project demonstrating the solution. Please note that the code is still a bit rough around the edges and could use some cleaning up.

     

    Thanks again for your guidance!

    src.zip

    • Like 1

  3. Hey everyone, I’m trying to reverse engineer a piece of JavaScript code found within an HTML file. It has this get_cookie_spsc_encrypted_part function, which contains an RSA private key embedded within a comment, and also an encrypted string. It uses some JavaScript crypto lib, KJUR.crypto.Cipher.decrypt, to decrypt this string.

    Here’s the Javascript code:

    function get_cookie_spsc_encrypted_part() {
     let func = function () {/*-----BEGIN RSA PRIVATE KEY-----
    MIICXAIBAAKBgQDFoP5AJIv1KFGRpv/Uw7drFXjWbZG6wNsO7P58ocZIcxyKGU6u
    TgXw8N1IvTmd9yXRSdcb2fCWB7J/QUQDJQ3YuuXSOQCVOdi8Wy9UoZ5jNdqtZ6CM
    CvnK/v4Wy38ZhrB0CRkeiuyjmUdfQhe8mh3pE3iFBusYd1TVCxQt3VBkqQIDAQAB
    AoGAaYBaeo+ID6YodWL7a+/XeNkLmxz/EP1nc/5clNgf7AlXkPmVoUORtGBBIVWy
    7ntDuwh6Ryn/X3hYd8q1riAX1UwVuUduOENmgyzmO1rRIoB/17vzYwVMYOB2h+qb
    xEqjg4dUfk/1occyDwpehWel+1NIgvQLNYLcn2JXxkAyrMkCQQD37+3Y8sjYxwAp
    giIClsCjrla73cS/QwzArGEnOjBs86LyzCc0pNzmP2OD0a9VlD3k6dMnhT2Oj+2k
    nZs8dUlHAkEAzA4/mQeFvdiKIkzUBECn3w9Ylu2IfpKnQt/0EFUENxS9ONZ1jj4p
    zDBfZosgwnE1GiECELM3R/6Pzl+uIGrajwJBALm5HG3az+CykMiHFnrh+kOiII5x
    vSOYUkEx30THLecvSeyeSPACXwaKjTz9IV31wbdsACQmhsn3vogFF3feU5kCQARP
    9MYeI5RshBbPeteQKjwLjfq6kFzkaoZ+RyElOs6TMKCH37oe1DFNgGahYBLb45xm
    wC1sLCnoVk+tM/fZaj8CQGQyIlxwbgNBBdV3wnmtX9yPDflOsjpo3FuBMOu3nZAD
    KEpmTXFgdwP4oMMbCmDvH3dav92LE5JN1cPik9z0Piw=
    -----END RSA PRIVATE KEY-----
    */};
     let pem = func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];
     return KJUR.crypto.Cipher.decrypt("82a4fa1da959701407ae4a80b48c0dca57d68fb5e54df1794418b03ba43ef9022328e4be4011ffbeb74d9d22769634a21537ba32788342f8abe6cfddc22512a39373ea2488af389740ac4f93699da92fcd86895c64bd6760a5aea27e172052947361177f3674ec68c52480744a75163c892556ec526387c92c0b50ab0b3a4ea5", KEYUTIL.getKey(pem));
    }
    

    I’ve managed to replicate the decryption in C# using System.Security.Cryptography. Here’s the C# code:

    using System.Text.RegularExpressions;
    using System.Security.Cryptography;
    
    var pemKey = Regex.Match(html, "-----BEGIN RSA PRIVATE KEY-----[\\s\\S]*?-----END RSA PRIVATE KEY-----").Value;
    var encryptedDataHex = Regex.Match(html, @"KJUR.crypto.Cipher.decrypt\(""(.*)""").Groups[1].Value;
    using var rsa = RSA.Create();
    rsa.ImportFromPem(pemKey);
    var decryptedData = rsa.Decrypt(Convert.FromHexString(encryptedDataHex), RSAEncryptionPadding.Pkcs1); // Perform Decryption
    

    Now, I’m trying to do the same in Delphi, and I’d like to use TurboPower LockBox 3. Unfortunately, the official documentation seems to be offline. I am struggling to understand how to use LockBox 3, or other suitable free libraries for this purpose. Could anyone provide some Delphi code examples and guidance on how to do the RSA decryption, using LockBox or any other free library? Any help would be greatly appreciated!

     

    Here's my code:

    program RSA_test;
    
    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils,
      System.Classes,
      System.RegularExpressions,
      uTPLb_Codec,
      uTPLb_CryptographicLibrary,
      uTPLb_BaseNonVisualComponent,
      uTPLb_Signatory,
      uTPLb_Constants,
      uTPLb_Asymetric,
      uTPLb_RSA_Engine,
      uTPLb_OpenSSL;
    
    const
      HTML =
        '<html><head><script>function get_cookie_spsc_encrypted_part() {' +
        '  let func = function () {/*-----BEGIN RSA PRIVATE KEY-----' +
        'MIICXAIBAAKBgQDFoP5AJIv1KFGRpv/Uw7drFXjWbZG6wNsO7P58ocZIcxyKGU6u' +
        'TgXw8N1IvTmd9yXRSdcb2fCWB7J/QUQDJQ3YuuXSOQCVOdi8Wy9UoZ5jNdqtZ6CM' +
        'CvnK/v4Wy38ZhrB0CRkeiuyjmUdfQhe8mh3pE3iFBusYd1TVCxQt3VBkqQIDAQAB' +
        'AoGAaYBaeo+ID6YodWL7a+/XeNkLmxz/EP1nc/5clNgf7AlXkPmVoUORtGBBIVWy' +
        '7ntDuwh6Ryn/X3hYd8q1riAX1UwVuUduOENmgyzmO1rRIoB/17vzYwVMYOB2h+qb' +
        'xEqjg4dUfk/1occyDwpehWel+1NIgvQLNYLcn2JXxkAyrMkCQQD37+3Y8sjYxwAp' +
        'giIClsCjrla73cS/QwzArGEnOjBs86LyzCc0pNzmP2OD0a9VlD3k6dMnhT2Oj+2k' +
        'nZs8dUlHAkEAzA4/mQeFvdiKIkzUBECn3w9Ylu2IfpKnQt/0EFUENxS9ONZ1jj4p' +
        'zDBfZosgwnE1GiECELM3R/6Pzl+uIGrajwJBALm5HG3az+CykMiHFnrh+kOiII5x' +
        'vSOYUkEx30THLecvSeyeSPACXwaKjTz9IV31wbdsACQmhsn3vogFF3feU5kCQARP' +
        '9MYeI5RshBbPeteQKjwLjfq6kFzkaoZ+RyElOs6TMKCH37oe1DFNgGahYBLb45xm' +
        'wC1sLCnoVk+tM/fZaj8CQGQyIlxwbgNBBdV3wnmtX9yPDflOsjpo3FuBMOu3nZAD' +
        'KEpmTXFgdwP4oMMbCmDvH3dav92LE5JN1cPik9z0Piw=' +
        '-----END RSA PRIVATE KEY-----' +
        '*/};' +
        '  let pem = func.toString().match(/[^]*\\/\\*([^]*)\\*\\/\\}$/)[1];' +
        '  return KJUR.crypto.Cipher.decrypt("82a4fa1da959701407ae4a80b48c0dca57d68fb5e54df1794418b03ba43ef9022328e4be4011ffbeb74d9d22769634a21537ba32788342f8abe6cfddc22512a39373ea2488af389740ac4f93699da92fcd86895c64bd6760a5aea27e172052947361177f3674ec68c52480744a75163c892556ec526387c92c0b50ab0b3a4ea5", KEYUTIL.getKey(pem));' +
        '} </script></head><body></body></html>';
    
    var
      PEMKey, EncryptedDataHex, DecryptedData: string;
      Codec: TCodec;
      CryptoLib: TCryptographicLibrary;
      Signatory: TSignatory;
      EncryptedBytes, DecryptedBytes: TBytes;
      MemStream: TMemoryStream;
      StringStream: TStringStream;
    
    begin
      try
        Codec := TCodec.Create(nil);
        CryptoLib := TCryptographicLibrary.Create(nil);
        Signatory := TSignatory.Create(nil);
    
        try
          with TRegEx.Match(HTML, '-----BEGIN RSA PRIVATE KEY-----[\s\S]*?-----END RSA PRIVATE KEY-----') do
            if Success then PEMKey := Value;
    
          with TRegEx.Match(HTML, 'KJUR\.crypto\.Cipher\.decrypt\("(.*)\"') do
            if Success then EncryptedDataHex := Groups[1].Value;
    
          // Convert base64-string to bytes
          EncryptedBytes := TNetEncoding.Base64.DecodeStringToBytes(EncryptedDataHex);
    
          // Setup encryption components
          Codec.CryptoLibrary := CryptoLib;
          Codec.StreamCipherId := 'native.RSA';
          Codec.ChainModeId := 'native.CBC';
          Codec.AsymetricKeySizeInBits := 1024; // ???
    
          StringStream := TStringStream.Create(PEMKey);
          try
            Signatory.Codec := Codec;
            Signatory.LoadKeysFromStream(StringStream, [partPrivate]); // !!! raised exception class EReadError with message 'Stream read error'
          finally
            StringStream.Free;
          end;
    
          // Decrypt data
          MemStream := TMemoryStream.Create;
          try
            MemStream.WriteBuffer(EncryptedBytes[0], Length(EncryptedBytes));
            MemStream.Position := 0;
    
            Codec.DecryptStream(MemStream, MemStream); // In-place decryption
    
            // Get decrypted data
            SetLength(DecryptedBytes, MemStream.Size);
            MemStream.Position := 0;
            MemStream.ReadBuffer(DecryptedBytes[0], MemStream.Size);
    
            DecryptedData := TEncoding.UTF8.GetString(DecryptedBytes);
          finally
            MemStream.Free;
          end;
    
        finally
          Codec.Free;
          CryptoLib.Free;
          Signatory.Free;
        end;
    
      except
        on E: Exception do
          WriteLn(E.ClassName, ': ', E.Message);
      end;
    
      ReadLn;
    end.

     


  4. 21 hours ago, FPiette said:

    Plain text CSV is my prefered format.

    Thank you for the suggestion! Using a sorted CSV file with a dedicated comparison tool sounds like a very interesting and potentially robust approach. I'll definitely explore this option further.

     

    19 hours ago, Die Holländer said:

    <?xml version="1.0" encoding="UTF-8"?>

    Thanks for sharing the XML example. I'm already familiar with saving the configuration in XML format 🙂. However, my main challenge lies in efficiently comparing two XML files to identify meaningful changes. I'm open to suggestions on how to best approach this comparison aspect.

     

    16 hours ago, corneliusdavid said:

    I'd be tempted to throw it in a small SQLite database.

    That's an interesting idea using SQLite. My main concern with a database approach is the unknown and variable number of fields. I'm not sure how to design the database structure to accommodate this and still allow for easy comparison between different snapshots. Could you elaborate on how you envision structuring the database to handle this dynamic nature and facilitate efficient comparisons?


  5. Hello everyone,

    I'm working on a utility that gathers PC configuration information and displays it in a TTree component. I want to be able to save this information to a file so that it can be compared with a similar file created at a later time. This would allow me to detect any changes in the PC's configuration, such as adding or removing hardware components.

    My main challenge is deciding on the best format to store this data for easy comparison and change detection. I've considered options like JSON, XML, and plain text, but I'm unsure which would be most suitable. A simple line-by-line comparison of a text file might not be reliable, as the order of components could change without signifying an actual configuration change (e.g., reordering hard drives).

    Could anyone offer advice on the best approach for storing and comparing this type of data? Are there any specific technologies or libraries that would be helpful for this task?

    Any guidance would be greatly appreciated!

    scr.jpg


  6. 2 hours ago, Kas Ob. said:

    Well see ROT13, Caesar and their family, these doesn't need key but easy to add one in case you want to, by shifting (adding) by the key, these it might fit your need

    Thanks for the feedback! I ended up implementing a modified ROT13 algorithm with a custom alphabet, as shown in the code below. Initial tests indicate that it meets my requirements effectively.

    const
      ALL_CHARACTERS_CONSTANT = '!#$%&()*+,-./:;<=>?@[\]^_`{|}~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя';
    
    function ROT13Encrypt(const Input: string): string;
    var
      idx, newIdx: Integer;
      halfLength: Integer;
    begin
      Result := '';
      halfLength := Length(ALL_CHARACTERS_CONSTANT) div 2;
    
      for var i := 1 to Length(Input) do
      begin
        idx := Pos(Input[i], ALL_CHARACTERS_CONSTANT);
        if idx > 0 then
        begin
          newIdx := ((idx - 1 + halfLength) mod Length(ALL_CHARACTERS_CONSTANT)) + 1;
          Result := Result + ALL_CHARACTERS_CONSTANT[newIdx];
        end
        else
          Result := Result + Input[i];
      end;
    end;
    
    function ROT13Decrypt(const Input: string): string;
    begin
      // ROT13 decryption is the same as encryption in this case
      Result := ROT13Encrypt(Input);
    end;

     

    • Like 2

  7. Thank you for your insights. I understand the challenges involved in meeting both requirements simultaneously.
    I'm willing to remove the constraint that "The obfuscated string must contain only Latin letters and digits."
    Revised requirements:

    • The obfuscated string can contain any printable characters.
    • The obfuscated string must have the same length as the original string.
    • Strong cryptographic security is not required.
    • The input strings will generally not exceed 30 characters in length.

    With this revised requirement, are there any suitable algorithms or approaches you could suggest for implementing the obfuscation and deobfuscation functions?


  8. How can I implement functions for basic string obfuscation and deobfuscation in Delphi, where the input string can contain Latin and Cyrillic letters, digits, and special characters !@#$%^&*()_+-=[]{}\|;':",./<>?

    Requirements:

    • The obfuscated string must contain only Latin letters and digits.
    • The obfuscated string must have the same length as the original string.
    • Strong cryptographic security is not required.

    I'm looking for a simple solution that can handle a variety of characters and maintain the original string length. Any suggestions or code examples would be greatly appreciated.

     

     


  9. The issue stemmed from how variables were captured within the closure passed to Parallel.Async. The loop variable i was not correctly captured, leading to incorrect values being used in the background tasks.
    The following code demonstrates my working solution:

    procedure Test;
    var
      arr_id: TArray<LongWord>;
      arr_ip: TArray<string>;
    
      procedure CreatePingTask(const id: LongWord; const ip: string);
      begin
        Parallel.Async(
          procedure (const task: IOmniTask)
          var
            PingResult: Boolean;
          begin // background thread
            // Simulate ping
            PingResult := Random(2) = 1; // random result for demonstration
            Sleep(Random(5000)); // simulate ping delay
    
            // in the main thread
            task.Invoke(
              procedure
              begin
                mmoLog.Lines.Add(Format('PingResult=%s, rec_id=%d, rec_ip=%s', [PingResult.ToString, id, ip]));
              end);
          end);
      end;
    
    begin
      arr_id := [1,2,3,4,5,6,7];
      arr_ip := ['192.168.16.1','192.168.16.2','192.168.16.3','192.168.16.4','192.168.16.5','192.168.16.6','192.168.16.7'];
    
      for var i := Low(arr_id) to High(arr_id) do
        CreatePingTask(arr_id[i], arr_ip[i]);
    end;

    Explanation:
    To ensure each background task receives the correct ID and IP, we pass them as parameters to the CreatePingTask procedure. This creates a separate copy of the variables for each task.
    task.Invoke is used to synchronize with the main thread and update the UI with the ping results.
    This approach ensures that each host is pinged exactly once and the results are processed correctly in the main thread.

    I'd love to get some expert opinions on my solution. Are there any "gotchas" I should be watching out for?


  10. I'm using the Async abstraction from the OmniThreadLibrary to ping multiple hosts in background threads (one thread per host). In the main thread, I want to perform some actions with the ping results based on the host ID. Here's a simplified version of my code:

    procedure Test;
    var
      arr_id: TArray<LongWord>;
      arr_ip: TArray<string>;
    begin
      arr_id := [1,2,3,4,5,6,7];
      arr_ip := ['192.168.16.1','192.168.16.2','192.168.16.3','192.168.16.4','192.168.16.5','192.168.16.6','192.168.16.7'];
    
      for var i := Low(arr_id) to High(arr_id) do
      begin
        Parallel.Async(
          procedure (const task: IOmniTask)
          var
            PingResult: Boolean;
            rec_id: LongWord;
            rec_ip: string;
          begin // background thread
            rec_id := arr_id[i];
            rec_ip := arr_ip[i];
            // PingResult := PingHost(rec_ip);
    
            // in the main thread
            task.Invoke(
              procedure
              begin
                // some actions with ping results based on host ID
                mmoLog.Lines.Add(Format('rec_id=%d, rec_ip=%s', [rec_id, rec_ip]));
              end);
          end);
      end;
    end;

    I'm getting inconsistent results. For example:

    rec_id=3, rec_ip=192.168.16.3
    rec_id=3, rec_ip=192.168.16.3
    rec_id=135299280, rec_ip=烬Ŧ
    rec_id=135299280, rec_ip=烬Ŧ
    rec_id=135299280, rec_ip=烬Ŧ
    rec_id=135299280, rec_ip=烬Ŧ
    rec_id=135299280, rec_ip=烬Ŧ
     or

    rec_id=2, rec_ip=192.168.16.2
    rec_id=3, rec_ip=192.168.16.3
    rec_id=4, rec_ip=192.168.16.4
    rec_id=7, rec_ip=192.168.16.7
    rec_id=7, rec_ip=192.168.16.7
    rec_id=7, rec_ip=192.168.16.7
    rec_id=135299280, rec_ip=烬Ŧ

     

    Not all IPs are being pinged, and some are pinged multiple times. Also, I get garbage data in some cases.

    How can I achieve the desired behavior, where each IP is pinged once and the results are processed correctly in the main thread? Alternatively, how can I rewrite the code using TTask?


  11. Maybe the 'Allow tabs to use custom colors' option is like the Force in Star Wars - a mystical power that only a few chosen ones can truly understand and control. May the colors be with you, young Padawan. ...on a more serious note, has anyone cracked the code on how to actually use this mysterious option? Does anyone actually know how to change the tab colors?

     

    tab1.png


  12. Quote

    Allow tabs to use custom colors Enabled by default. This option allows you to activate the custom colors support in the editor tabs.

    What is the purpose of this feature? How can I change the color of the tab in the code editor? I am unable to find an option to modify the color in the tab settings.

    tabs.png


  13. Upon each launch of IDE, the Component Palette panel consistently shifts to the right by a specific distance. This behavior requires me to manually drag the panel back to its original position on the left side every time I start Delphi 12.
    Additionally, I have observed that the "Lock Controls" icon from the "View" toolbar disappears. I have manually added this icon to the toolbar, but it vanishes. It reappears only after selecting the same action through the "Edit|Lock Controls" menu. I have attached a screenshot illustrating the issue.

     

    I would like to inquire if there is a solution or workaround to address this problem. Is there a way to lock or fix the position of the Component Palette panel, so it remains in place across Delphi 12 sessions?

    Additionally, I am curious about where the configuration data for the panel's position is stored. Does Delphi 12 save this information in the registry, a configuration file, or elsewhere?

    screenshot.png


  14. I've found the source of the problem. It turned out to be third-party components - ESBPCS for VCL. If they are disabled, then the problem disappears. As @balabuev rightly pointed out, here's what's to blame: "Non-standard property editors are installed. More technically, this happens when a property editor implements the ICustomPropertyDrawing interface but does not implement the more recently introduced ICustomPropertyDrawing80 interface."
    The developer of these components has already been notified.

    • Like 2
    • Thanks 1

  15. I'm encountering a problem with the color names in freshly installed Delphi 12, and this issue also existed in Delphi 11.x. The problem is observed as a text "overlay" in any Object Inspector field related to color, as illustrated in the attached animation. It seems to occur regardless of whether any experts or updates are installed. How can I address this issue?

    animation.gif


  16. I recently installed RAD Studio 12 Pro with Delphi. Now a ProjectName.dsv file is being created in the project folder. What is this, and how can I disable the creation of this file? Here's what its contents look like for example:
     

    [ClosedView_RDpcRGVscGhpX3Byb2plY3RzXENhbGxDZW50ZXJcQ2FsbENlbnRlci5kcHI=]
    Module=D:\Delphi_projects\CallCenter\CallCenter.dpr
    CursorX=1
    CursorY=18
    TopLine=1
    LeftCol=1
    Elisions=
    Bookmarks=
    EditViewName=D:\Delphi_projects\CallCenter\CallCenter.dpr
    [ClosedView_RDpcRGVscGhpX3Byb2plY3RzXENhbGxDZW50ZXJcX3VuaXRzXGZyYW1lc1xmclJlcG9ydF9UcmFu
    c2ZlcnJlZFRvQW5vdGhlckRlcGFydG1lbnQucGFz]
    Module=D:\Delphi_projects\CallCenter\_units\frames\frReport_TransferredToAnotherDepartment.pas
    CursorX=1
    CursorY=1
    TopLine=1
    LeftCol=1
    Elisions=
    Bookmarks=
    EditViewName=
    [ClosedView_RDpcRGVscGhpX3Byb2plY3RzXENhbGxDZW50ZXJcX3VuaXRzXGZvcm1zXGZybVJlZmVyZW5jZS5w
    YXM=]
    ...

     


  17. On 3/21/2023 at 12:51 AM, rgdawson said:

    The new editor feature that highlights words that you select where visible elsewhere in the editor causes the editor to scroll unexpectedly if you are using folding, which I do, so I had to disable that feature.

    Yes, I also turned off this feature because of the spontaneous jumps of the text. It's very annoying. Is there any RSP about this?

    • Like 1
×