RSACryptoServiceProvider & Bad Key Exception

Hi,

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
pw = CipherEngine.DecryptString(cp)

'Create a new password window, displaying the old password

sec = New SecuritySettings(pw)

Else

'Create a new password window, displaying NO old password

sec = New SecuritySettings

End If

Else

'Create a new password window, displaying NO old password

sec = New SecuritySettings

End If

'Show the password dialog box

If sec.ShowDialog(Me) = DialogResult.OK Then

'Get the new password

pw = sec.txtNewPassword1.Text

'Encrypt the password

cp = CipherEngine.EncryptString(pw)

'Serialize the password and RSAParameters to file

CipherStorage.SaveCipherPackage(cp)

End If

sec.Dispose()

sec = Nothing

cp = Nothing

End Sub

 



and this is the rest of the code:



Imports System.Runtime.Serialization.Formatters

Imports System.Security.Cryptography

Imports System.IO

Imports System.Text

<Serializable()> _

Class CipherPackage

Public cipherBytes() As Byte ' RC2 encrypted message text

Public params As RSAParameters

End Class 'CipherPackage

Class CipherEngine

Public 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 RSACryptoServiceProvider

rsa.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 'DecryptMessage

End Class 'Person

Class CipherStorage

Public 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 = Nothing

fs.Close()

fs = Nothing

Catch e As Exception

Console.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.BinaryFormatter

result = CType(formatter.Deserialize(fs), CipherPackage)

formatter = Nothing

fs.Close()

fs = Nothing

Catch e As Exception

Console.WriteLine(e.Message)

End Try

Return result

End Function

 



Any help would be appreciated!

Charl



Answer this question

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

    Thanks 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



  • RSACryptoServiceProvider & Bad Key Exception