How to import keys with TWebRSAEncryption using ImportKeyP ?

Hello together,

the generation and the export of the rsa key pair works fine,
but I don't know how to reimport the exported keys.
So I tried several combinations, but always raises an exception :frowning:

Best Regards
Martin

procedure TForm1.GenerateAndImport;
var
  rsaenc: TWebRSAEncryption;
  rsaenc2: TWebRSAEncryption;
  pubkey: String;
  privkey: String;
  rb: Boolean;
begin
  //### Generate and export a KeyPair ###
  rsaenc := TWebRSAEncryption.Create(rml2048, ehSHA256, True, [kuEncrypt, kuDecrypt]);
  try
    rb := Await(Boolean, rsaenc.GenerateKeyP);
    // rb alway True? (see Webcore documentation)
    pubkey := Await(String, rsaenc.ExportKeyP(aktPublic, efJSON));
    privkey := Await(String, rsaenc.ExportKeyP(aktPrivate, efJSON));
    ShowMessage(pubkey);
    ShowMessage(privkey);
  except
    ShowMessage('GenerateKey failed!')
  end;

  //### Import a PublicKey or a KeyPair ###
  rsaenc2 := TWebRSAEncryption.Create(rml2048, ehSHA256, True, [kuEncrypt, kuDecrypt]);
  try
    rb := Await(Boolean, rsaenc2.ImportKeyP(privkey, aktPrivate, efJSON));
    rb := Await(Boolean, rsaenc2.ImportKeyP(pubkey, aktPublic, efJSON));
  except
    ShowMessage('ImportKey failed!')
  end;
end;

Hi,

What you define as [kuEncrypt, kuDecrypt] is equivalent to the keyUsages in the importKey call. Then the import fails beause keyUsages (= [encrypt, decrypt]) will not be a subset of [decrypt] when importing the private key (and after it won't be a subset of [encrypt] when importing the public key).

We'll look to improve this. In the meantime you can use this as a workaround:

rsaenc2 := TWebRSAEncryption.Create(rml2048, ehSHA256, True, [kuDecrypt]);
try
  rb := Await(Boolean, rsaenc2.ImportKeyP(privkey, aktPrivate, efJSON));
  rsaenc2.Usages := [kuEncrypt];
  rb := Await(Boolean, rsaenc2.ImportKeyP(pubkey, aktPublic, efJSON));
  rsaenc2.Usages := [kuDecrypt, kuEncrypt];
except
  ShowMessage('ImportKey failed!')
end;

Oh thanks, that works! Encoding and Decoding works so far with the original generated keys. When importing the exported keys, it doesn't work. Any idea? But I'll test it again :slight_smile:

What do you mean exactly by "it doesn't work"?

The following encrypts "hello world", decrypts it, exports the keys, imports the keys and finally decrypts the original encrypted array buffer again which still results in "hello world":

procedure TForm1.WebButton1Click(Sender: TObject);
var
  ab: TJSArrayBuffer;
  pubkey, privkey: string;
begin
  //Encrypt
  ab := Await(TJSArrayBuffer, rsaenc.EncryptP('hello world'));
  WebLabel1.Caption := Await(string, rsaenc.DecryptP(ab, drtString));

  //Export the keys
  try
    pubkey := Await(String, rsaenc.ExportKeyP(aktPublic, efJSON));
    privkey := Await(String, rsaenc.ExportKeyP(aktPrivate, efJSON));
  except
    ShowMessage('ExportKey failed');
  end;

  //Import the keys
  rsaenc2 := TWebRSAEncryption.Create(rml2048, ehSHA256, True, [kuDecrypt]);
  try
    Await(Boolean, rsaenc2.ImportKeyP(privkey, aktPrivate, efJSON));
    rsaenc2.Usages := [kuEncrypt];
    Await(Boolean, rsaenc2.ImportKeyP(pubkey, aktPublic, efJSON));
    rsaenc2.Usages := [kuDecrypt, kuEncrypt];
  except
    ShowMessage('ImportKey failed!')
  end;

  //Decrypt ab with imported key
  WebLabel2.Caption := Await(string, rsaenc2.DecryptP(ab, drtString));
end;

procedure TForm1.WebFormCreate(Sender: TObject);
begin
  rsaenc := TWebRSAEncryption.Create(rml2048, ehSHA256, True, [kuEncrypt, kuDecrypt]);
  try
    Await(Boolean, rsaenc.GenerateKeyP);
  except
    ShowMessage('GenerateKey failed!')
  end;
end;

Before button click:
image
After button click:
image
What are you doing differently?

Hi, as additional stepp, I've converted the TJSArrayBuffer into a HEX-String and vice versa. And sometimes decoding works, and sometimes it doesn't. But I'll put a demo-project together, and then we can see further.

Hello, here comes the little demo project with a screen capture to show the problem.
While testing, I can't reproduce the problem on the Google Chrome Browser, but on
Firefox Version 97.0.1 as you can see in the video.

The mp4-video you can find under: http://www.spechto.de/tms/rsaenc.mp4

WebRSAEncryption.zip (8.0 KB)

Hi,

We are unable to reproduce what is in the video even on Firefox 97.0.1.
Can you remove the try..except blocks for testing purposes to see with what error the promise is rejected? You'll see the output in the developer tools' console tab.

The MDN documentation is not really helpful, it seems like this can mean anything.

You could try to first eliminate the HEX conversion and see if it still reproduces the error. Save the encoded/decoded result into a variable and use that instead of relying on AB2HEX and HEX2AB. If it works without HEX conversion, the problem might be with the HEX2AB function.

HEX conversion is eliminated, but the error is reproduceable. It looks like that the exception raises in the Decrypt-Method of TWebRSAEncryption. It's the same when try to decode a Buffer coded with another key. :thinking: ???

TWebRSAEncryption is nothing more than a wrapper around the WebCrypto API. TWebRSAEncryption.Decrypt is calling window.crypto.subtle.decrypt() with the appropriate parameters so window.crypto.subtle.decrypt() is where the exception comes.

It's unclear why it fails on your Firefox installation but works here. The ideal way to solve this would be to check if it's really a browser issue by writing a sample in pure HTML + JS and test it under your Firefox.

It's a long shot but you could also try to clear your cache first and see if it makes any difference.

Wouldn't that be a normal behavior? You should not be able to decode a buffer encoded with a different key.

This is correct, it's a normal behavior, when having a wrong encoded string.
I've tested with other Firefox versions and installations. The problem is reproduceable.
So here is a link to a compiled version: https://www.martinspecht.de/tms/WebRSAEncryption.html
It is the version with "try ... except" and HEX2AB / AB2HEX.
Sometimes you can do this: When having an encoded string, import the keys, then decode (works) and encode (works) and the decode again (exception). This makes me crazy :slight_smile:
By the way: Chrome and Edge don't have any problems ... only Firefox. I'll tested Firefox on Android too and the behaviour is the same (there are exceptions). Chrome on Android: no Problems

This is very strange, we still cannot reproduce this here even with your compiled version.
We tested both on Windows 10 x64 and Android 11. What are you testing on?

Here's a separate HTML file with the same but minimal functionality as your application. Please try this in Firefox and see if it fails.
index.html (3.3 KB)