Jump to content

Dave Nottage

Members
  • Content Count

    1609
  • Joined

  • Last visited

  • Days Won

    36

Posts posted by Dave Nottage


  1. 9 minutes ago, Kas Ob. said:

    So this 

    
    EVP_CIPHER_CTX_set_padding(LContext, 0);

    After EVP_DecryptInit_ex should solve the failure of EVP_DecryptFinal_ex,

    That it does, thanks! 

    10 minutes ago, Kas Ob. said:

    the rest is up to you to find and fix, specially that HMAC !!!!!, where it comes from ?

    From other code I found. Yes, I guess that part is wrong since the output is wrong.


  2. The goal is to be able to encrypt some data using crypto-js (in Javascript) and decrypt the value in a back end built with Delphi, using OpenSSL (since crypto-js claims to be OpenSSL compliant).

     

    This is the Javascript code:

    const CryptoJS = require('crypto-js');
    
    var IV = '583066480e215358084bc6640df95fdd';
    var passphrase = 's0m3s3cr3t!';
    
    // According to:
    //   https://stackoverflow.com/a/75473014/3164070
    // IV is ignored, so can be anything!
    
    function encrypt(text: string): string {
      var key = passphrase;
      var iv = CryptoJS.enc.Hex.parse(IV);
      console.log('iv: ' + iv.toString());
      var encrypted = CryptoJS.AES.encrypt(text, key, { iv: iv });
      return encrypted.toString();
    }

    This is the Delphi code. Note that OpenSSL.Api_11 comes from Grijjy (as well as the SSL binaries):

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    uses
      System.NetEncoding,
      OpenSSL.Api_11;
    
    const
      cPassphrase = 's0m3s3cr3t!';
    
    procedure CryptoError;
    var
      LError: TBytes;
      LMessage: string;
    begin
      SetLength(LError, 120);
      ERR_load_crypto_strings;
      ERR_error_string_n(ERR_get_error, @LError[0], Length(LError));
      LMessage := TEncoding.UTF8.GetString(LError);
      // Display the message
    end;
    
    function DecryptAES256(const AValue: string): string;
    var
      LContext: PEVP_CIPHER_CTX;
      LOutputLen, LFinalLen: Integer;
      LBytes, LSalt, LIV, LEncryptedText, LKey, LOutput: TBytes;
    begin
      Result := '';
      LBytes := TNetEncoding.Base64.DecodeStringToBytes(AValue);
      // crypto-js returns an OpenSSL result, i.e. "salted__" + salt + encrypted text
      LSalt := Copy(LBytes, 8, 8);
      LEncryptedText := Copy(LBytes, 16, MaxInt);
      SetLength(LKey, EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH);
      // Calc key and IV from passphrase and salt
      if PKCS5_PBKDF2_HMAC(cPassphrase, Length(cPassphrase), @LSalt[0], Length(LSalt), 1000, EVP_sha256, Length(LKey), @LKey[0]) = 1 then
      begin
        LIV := Copy(LKey, EVP_MAX_KEY_LENGTH, EVP_MAX_IV_LENGTH);
        LKey := Copy(LKey, 0, EVP_MAX_KEY_LENGTH);
        // Create a new cipher context
        LContext := EVP_CIPHER_CTX_new();
        if LContext <>  nil then
        try
          // Initialize the decryption operation with 256 bit AES
          if EVP_DecryptInit_ex(LContext, EVP_aes_256_cbc, nil, @LKey[0], @LIV[0]) = 1 then
          begin
            SetLength(LOutput, Length(LEncryptedText) + EVP_MAX_BLOCK_LENGTH);
            // Provide the message to be decrypted, and obtain the plaintext output
            if EVP_DecryptUpdate(LContext, @LOutput[0], @LOutputLen, @LEncryptedText[0], Length(LEncryptedText)) = 1 then
            begin
              if EVP_DecryptFinal_ex(LContext, @LOutput[LOutputLen], @LFinalLen) = 1 then
              begin
                Inc(LOutputLen, LFinalLen);
                Result := TEncoding.UTF8.GetString(LOutput);
              end
              else
                CryptoError;
            end
            else
              CryptoError;
          end
          else
            CryptoError;
        finally
          EVP_CIPHER_CTX_free(LContext);
        end;
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      // Decrypt value output by crypto-js
      DecryptAES256('U2FsdGVkX1812TdTm8MD2w4u2AaxUB2PdurCNOmu4bmutkR1Ul7Z1+bGXDsdlNK5'); // This is just an example value. Generate a new one from the Javascript code
    end;

    The code "fails" at the EVP_DecryptFinal_ex stage. Have I missed anything obvious?

     

    I know there's 3rd party code that will probably handle this, however it's just this function that is required (for now), so I'd prefer to avoid introducing a bunch of dependencies


  3. On 9/9/2023 at 2:36 AM, grantful said:

    I am just wondering is there a way to access this and use it in my iOS app

    Should be possible using Vision and VisionKit, as indicated by this article. It's in Swift, so you'd need to know how to translate it into Delphi, but you could use these imports:

     

    https://github.com/DelphiWorlds/Kastri/blob/master/API/DW.iOSapi.Vision.pas

    https://github.com/DelphiWorlds/Kastri/blob/master/API/DW.iOSapi.VisionKit.pas  Please take heed of the notes in this unit!

     


  4. 59 minutes ago, Brian Evans said:

    A HTTP GET doesn't use a body

    It can, but there are warnings against doing it. This is an interesting article on the topic.

     

    The fact that it is possible (even though ill advised) means that the code in Delphi that turns the GET into a POST on Android, is a bug.

    Jon R should describe why they need to subvert the warnings against doing it 🙂

    • Like 1

  5. 23 hours ago, Dave Nottage said:

    You’ll need TEdgeBrowser or something similar to actually render it for you

    I've decided to go down this route - it has turned out easier than I expected, especially when using ExecuteJavascript to extract the relevant parts out of the HTML


  6. I have some code that queries mvnrepository via HTTP, specifically looking for packages for Android. It essentially boils down to this:

    uses
      System.Net.HttpClient;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LHTTP: THTTPClient;
      LResponse: IHTTPResponse;
    begin
      LHTTP := THTTPClient.Create;
      try
        LResponse := LHTTP.Get('https://mvnrepository.com/search?q=play+services+maps'); // for example
        // At this point, LResponse.StatusCode is 403 :-(
        // The same query works in regular browsers
      finally
        LHTTP.Free;
      end;
    end;

    Except that recently, as per the comment, it now returns a 403 result, with this content (truncated):

    <!DOCTYPE html><html lang="en-US"><head><title>Just a moment...</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><meta name="robots" content="noindex,nofollow"><meta name="viewport" content="width=device-width,initial-scale=1"><link href="/cdn-cgi/styles/challenges.css" rel="stylesheet"></head><body class="no-js"><div class="main-wrapper" role="main"><div class="main-content"><noscript><div id="challenge-error-title"><div class="h2"><span class="icon-wrapper"><div class="heading-icon warning-icon"></div></span><span id="challenge-error-text">Enable JavaScript and cookies to continue</span></div></div></noscript></div></div>

    ..and is followed by a bunch of cryptic JavaScript.
     

    If there was an API (such as REST), I'd use that, however there does not appear to be, and I haven't had a reply for my email to info@mvnrepository.com.

     

    Any ideas as to how I might be able to handle it?


  7. 29 minutes ago, JohnLM said:

    The VCL app is up and running, and the TetherDBClient compiles and runs on the mobile device, but there is no database showing and the two devices do not connect, that is, when I click on the [Connect] button on the mobile device

    Same here. Not sure which method(s) it tries to use to tether in this case - I can take a deeper look later if no-one else answers beforehand. 


  8. 1 minute ago, alogrep said:

    Open an existing project, press DEL Key twice (to delete 2 letters) and the IDE goes fishing: keystrokes or mouse totally disabled. 

    Either there's a step missing between opening an existing project and pressing the DEL key, or it just doesn't happen for me.

×