Jump to content
Shrinavat

RSA decryption from JavaScript

Recommended Posts

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.

 

Share this post


Link to post

Hi,

I waited for someone else to add an answer for you as i don't use LockBox, and have no experience with it, sources i looked at

https://github.com/TurboPack/LockBox

https://github.com/TurboPack/LockBox3

 

Now to what i see (without building or compiling anything):

1) Extracted the private key from your post and pasted it on ASN1 decoder and here the result

https://lapo.it/asn1js/#MIICXAIBAAKBgQDFoP5AJIv1KFGRpv_Uw7drFXjWbZG6wNsO7P58ocZIcxyKGU6uTgXw8N1IvTmd9yXRSdcb2fCWB7J_QUQDJQ3YuuXSOQCVOdi8Wy9UoZ5jNdqtZ6CMCvnK_v4Wy38ZhrB0CRkeiuyjmUdfQhe8mh3pE3iFBusYd1TVCxQt3VBkqQIDAQABAoGAaYBaeo-ID6YodWL7a-_XeNkLmxz_EP1nc_5clNgf7AlXkPmVoUORtGBBIVWy7ntDuwh6Ryn_X3hYd8q1riAX1UwVuUduOENmgyzmO1rRIoB_17vzYwVMYOB2h-qbxEqjg4dUfk_1occyDwpehWel-1NIgvQLNYLcn2JXxkAyrMkCQQD37-3Y8sjYxwApgiIClsCjrla73cS_QwzArGEnOjBs86LyzCc0pNzmP2OD0a9VlD3k6dMnhT2Oj-2knZs8dUlHAkEAzA4_mQeFvdiKIkzUBECn3w9Ylu2IfpKnQt_0EFUENxS9ONZ1jj4pzDBfZosgwnE1GiECELM3R_6Pzl-uIGrajwJBALm5HG3az-CykMiHFnrh-kOiII5xvSOYUkEx30THLecvSeyeSPACXwaKjTz9IV31wbdsACQmhsn3vogFF3feU5kCQARP9MYeI5RshBbPeteQKjwLjfq6kFzkaoZ-RyElOs6TMKCH37oe1DFNgGahYBLb45xmwC1sLCnoVk-tM_fZaj8CQGQyIlxwbgNBBdV3wnmtX9yPDflOsjpo3FuBMOu3nZADKEpmTXFgdwP4oMMbCmDvH3dav92LE5JN1cPik9z0Piw

And that is correct and valid RSA key, yet clicked and browsed the sources on github, there is no ASN1 decoder in the sources, the closest thing is using OpenSSL to do the loading of the private key, or to be more accurate to decode the private key to usable format by TP.

 

2) searching for KJUR.crypto.Cipher.decrypt, found this

https://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Cipher.html

So the encryption indeed is RSAOAEP, (RSA encryption is completely different from RSAOAEP for future references don't mix them), also check the sources and its look like TP can do RSAOAEP 

https://github.com/TurboPack/LockBox3/blob/master/run/RSA/uTPLb_RSA_Primitives.pas#L116

And that what you should use, so your code is using "Signatory: TSignatory" in complete wrong path

 

3) Also important the JS code does the decryption, and as usual decryption parameters way less than encryption, to perform RSAOAEP encryption and decryption sometimes you need the default parameters and sometimes you need to figure if there is some default must be set before the decryption. 

 

3) Couldn't find useful examples for you but, so others may help here, or you can start by looking at 

https://github.com/TurboPack/LockBox3/blob/master/test/uLockBox_RSA_TestCases.pas#L466

Notice there codec and no TSignatory, but the most important (for me at least) these keys are not decodable as they are not ASN1, from the sources they look like custom format specific to LockBox

 

Here SO question, close enough to your problem 

https://stackoverflow.com/questions/68186850/lockbox-3-encrypt-rsa-with-public-certyficate

Again couldn't find what can solve your problem in full

 

Suggestion

With above i hope you have better understanding what is your problem actually is, it is loading the private key as first step, then perform the right decryption with RSAOAEP, and that is it, so either try with OpenSSL to load and decrypt or look for different library.

 

And good luck !

  • Like 2
  • Thanks 1

Share this post


Link to post

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

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×