I see that lots of people find my question too long (because there is lots to explain), read the first sentence and then just think that I'm going on the worst tangent possible without seeing the entire question. If the question isn't clear enough please let me know. I'm trying to condense it in the simplest way and not to cause any confusion.
The reason for the public key decryption is to achieve a form of digital signing where the recipient decrypts the encrypted content to reveal a hash value. I didn't see the need to mention this in the question as I wanted to find out how to perform this operation in its basic form. However to avoid any further concerns and warnings around what RSA is all about and that public key decryption is bad, I updated my question with that disclaimer.
I have written a C# application that uses the Chilkat's RSA library to take content and encrypt it using a personal Private Key.
Then I would like to use a public website to allow someone to decrypt that very content (that's encrypted) by using an associated public key.
Now, I found a 3rd party website (and there are not a lot of them, BTW) that allows you to decrypt content using a RSA public key (https://www.devglan.com/online-tools/rsa-encryption-decryption).
Unfortunately when I try to use it, I get a "Decrypt error".
Here is a sample setup. I have generated my own personal Public & Private Key pairs. In my C# application, I'm taking a string and encrypting it with a private key and encoding it using Base64.
const string originalContent = "This !s original c0nt3nt";
var rsa = new Chilkat.Rsa();
rsa.GenerateKey(2048);
var encryptedBytes = rsa.EncryptBytes(Encoding.UTF8.GetBytes(originalContent), true);
var encryptedEncodedString = Convert.ToBase64String(encryptedBytes);
Console.WriteLine($"Encrypted:{Environment.NewLine}{encryptedEncodedString}");
Console.WriteLine();
var privateKeyBytes = rsa.ExportPrivateKeyObj().GetPkcs8();
var privateKeyEncodedString = Convert.ToBase64String(privateKeyBytes);
Console.WriteLine($"Private Key:{Environment.NewLine}{privateKeyEncodedString}");
Console.WriteLine();
var publicKeyBytes = rsa.ExportPublicKeyObj().GetDer(false);
var publicKeyEncodedString = Convert.ToBase64String(publicKeyBytes);
Console.WriteLine($"Public Key:{Environment.NewLine}{publicKeyEncodedString}");
Console.WriteLine();
var decyptedContentBytes = rsa.DecryptBytes(encryptedBytes, false);
var decryptedContentString = Encoding.UTF8.GetString(decyptedContentBytes);
Console.WriteLine($"Decrypted:{Environment.NewLine}{decryptedContentString}");
Console.WriteLine();
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
This sample console app will write out all the necessary information needed to use for the next part of the process and to demonstrate that in principle it works as expected.
Here are the sample values from the console window:
ENCRYPTED CONTENT
H5JTsGhune1n3WWSPjwVJuUwp70Hsh1Ojaa0NFCVyq0qMjVPMxnknexOG/+HZDrIYsZM7EnPulpmihJk4QyLM8T2KNQIhbWuMHvzgHYlcPJdXpGZhAxwfklL4HP0iRUUXJBsJcS/2XoUDZ6elUoMIFY9cDB4O+WFxKS/5vzLEukTLbQ3aEBNg3xaf9fg12F8LcMxZ3GDsk0W9b6oJci09NTxXd6KKes0RM1hnOhw6bu0U33ZLF3sa0nH9Kdf8w23PoKc/tl12Jsa8N1A4OjaT5910UF8FRH6OkAbNKnxqXcL7+V4HVuHchi3ghuFivAW57boLeHr7OG7wOEC/gfPOw==
PRIVATE KEY
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8xYcNXckXf1X4Kd6qE5c7pddfWdKo71mcwZWskuaq+wq3FTcCTAedo/Vcx8Vxn+RMn5XE7QCDzcAAN0K/BzQsoU81myRzZ+bKP+TJ5HH0jClCUMj+ideEm0fay873jnbG0hKEOJPVxPWwKq3jvDLLmWrdgvd/UiDStDm286SFKfMlLWkSw8YIc5nXsthAgP0hv8Nj7UDKvTEG5o3boTuhG1JQARCEXP0fTdIiv0cEFlSN3KkgF4KDf32Vt2x57N/+PJXpQvcECkLwPpBAq/aM0qbtgeiILxavfBJRwQ5zXDUmZHepvSjK6KIYQsTavQQLDXnFKuXa2fxOJHIlys6pAgMBAAECggEBAI0ZMBtDkL2phj7aPP7vaclB6rvwzc9MKLVM1W2K2DPRNW8nwlhLMB4aoZnaELEfjGvhlPb/F7VtIyiGJbPX1J3PbP9qmVJRxWZDX+WwhaT+5xAUhkgMDDWoQ4s9b9QGfq2Z9BE0oPvWHraxEAz7bRRV9lTgQdK/Np2H7OPdNYn6SW8qVgAukgTBqVno4VDbC34bJwal0e63oBFFfensWlhPtDUQB/uQX7UiRfEkxL+CNuqVLDoAeXWmSVWOPlDTKVu1y1bzfA+WMOKHm1ndq21I07TUPf9FcgYdKf4yKpWvMfVeDev6Oo/2mlac+vrJO571S+h4a5m79jUhCeJwX4kCgYEA7q5hrNtMbErA6dgEOG+KpFTaeqbknwtcykVApEvHt4LKULedAvwkORu65acKFYkxbMt19Fx7ligGxg0yOQRWX1BXK1XOCo9eYOjvOVlbRqBywLIbegehoZQ0LoSsdRcOvFq7EbMV3BaxCmxgpnrCZ75VaCYUMzylIduPWKeT9xcCgYEAyngNIIgsXfpCI+HHILNpprFfS2JBBGPx8N/d9cXahKCJhxrMe8K64CSMyxTwum5DXjJnbE4QBsoowRZTCEF6JUBagRM/pQrVX/CK//oyUUaa5+1S/0OxlUevXR7TD6gcpGNEdPjruc+gZzhfKFuWh+V9mJQUviqm3RjAcEdHAD8CgYBL0kOfGM8vO5QK9R9qGiztxTLecbQAvihM7TD6wEQCjN7eQ2Xyc8zCA4gcujKe4sU7rWqcJODxs2drdPe2WyVhA/GdB5X7js3JdVXBXxx61C9//VRzMIds/9qPyH/MdnWs6hmxJrXUA7Vb/U+6sxacxD73ZdlW6XX/ynLAFAQSIwKBgQCk4i12j87p3ZMdW5HprJJeoNYFMwfVxnrSec1tiGoTVhWJxCZAp22+eaV7ARumB4OvY4bcKZpdnSahUEfgUkphqc3Kjd1nz7HCxsa7/YoarFAcjiXoIb2t30oNoLurZXGl4f1u8QQvNsnfJYZA/I1TMG4e4oEd+OgY6D5XcYR9ywKBgGdaZmoBieiw0NkbijjgQZ0WILDmrIYdsSp4HMp6XDeVvdMb/qYg2jTnvVyqMSb8NdfCOB0GT19r1isQX9RnUgxPikJbVLj8WjAQjHT28mtmRn+Ju/3KT75RJ/LHY3SySNMOgTW75X2u8v0ELdEiiOmc/vTkCYoS/oqp92ELjT1Y
PUBLIC KEY
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMWHDV3JF39V+CneqhOXO6XXX1nSqO9ZnMGVrJLmqvsKtxU3AkwHnaP1XMfFcZ/kTJ+VxO0Ag83AADdCvwc0LKFPNZskc2fmyj/kyeRx9IwpQlDI/onXhJtH2svO9452xtIShDiT1cT1sCqt47wyy5lq3YL3f1Ig0rQ5tvOkhSnzJS1pEsPGCHOZ17LYQID9Ib/DY+1Ayr0xBuaN26E7oRtSUAEQhFz9H03SIr9HBBZUjdypIBeCg399lbdseezf/jyV6UL3BApC8D6QQKv2jNKm7YHoiC8Wr3wSUcEOc1w1JmR3qb0oyuiiGELE2r0ECw15xSrl2tn8TiRyJcrOqQIDAQAB
Now, when I go to the website (mentioned above) I paste in my encrypted content in the encrypted content text block and I paste my public key that I generated in the text block underneath it and set the RSA Key Type to Public Key
. But it fails.
But...
I have done some troubleshooting by taking my personal Private & Public keys that I generated and I use the website to perform the encryption & decryption with my keys and I'm able to encrypt my string and decrypt that encrypted content successfully which leads me to believe that somehow my Chilkat encryption setup is not fully aligned with the one that the website uses.
So I started reading what the website had to offer and the author of the page posted an explanation on how to accomplish this (https://www.devglan.com/java8/rsa-encryption-decryption-java) which uses the Java RSA libraries under the hood. Apparently, there are two Java RSA ciphers that can be used "RSA" and "RSA/ECB/PKCS1Padding".
I am not so familiar with the Java libs and I know enough of cryptography to know how to get things done but there are lots of technical aspects that are still unclear to me as to help me figure out where to go next.
My question is, is there anything in Chilkat that I need to setup so that it can encrypt content that would allow a Java application (like the website link posted above) to be able to decrypt? (of course Chilkat needs to be able to decrypt it as well)
A message that has been encrypted with the private key using the Chilkat-library cannot be decrypted with the public key using Java (at least not with the standard SunJCE-provider) or the java-based web-site, since different padding variants are used on both sides.
The prerequisite for a successful decryption is that both encryption and decryption use the same padding variant. The same applies to signing and verification.
There are two variants of the PKCS1-v1.5-padding described in RFC8017: One is RSAES-PKCS1-v1_5, which is used in the context of encryption and decryption, and the other is RSASSA-PKCS1-v1_5, which is used in the context of signing and verifying. RSAES-PKCS1-v1_5 is non-deterministic, i.e. repeated encryption of the same plaintext with the same key always generates different ciphertexts. RSASSA-PKCS1-v1_5 is deterministic, that is, it always generates the same ciphertext under the mentioned conditions.
Since the padding variant depends on the respective platform/library, a general statement is not possible. However, for the Chilkat-library and Java (standard SunJCE provider) the following applies (PKCS1-v1.5-padding assumed):
The methods that Chilkat provides in the context of encryption/decryption use RSAES-PKCS1-v1_5 regardless of whether the public or private key is used for encryption. Analog methods also exist in the context of signing/verifying. These use RSASSA-PKCS1-v1_5.
To check this, the padding variant can be determined by setting the Chilkat.Rsa#NoUnpad
flag to true
, so that the padding is not removed during decryption. Another option for a test is to repeatedly encrypt the same plaintext with the same key. Since RSAES-PKCS1-v1_5 is probabilistic, different ciphertexts are generated each time.
In Java, the Cipher
-class determines which padding variant is used based on the mode (encryption or decryption) and the key type used (private or public). For encryption with the public key and decryption with the private key, RSAES-PKCS1-v1_5 is used. For encryption with the private key and decryption with the public key, RSASSA-PKCS1-v1_5 is used. For signing/verifying, Java provides the Signature
-class which uses RSASSA-PKCS1-v1_5.
To check this, proceed as described above. In Java, you can prevent the padding from being removed with RSA/ECB/NoPadding
during decryption.
Since in the context of encryption/decryption the public key is used for encryption and the private key is used for decryption, and dedicated classes or methods are used in the context of signing/verifying, there are no or few use cases for direct encryption with the private key and decryption with the public key. Furthermore or maybe because of that these processes are not uniformly implemented in the libraries as you can see in the example of the Chilkat-library and Java.
Altogether three cases can be distinguished for the Chilkat-library and Java:
After this explanation now to your question: My question is, is there anything in Chilkat that I need to setup so that it can encrypt content that would allow a Java application (like the website link posted above) to be able to decrypt? Since the Java-code uses RSASSA-PKCS1-v1_5 for decryption with a public key, it would be necessary for compatibility to change the padding variant in the Chilkat-code from RSAES-PKCS1-v1_5 to RSASSA-PKCS1-v1_5 in the context of encryption/decryption. If you look at Chilkat's RSA-methods, it seems that this is not intended, but that the logic for determining the padding variant is hard coded (as probably with most libraries). You can only choose between PKCS1-v1.5-padding and OAEP for padding. This means that a message encrypted with the private key using the Chilkat-code cannot be decrypted with the public key in Java or on the website.
What are the alternatives? According to the question, the goal is: The reason for the public key decryption is to achieve a form of digital signing where the recipient decrypts the encrypted content to reveal a hash value.
signBytes
. The hash of the data is created automatically and RSASSA-PKCS1-v1_5 is used as padding variant (if the data are already hashed, the method signHash
can be used). On the Java-side, this signature can be verified. Alternatively, the signature can be decrypted with the public key, which allows the hash value to be determined, since Java uses the padding variant RSASSA-PKCS1-v1_5 in both cases. Decryption is also possible on the web site, but the decrypted data are not displayed properly because they are only given as a string (which does not produce any meaningful output because of the arbitrary byte-sequences in a hash) and the encoding cannot be changed to hexadecimal or Base64.