TRSAEncSign.Verify still buggy in last version?

Hi,

I upgraded to latest version, RSAOBj.pas Version 1.4.8 last modified: 16 November 2025.

I still get "Invalid Operation : -316" in Verify method.

Here is a very simple code to reproduce:

in uses, add
CryptoConst, MiscObj, RSAObj, RSACore;

Then drop a button and assign this code:

procedure TForm1.Button6Click(Sender: TObject);
var
 rsa: TRSAEncSign;
 RSASig: String;

begin
 rsa = TRSAEncSign.Create(self);
 rsa.KeyLength:= kl2048;
 rsa.InputFormat:= raw; // default
 rsa.OutputFormat:= base64;
 rsa.GenerateKeys;
 rsa.Unicode := yesUni;
 rsa.hashFunction := sha256;
 rsa.signType := pss;
 edit1.Text := rsa.Sign('test');
 if RSA.Verify('test', edit1.text) <> 0 then Caption := 'INVALID SIGNATURE';
 rsa.Free;
end;

Clicking the button will cause error -316...

Using latest Delphi 13 with all updates, platform: Windows 64-bit.
On Windows 11.

What could be wrong?

Thank you!

Hi, you need to convert the signature to 'raw' before verifying it, as you selected 'base64' for the output with 'raw' as input'.

Selecting a format doesn't convert the value, it just tells the algorithm that it needs to convert data.

Add a TConvert:

var
  conv: TConvert;
  s: string;
conv := TConvert.Create(base64);
...
s := conv.FormatToChar(edit1.text);
if RSA.Verify('test', s) <> 0 then Caption := 'INVALID SIGNATURE';

You can also check the VCL demo from line 2040 to 2120.

Thank you for your answer. It makes sense, though

, if I change rsa.InputFormat:= base64, would it work without conv: TConvert ?

And suppose I want to set the keys without GenerateKeys and these keys are in hex.
Assigning them like this code doesn't work;

RSA.Modulus := 'B4C8691DB3F40D30CB5CB3D398A2DXXXXX';
RSA.PublicExponent := '00000000000000000000000000XXXX';
RSA.PrivateExponent := 'XXXXXX';
RSA.inputFormat := hexa;

What would be the proper way to do it?

if I change rsa.InputFormat:= base64, would it work without conv: TConvert

If the input string is in base64, it will be converted to 'raw' within the RSA class.

  if InputFormat <> raw then // RSAObj, line 559
    m := conv.FormatToChar(m);

Keys are currently accepted in 'raw' format. However, you can do this:

var
  conv: TConvert;

begin
  conv := TConvert.Create(hexa);

  RSA.Modulus := conv.ToCharString('B4C8691DB3F40D30CB5CB3D398A2DXXXXX');
  RSA.PublicExponent := conv.FormatToChar('00000000000000000000000000010001');
  RSA.PrivateExponent := conv.FormatToChar('XXXXXX');
  ...

Note that because conv.AType := 'hexa', FormatToChar and ToCharString are identical here.

1 Like

Thanks, but with

RSA.Modulus := conv.ToCharString('B4C8691DB3F40D30CB5CB3D398A2DXXXXX');

I now get this:

Modulus length incorrect, must be 512.

Logical. Try this.

var
  conv: TConvert;
  sig: string;

begin
  conv := TConvert.Create(hexa);

  rsa = TRSAEncSign.Create(self);
  rsa.KeyLength:= kl2048;
  rsa.InputFormat:= raw; // to load the keys
  rsa.OutputFormat:= base64;

  rsa.Modulus := conv.FormatToChar('B4C8691DB3F40D30CB5CB3D398A2DXXXXX');
  rsa.PublicExponent := conv.FormatToChar('00000000000000000000000000010001');
  rsa.PrivateExponent := conv.FormatToChar('XXXXXX');

   rsa.InputFormat:= base64; // switch format for input
   sig := rsa.sign(aBase64Input); // should generate a base64 signature from a base64 input 

  ...

Hi Bernard,

Thank you but I still get Modulus length incorrect, must be 512. :frowning:

RSA:= TRSAEncSign.Create(self);
RSA.Unicode := yesUni;
rsa.KeyLength:= kl2048;

conv := TConvert.Create(hexa);
RSA.Modulus := conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5');

RSA.PublicExponent := conv.FormatToChar('0000080000000000040000080000000000000000000000001000004000000229');
RSA.PrivateExponent := conv.FormatToChar('53D76497A22E3104BB6711ED0EF583012DCE7001209384D817BFF55A6E04F1A2A8643C0F71504A7A0C09388BA58464D9DE027CA31252E38B388BBA2DF514C5035CC74EFC69F78E165A180554808612F486B68F5934F1D2B477C7ED216EF297A23AD5EFF3F0B3677645B8616F020542DC7C924CF2C35E86321B3FB02861902EF488840B61FB561D2B230F8D96BFF5F8F210AEC7822EFFD21128555F0235DAB1DD658D59F8834FE4B5DAA18969795D27FF02798DD51F4BFDA46826CE8216C638780366B537EF5564BD95E15C19F65ED8688EF4E49D982B6E5DEE3F57E39167B8A19B7EC6021D528E4BAB93698CF0B640E3D3D19776F65EA8FF3D76DF0BCFFFF131');

