0
votes

I have the following working asymetric encryption implementation:

private static RSAParameters privateKey;
private static RSAParameters publicKey;

private static void RSA()
{
  var rsa = new RSACryptoServiceProvider();
  privateKey = rsa.ExportParameters(true);
  publicKey = rsa.ExportParameters(false);

  byte[] originalMessage = GenerateRandomData();
  byte[] encryptedMessage = Using(publicKey).Encrypt(originalMessage, false);
  byte[] decryptedMessage = Using(privateKey).Decrypt(encryptedMessage, false);
  Debug.Assert(originalMessage.SequenceEqual(decryptedMessage));
}

private static RSACryptoServiceProvider Using(RSAParameters parameters)
{
  RSACryptoServiceProvider encryptor = new RSACryptoServiceProvider();
  encryptor.ImportParameters(parameters);
  return encryptor;
}

private static byte[] GenerateRandomData()
{
  Random rnd = new Random();
  byte[] originalData = new byte[10];
  rnd.NextBytes(originalData);
  return originalData;
}

I use this to encrypt data with the recipient's public key [Using(publicKey).Encrypt(originalData)] so that the receiver only can decrypt the data [Using(privateKey).Decrypt(encryptedData)].

Now I want to reuse asymetric encryption for the following use case: The recipient publishes data and everyone who knows the recipient's public key (which is basically everyone in the system, but nobody outside the system e.g. a protection against leaking readable data to the public) can read it. The publisher uses his private key to encrypt and his public key would be used to decrypt:

byte[] originalData = GenerateRandomData();
byte[] publishedData = Using(privateKey).Encrypt(originalData, false);
byte[] retrievedData = Using(publicKey).Decrypt(publishedData, false);
Debug.Assert(originalData.SequenceEqual(retrievedData));

However this yields a

System.Security.Cryptography.CryptographicException
  HResult=0x8009000D
  Message=Keyset does not exist.

I do not want to use a different public-private-key-pair for data publishing part, especially in this scenario it means making public a private key. It already sound awkward when typing...

EDIT: Is there an asymetric encryption contained in .NET framework which allows me to use both keys (public and private) in both directions where if one key is used for encryption only the other one can be used to decrypt?

1
RSA signing is not decryption. For encryption, you should use proper padding as PKCS#1.5 or OAEP. For signing you should use RSA-PSS. Normally we don't advice to encrypt messages with RSA, the message space will be short and you may need multiple encryptions that will make your application very slow. RSA can be used for key exchange like RSA-KEM. After that you can encrypt with AES. A nice library, actually, is the sealed boxes if you can find a C# library.kelalaka
The Bouncycastle C# library has an RSAEngine class that will let you do this.President James K. Polk
Do not be tempted to use a private key as the "public key" which you publish, and keep the public key "secret". Given a private key in practice, it is trivial to derive the public key from it.Jim Flood
@JimFlood It already sounded awkward when typing. I promise I won't. But thanks for confirming and pointing this out.David

1 Answers

1
votes

RSA signing is not the same as encrypting with the private key.

PKCS#1 v1.5 signature:

  • Hash the content with a chosen algorithm.
  • Create a DigestInfo value to represent the hash.
  • Apply padding to make a message almost, but not quite, the size of the modulus (details omitted here).
  • Apply the RSA primitive with the private key

Note that last step doesn’t say “encrypt”.

The RSA classes in .NET do the padding and such for you, so they expose Sign/Verify and Encrypt/Decrypt. You can’t use them for cross purposes, and you can’t use these classes for the RSA primitive (aka “raw RSA”).