I'm hoping somebody can help me with this one. I encrypt a simple string with the RSACryptoServiceProvider, export the RSAParameters and then Serialize the exported RSAParameters, together with the encrypted string, to a file using a BinaryFormatter.
Later I deserialize the whole lot, import the RSAParameters into a newly created RSACryptoServiceProvider, and try to decryp the string, but I keep on getting a 'Bad Key' exception.
What am I doing wrong here
I start with this piece of code:
Private Sub mnuToolsSecSettings_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolsSecSettings.Click Dim sec As SecuritySettings Dim pw As String Dim epw As String 'Create a Cipher package Dim cp As CipherPackage 'Check if the file, to which the package had previously been serialized, exists If IO.File.Exists(QualifyPath(Application.UserAppDataPath) & DataFileName & ".bin") Then 'If it does, deserialize it cp = CipherStorage.LoadCipherPackage() If Not (cp Is Nothing) Then'If the password had previously been encrypted, the exception happens here sec = New SecuritySettings(pw) Else 'Create a new password window, displaying NO old passwordsec = New SecuritySettings End If Else 'Create a new password window, displaying NO old passwordsec = New SecuritySettings End If 'Show the password dialog box If sec.ShowDialog(Me) = DialogResult.OK Then 'Get the new passwordpw = sec.txtNewPassword1.Text 'Encrypt the passwordcp = CipherEngine.EncryptString(pw) 'Serialize the password and RSAParameters to fileCipherStorage.SaveCipherPackage(cp) End Ifsec.Dispose() sec = Nothingcp = Nothing End Sub |
and this is the rest of the code:
Imports System.Runtime.Serialization.FormattersImports System.Security.CryptographyImports System.IOImports System.Text<Serializable()> _ Class CipherPackagePublic cipherBytes() As Byte ' RC2 encrypted message text Public params As RSAParameters End Class 'CipherPackageClass CipherEnginePublic Shared Function EncryptString(ByVal str As String) As CipherPackage ' Convert string to a byte array Dim package As New CipherPackage Dim plainBytes As Byte() = Encoding.ASCII.GetBytes(str) ' Encrypt the Text Message using RSA Dim rsa As New RSACryptoServiceProvider package.params = rsa.ExportParameters( True)package.cipherBytes = rsa.Encrypt(plainBytes, False)rsa.Clear() rsa = Nothing Return package End Function 'EncryptMessage Public Shared Function DecryptString(ByVal package As CipherPackage) As String Dim result As String = String.Empty If Not (package Is Nothing) Then Dim rsa As New RSACryptoServiceProviderrsa.ImportParameters(package.params) Dim decrypt_result() As Byte = rsa.Decrypt(package.cipherBytes, False)result = Encoding.ASCII.GetString(decrypt_result) rsa.Clear() rsa = Nothing End If Return result End Function 'DecryptMessageEnd Class 'PersonClass CipherStoragePublic Shared Sub SaveCipherPackage(ByVal package As CipherPackage) Try Dim fs As New IO.FileStream(QualifyPath(Application.UserAppDataPath) & DataFileName & ".bin", IO.FileMode.Create) Dim formatter As New Binary.BinaryFormatter formatter.Serialize(fs, package) formatter = Nothingfs.Close() fs = Nothing Catch e As ExceptionConsole.WriteLine(e.Message) End Try End Sub Public Shared Function LoadCipherPackage() As CipherPackage Dim result As CipherPackage Try Dim fs As New IO.FileStream(QualifyPath(Application.UserAppDataPath) & DataFileName & ".bin", IO.FileMode.Open) Dim formatter As New Binary.BinaryFormatterresult = CType(formatter.Deserialize(fs), CipherPackage)formatter = Nothingfs.Close() fs = Nothing Catch e As ExceptionConsole.WriteLine(e.Message) End Try Return result End Function |
Any help would be appreciated!
Charl

RSACryptoServiceProvider & Bad Key Exception
JHW
HI All,
I have to use RSA and im using it...............
Im also facing the same problem
!!!!!!!!!!!!!!!!!!!
could you provide me with a solution to the same problem which you faced
Mikey Stevey
Hello,
If the string to be encrypted is only going to be decrypted on the same machine, I recommend using the ProtectedData class. When you use ProtectedData, the current account or machine information is used to encrypt/decrypt the data, so you don’t have to worry about storing a key. It’s much easier to use for people who are new to cryptography. Also, Microsoft doesn’t recommend storing your private keys in a plaintext file.
Stephen< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Edward Stephen
I suppose I should have mentioned that I'm using .NET 1.1, but I'll keep that in mind as I'm planning to migrate as soon as VS 2005 is released.
Charl
Roger Haight MSFT
Hi Charl,
If you take a look at the RSAParameters structure, you'll notice that although it is marked Serializable, when it is serialized only the Exponent and Modulus (the public part of the key) get written out -- the other portions (P, Q, DP, DQ, InverseQ, and D -- the private part of the key) are not serialized. In your case you'll probably want to use the ToXmlString and FromXmlString methods, which will allow you to save and restore the entire key.
Is there any reason you've chosen RSA Generally we recommend that encryption be done with a symmetric algorithm, and that only the symmetric key be encrypted with an asymmetric algorithm such as RSA. Since symmetric encryption is much faster you'll see a perf gain, and you'll also increase the amount of data you can encrypt. (RSA will only encrypt the same number of bytes as it's key length - padding. So you're likely to have somewhere around a 120 byte maximum here).
A few other comments from looking at this code. CipherBytes is commented as being the RC2 encrypted value. However, you're using RSA not RC2 -- you'll need to use the RC2CryptoServiceProvider class for that. Also, you probably want to use Encoding.Default rather than Encoding.ASCII. ASCII encoding is limited to 7 bits, so any input which is greater than 128 will be corrupted by this transform. UTF8 will use all 8 bits, but not every input is a valid UTF8 sequence, so you're likely better off just using the default encoding.
One other point is that it's not necessary to set your locals to Nothing when you've finished with them. The Garbage Collector will notice on its own that you don't use the locals anymore, and their contents will be eligible for collection without this step. Actually, by doing this you may extend their lifetime!
Feel free to post back if you've got any more questions. [:-)]
-Shawn