RSA.inputFormat := raw;
RSA.outputFormat := base64;

Edit1.Text := RSA.Sign('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA='); // Signe les données

 if RSA.Verify('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=', Edit1.Text) <> 0 then  Caption := 'INVALID SIGNATURE';
 RSA.Free;
 Conv.Free;

The values above were generated with your CryptoDemo.

Hi,
That's normal because

RSA.inputFormat := raw;

needs to be placed BEFORE

RSA.Modulus := conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5');

and then

 rsa.InputFormat:= base64; // switch format for input

needs to be placed BEFORE

Edit1.Text := RSA.Sign('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA='); // Signe les données

Here is a revised version.

RSA:= TRSAEncSign.Create(self);
RSA.Unicode := yesUni;
rsa.KeyLength:= kl2048;

conv := TConvert.Create(hexa);
RSA.inputFormat := raw;
RSA.Modulus := conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5');

RSA.PublicExponent := conv.FormatToChar('0000080000000000040000080000000000000000000000001000004000000229');
RSA.PrivateExponent := conv.FormatToChar('53D76497A22E3104BB6711ED0EF583012DCE7001209384D817BFF55A6E04F1A2A8643C0F71504A7A0C09388BA58464D9DE027CA31252E38B388BBA2DF514C5035CC74EFC69F78E165A180554808612F486B68F5934F1D2B477C7ED216EF297A23AD5EFF3F0B3677645B8616F020542DC7C924CF2C35E86321B3FB02861902EF488840B61FB561D2B230F8D96BFF5F8F210AEC7822EFFD21128555F0235DAB1DD658D59F8834FE4B5DAA18969795D27FF02798DD51F4BFDA46826CE8216C638780366B537EF5564BD95E15C19F65ED8688EF4E49D982B6E5DEE3F57E39167B8A19B7EC6021D528E4BAB93698CF0B640E3D3D19776F65EA8FF3D76DF0BCFFFF131');

RSA.inputFormat := base64;
RSA.outputFormat := base64;

Edit1.Text := RSA.Sign('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=');

 if RSA.Verify('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=', Edit1.Text) <> 0 then  Caption := 'INVALID SIGNATURE';
 RSA.Free;
 Conv.Free;

Hi Bernard,

I thought it would make it finally, but with your last code, the exception is back.

Invalid Operation : -316.

This time, the error occurs on RSA.Verify()

I just copied/pasted the code you wrote. Any further idea?

Thank you!

Looks like there is a regression. I am investigating it.

1 Like

OK, the good news is that the RSA algorithm is fine.
This code works for me (reverse the byte ordre for each 'key'):

