Decrypt text encrypted in Java

I am using TRSAEnc decryption with private key file to decrypt a key that was encrypted in Java using the following Java code to encrypt the key with a public cert:

public static String encryptSessionKey(byte[] sessionKey, String publicCertificatePath) throws Exception {
        //Load public key
        PublicKey publicKey = getPublicKeyFromCertificate(publicCertificatePath);
        //Prepare cipher with correct transform and padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(sessionKey);
        //return as base64
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

I am unable to successfully decrypt the encrypted key, I always get exception attached:

Using dfollowing Delphi code:

 lRSA := TRSAEncSign.Create;
  try
    lBytes := TNetEncoding.Base64.DecodeStringToBytes(memEncSessionKey.Text);
    lText := Convert1.TBytesToString(lBytes);
    lRSA.FromPrivateKeyFile(aTestCert);
    lRSA.hashFunction := sha256;
    lRSA.encType := TRSAEncType.oaep;
    lRSA.keyLength := kl2048;
    lText := lRSA.Decrypt(lText);
    Memo3.Text;
  finally
    lRSA.Free;
    SetLength(lBytes, 0);
  end;

Is there anything I am missing?

Hi,
What version of TMS CP are you using? v5.0.9.0 should work fine, unless the byte order is different from one piece of code to the other.

Hi Bernard
Thanks, seems I am running on 4.3.3.0. Will upgrade and try again.

Hi Bernard
Maybe I am missing something but I cannot see how to upgrade to v5.0.9.0. We recently purchased TMS Crypto Pack and what we were given is 4.3.3.0.


How would I go about upgrading to v5.0.9.0?
Thanks

Hi Roy,
You shoyld see something like that

and select the 'Beta' ZIP.
Regards,
bernard

Hi Bernard
I got the beta, unzipped it and copied over the pas files, overwriting the v4.3.3 pas files.
I tried to decrypt the key generated by Java function and now I get the following error:
'Exception with message 'Invalid Operation : -314'.

procedure TForm1.btnDecrypt2Click(Sender: TObject);
var
  lRSA : TRSAEncSign;
  lText : String;
begin
  lRSA := TRSAEncSign.Create;
  try
    lText := Convert1.Base64ToHexa(memEncSessionKey.Text);
    lRSA.FromPrivateKeyFile(fTestPrivateKey);
    //lRSA.hashFunction := sha256;
    //lRSA.encType := TRSAEncType.oaep;
    //lRSA.keyLength := kl2048;
    lText := lRSA.Decrypt(lText);
    Memo3.Text;
  finally
    lRSA.Free;
  end;
end;

I tried with the commented code in and out and I get the same error.
I tried using inputformat = base64 and then using the base64 string from Java as the input without converting it and I get the same error.
I tried settign inputformat = raw and then using FormatToChar, but I get the same error.
Am I missing something?

Hi Roy,
Error 314 is an RSA_ERROR_OAEP_DECRYPT, which means the decrypted value doesn't pass the format tests.
lText should be decoded as 'raw'. The key should be automatically set to 2048 if loaded from a 2048 bit private key (what is the format? PKCS#8?).
Could you send me a project with the relevant key and encrypted data, so that I can check?

Regards,
bernard

bernard@tmssoftware.com

Hi Bernard
I sent an email to you with the subject 'Roy M: Java RSA decryption sample project', it is not from the registered email address on this account.
Thank you

From Stack Overflow.

Java has a mode called RSA/ECB/OAEPWithSHA-256AndMGF1Padding.

RFC3447, Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1, section 7.1.2 Decryption operation says Hash and MGF are both options for RSAES-OAEP-DECRYPT. MGF is it's own function, defined in Section B.2.1 MGF1 and that has it's own Hash "option" as well.

Then:

OAEP uses a separate hash invocation to hash a (usually empty: NOTE: as in TMSCP) label as well as a parameter to MGF1 (mask generation function), used for most of the OAEP padding.

Then:

"I was playing around with the BouncyCastle crypto provider and BouncyCastle appears to operate differently with regard to RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING. ie. while Java's default crypto provider uses sha1 as the MGF hash bouncycastle appears to use sha256."

Then:

"I just verified this, sun.security.rsa.RSAPadding when used with OAEP SHA256, uses SHA1 for the MGF1 function, bouncy castle uses SHA256 for both, that's why they are not compatible."

This begs the following question: what Java library are you using? It may be that MGF1 hash function is not the same as in TMS CP.

A third party does the Java encryption and they are using Sun library. Does this mean I won't be able to decrypt with TMS CP?

I don't know yet as I need to understand what parameters they are using.
It looks like "sun.security.rsa.RSAPadding when used with OAEP SHA256, uses SHA1 for the MGF1 function".
I need to check the SHA256/SHA1 combo in this case.

You can see the Java code in the first message I sent, the Label is not set nor is the provider set to "BC", so it should be the default Sun library.

The issue was that the same hash function is used for 2 different operations, like in Bouncy Castle, but unlike in the Sun library.
I fixed it with the addition of a new property in the RSA class (MGFhash).
It works and I could decrypt the base64 string. I sent you the hex value by email.

The code will be uploaded soon as TMS CP 5.0.9.1.

Also, RSA.unicode needs to set to noUni as we are decrypting.

The code looks like this

procedure TForm1.Button1Click(Sender: TObject);
var
  lRSA : TRSAEncSign;
  lText : String;
begin
  lRSA := TRSAEncSign.Create;
  lRSA.hashFunction := sha256; // not needed but to show the difference with MGFhash
  lRSA.MGFhash      := sha1;
  lRSA.Unicode      := noUni; // required here as we decrypt some 'raw' string of bytes
  try
    lText := Convert1.Base64ToHexa(Memo1.Text);
    lText := Convert1.FormatToChar(lText);
    lRSA.FromPrivateKeyFile('jerometestprivate.key'); // a PKCS#8 base64 blob
    lRSA.inputFormat := raw;
    lText := lRSA.Decrypt(lText);
    Memo2.Text := lText;
  finally
    lRSA.Free;
  end;
end;

That is great news, I can confirm a match.
Thank you Bernard I appreciate your assistance and persistance in this matter.

Just a question: Would this go for encryption as well, we need to use the same algorithm and padding in Delphi to encrypt so the Java side can decrypt?

Thank you again, this is awesome

Great!

It works both ways. You just need to make sure all parameters are identical in Delphi and Java:

  • key pair (one key for encryption, the other for decryption)
  • hash functions: the one to hash the content, the other for the mask generation (the MGF)
  • the label: in most implementations the label is set to 'empty', but I just added a new property (OAEPlabel) to cover the case where someone would like to add a label (max 20 bytes as in the standard); it works fine
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.