...
conv := TConvert.Create(hexa);
RSA.inputFormat := raw;
RSA.Modulus := conv.reverse(conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5'));

RSA.PublicExponent := conv.reverse(conv.FormatToChar('0000080000000000040000080000000000000000000000001000004000000229'));
RSA.PrivateExponent := conv.reverse(conv.FormatToChar('53D76497A22E3104BB6711ED0EF583012DCE7001209384D817BFF55A6E04F1A2A8643C0F71504A7A0C09388BA58464D9DE027CA31252E38B388BBA2DF514C5035CC74EFC69F78E165A180554808612F486B68F5934F1D2B477C7ED216EF297A23AD5EFF3F0B3677645B8616F020542DC7C924CF2C35E86321B3FB02861902EF488840B61FB561D2B230F8D96BFF5F8F210AEC7822EFFD21128555F0235DAB1DD658D59F8834FE4B5DAA18969795D27FF02798DD51F4BFDA46826CE8216C638780366B537EF5564BD95E15C19F65ED8688EF4E49D982B6E5DEE3F57E39167B8A19B7EC6021D528E4BAB93698CF0B640E3D3D19776F65EA8FF3D76DF0BCFFFF131'));

RSA.inputFormat := base64;
RSA.outputFormat := base64;
...
1 Like

Thanks but still no luck. Same error.

procedure TForm1.Button6Click(Sender: TObject);
var
 RSA: TRSAEncSign;
 RSASig, S, msgRaw, sigRaw: String;
 conv: TConvert;
begin

RSA:= TRSAEncSign.Create(self);
RSA.Unicode := yesUni;
rsa.KeyLength:= kl2048;

conv := TConvert.Create(hexa);
RSA.inputFormat := raw;
RSA.Modulus := conv.reverse(conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5'));
RSA.PublicExponent := conv.reverse(conv.FormatToChar('0000080000000000040000080000000000000000000000001000004000000229'));
RSA.PrivateExponent := conv.reverse(conv.FormatToChar('53D76497A22E3104BB6711ED0EF583012DCE7001209384D817BFF55A6E04F1A2A8643C0F71504A7A0C09388BA58464D9DE027CA31252E38B388BBA2DF514C5035CC74EFC69F78E165A180554808612F486B68F5934F1D2B477C7ED216EF297A23AD5EFF3F0B3677645B8616F020542DC7C924CF2C35E86321B3FB02861902EF488840B61FB561D2B230F8D96BFF5F8F210AEC7822EFFD21128555F0235DAB1DD658D59F8834FE4B5DAA18969795D27FF02798DD51F4BFDA46826CE8216C638780366B537EF5564BD95E15C19F65ED8688EF4E49D982B6E5DEE3F57E39167B8A19B7EC6021D528E4BAB93698CF0B640E3D3D19776F65EA8FF3D76DF0BCFFFF131'));

RSA.inputFormat := base64;
RSA.outputFormat := base64;

Edit1.Text := RSA.Sign('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=');

S := edit1.Text;
if RSA.Verify('tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=',S) <> 0 then  Caption := 'INVALID SIGNATURE';

 RSA.Free;
 Conv.Free;

end;


Executing this code gives -316 error:

I took more time to study your conversion code in RSAObj and the one in the uCryptDemo.

I saw that you use the conversion to extract the bytes from the Modulus and PublicExponent strings.
If we always keep InputFormat as raw, then it finally works! :smiley:
Here is the code working for me:

procedure TForm1.Button6Click(Sender: TObject);
var
  RSA: TRSAEncSign;
  S, sigRaw: String;
  conv: TConvert;
  inputMsg: String;
begin
  RSA := TRSAEncSign.Create(self);
  conv := TConvert.Create(hexa);
  try
    RSA.Unicode := yesUni;
    RSA.KeyLength := kl2048;
    RSA.inputFormat := raw;
    RSA.Modulus := conv.reverse(conv.FormatToChar('C4B7179296918317F15BCD8703D172CCA1096177F418B6AED4C8F6B0B09619291A7A63C57EB17E9FEC577F2872F3AE603CA4BE332A63A1D51A17918AD604573BB0DC93A9B7BD1CFB06ACC3DB744EE71E2DC2C8F2440CC6499F92000375D92A1ABAF416A12A4A95B6DDAF331D1BF4986A460954C2D7A28D4E48237CBA373E14F574EDC1BC5E7B363C2623544E1BB14B43B44B23C1B0E22FC96CD486AC6EF8DCBB3795EC8AD0F521C891E516AAD3F771531EE32C3BBFEBD9C56EFC41334CE99B850249A2DBECCA7AE162060ED6F040B41C49A5E207033DFD507ED4A2895C796C0A70B6001867F28CC937A920D13D6050646DA2C47E06F63436F7645E473111B2F5'));
    RSA.PublicExponent := conv.reverse(conv.FormatToChar('0000080000000000040000080000000000000000000000001000004000000229'));
    RSA.PrivateExponent := conv.reverse(conv.FormatToChar('53D76497A22E3104BB6711ED0EF583012DCE7001209384D817BFF55A6E04F1A2A8643C0F71504A7A0C09388BA58464D9DE027CA31252E38B388BBA2DF514C5035CC74EFC69F78E165A180554808612F486B68F5934F1D2B477C7ED216EF297A23AD5EFF3F0B3677645B8616F020542DC7C924CF2C35E86321B3FB02861902EF488840B61FB561D2B230F8D96BFF5F8F210AEC7822EFFD21128555F0235DAB1DD658D59F8834FE4B5DAA18969795D27FF02798DD51F4BFDA46826CE8216C638780366B537EF5564BD95E15C19F65ED8688EF4E49D982B6E5DEE3F57E39167B8A19B7EC6021D528E4BAB93698CF0B640E3D3D19776F65EA8FF3D76DF0BCFFFF131'));

    inputMsg := 'tQj2+0SClRgYfWjs7yPd0LB2AwI9f5yx6XGGN0mTFEA=';

    RSA.inputFormat := raw;
    RSA.outputFormat := base64;

    S := RSA.Sign(inputMsg);
    Edit1.Text := S;

    conv.AType := base64;
    sigRaw := conv.FormatToChar(S);

    RSA.inputFormat := raw; // Must be raw here!!


    if RSA.Verify(inputMsg, sigRaw) <> 0 then
      Caption := 'INVALID SIGNATURE'
    else
      Caption := 'SIGNATURE VALID';

  finally
    RSA.Free;
    Conv.Free;
  end;
end;

Good news!

1 Like

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