VB.NET - RSA decryption problem

Asked By Harpreet Singh on 11-Jul-04 02:57 PM
HI 
I am using RSA to encrypt a data for my application software .In one program of my software I encrypt data and decrypt data in another (so needs same keys).. I wrote the following code and it works fine for my pc but when i deploy it at another machine it gives the error "bad data"..probably it is not using the same keys for decryption ..Please suggest .. thanks .. Harpreet
    Dim PlainTextBArray As Byte()
    Dim xmlKeys As String   
    Dim xmlPublicKey As String
    Dim CypherTextBArray As Byte()
    Dim rsa As RSACryptoServiceProvider
    Sub New()
        Const PROVIDER_RSA_FULL As Integer = 1
        Const CONTAINER_NAME As String = "MyContainer"
        Dim cspParams As CspParameters
        cspParams = New CspParameters(PROVIDER_RSA_FULL)
        cspParams.KeyContainerName = CONTAINER_NAME
        cspParams.Flags = CspProviderFlags.UseMachineKeyStore
        rsa = New RSACryptoServiceProvider(cspParams)
        xmlKeys = rsa.ToXmlString(True)  
xmlPublicKey = rsa.ToXmlString(False)   
    End Sub
    Function encrypt(ByVal message As String) As Byte()
        rsa.FromXmlString(xmlPublicKey)
        PlainTextBArray = (New UnicodeEncoding()).GetBytes(message)
                CypherTextBArray = rsa.Encrypt(PlainTextBArray, False)
                Return CypherTextBArray
    End Function
    Function decrypt(ByVal message As Byte()) As Byte()
        rsa.FromXmlString(xmlKeys)
               Dim RestoredPlainText As Byte() = rsa.Decrypt(message, False)
        Return RestoredPlainText
    End Function

cspParams = New CspParameters(PROVIDER_RSA_FULL)

Asked By Peter Bromberg on 11-Jul-04 03:34 PM
is creating a whole new RSA public/private key structure each time it is run. Obviously, this will be different on 2 different machines.
What you need to do is either store the CspParameters object or use the same Certificate everywhere the code is run and derive the CspParameters from the certificate.

Public private keys

Asked By Harpreet Singh on 11-Jul-04 04:16 PM
Actually I am encrypting and decrypting data at that machine itself ..so if two machines have different key structure it should not matter as long as encryption and decryption is done on the same machine.. Am I wrong ? PLease guide me if I am thinking wrong
Thanks

That is correct -

Asked By Peter Bromberg on 11-Jul-04 06:11 PM
if your application only does encryption/decryption on the same machine, it should work "out of the box" no matter where you deploy it. 
Which essentially means that you have another type of problem, and the chances are 90% or better that it is a permissions issue. Try using a different data store. Let us know what you find out.
Data Store
Asked By Harpreet Singh on 11-Jul-04 09:19 PM
Thanks for your reply.. How can I use different data store ..I am a newbie so be patient with my questions if they are silly :)... Actually, I am making an application software so wat are the prerequisites on the client machine for me to run RS. Please suggest should I use symmeteric encryption techniques .
Thanks
RSA decryption problem
Asked By Richard Samworth on 15-Jul-04 01:29 PM
Are you still having trouble with this?
Re RSA Problem
Asked By Harpreet Singh on 15-Jul-04 03:34 PM
Yeh I had problem with decryption ..was not able to solve it so i switched to another algorithn if you can suggest wat I was doing wrong ,i would appreciate  that.
Thanks
RSA problem
Asked By Richard Samworth on 16-Jul-04 02:56 PM
Peter Bromberg was probably right, you were getting a different key from the one that you expected when you called RSACryptoServiceProvider.
I'll describe how I think it happened a little later on but first, it's worth discussing your initial design.
All cryptograpic systems have one of three underlying key management strategies:
o Symmentric key management
o Public (or asymmetric) Key management or
o A hybrid key management strategy
In your design you selected a Public Key management strategy. To work reliably and consistently a Public key management strategy requires some form of Public Key Infrastructure (PKI). The Microsoft world has three PKI strategies:
o The .NET CSP key database
o Microsoft Active Directory
o Third-party products (Entrust, RSA, Baltimore etc.)
Your design selected Public key management using the Microsoft CSP key database, supplied as part of the .NET Framework.
Documentation for the Microsoft CSP key database is relatively thin on the ground but the MSDN has one article, written in 1996 that throws some light on the subject. In 'The Cryptography API, or How to Keep a Secret' (MSDN, MSDN LIbrary, Security, Technical Articles) Robert Coleridge writes 'Each CSP has a key database in which it stores its persistent cryptographic keys. Each key database contains one or more key containers, each of which contains all the key pairs belonging to a specific user (or Cryptography API client). Each key container is given a unique name, which applications provide to the CryptAcquireContext function when acquiring a handle to the key container.'
So, the Microsoft CSP key database stores Public/Private key pairs as User Name/Unique Name and this can cause a problem.
The following VB .NET code snippet:
o creates a new CSP container
o Assigns a unique name to the container
o Passes the container and its keys to the RSACryptoServiceProvider constructor
	Dim cp As New CspParameters ' Create a new instance of the CSP container
	cp.KeyContainerName = "MyContainerName" ' Set the name of the container where I store my keys
	Dim rsa As New RSACryptoServiceProvider(cp) ' Instantiate a CSP with my keys
If the unique name doesn't exist in the CSP key database the constructor creates a new entry, generates a new Public/Private key pair, and stores the key pair in the new entry. Therefore, if User A and User B run the same process, the keys database ends up with two entries, one for each user. Both entries have the same 'unique name' and different Public/Private key pairs. And so, the same process running on the same machine under two different User Names will return differrent keys from the CSP key database.
In the .NET Framework 1.1 Microsoft provides a way of getting round this issue. The 
RSACryptoServiceProvider.UseMachineKeyStore property gets or sets a value indicating whether the key should be persisted in the computer's key store instead of the user profile store.
In general, it is better to use a symmetric key management strategy to encrypt and decrypt data because:
o Symmetric cryptography is significantly faster than public key cryptography
o You can write and dsitribute processes that will run on separate machines under different user names but will still be able to read and write encrypted data to one another.
This, I suspect is what you did to solve the problem.
Unless you have a fully functioning PKI .NET Public key cryptography should be used for creating and verifying digital signatures.
Re : RSA Problem again
Asked By Harpreet Singh on 17-Jul-04 04:37 PM
Hi 
Thanks for nice explanation! .. I guessed that error is because of not retrieving the same keys on decryption. I followed the steps of creating a new container and passing csp to initialize rsacryptoserviceprovider and used the machinekeystore  to store the keys. But I was able to run the code perfectly on my machine but when I run the application on my fren's machine it was not decrypting .. I am using .net framework1.0 .. can it be an issue? 
Then I used tripledes and RC2 encryption with private key and IV but I found a unique problem with that too ( luckily problems love me).. When I run the code without debugging(ctrl+F5) the decryption was perfect but on running with debugging(F5) ..1st 4-5 characters were screwed .. can't guess the reason ..I used memory streams to keep data for encryption n decryption.
Atlast I searched on net and I found a code from a site using tripledes with hash stuff( just copied it ..project was getting late)... and it worked fine .... And the problem solved  but not happy as dont know why the things behaved that way
Hopefully some intelectualls like you will put some light on it.
Thanks
Continuing cryptography problems
Asked By Richard Samworth on 21-Jul-04 05:16 AM
Hi Harpeet
It seems to me that changing the design of your application will fix the problem. Changing the underlying algorithm is not likely to be as effective.
All cryptographic systems follow the same 3 steps:
1.  Generate keys
2.  Exchange keys
3.  Use keys
In your initial design, you mixed up steps 1 and 2 and tried to use the same public/private key pair for two different applications. Your used the Microsoft-supplied keys database to store the key pairs. As you discovered, this is not a very reliable design.
As a general rule, always use symmetric encryption to protect the privacy of messages because:
1.  Symmetric key encryption is quicker than public key encryption
2.  Key management is easier to implement
Here's some symmetric key code that uses the Microsoft the RijndaelManaged class to  protect the privacy of messages.
1. Generate keys
Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Public Class Crypto
    Structure stKeys ' Stores symmetric key and initialisation vector
        Dim key() As Byte
        Dim IV() As Byte
    End Structure
    Dim RM As New RijndaelManaged ' New instance of the RijndaelManaged class
    Dim keys As New stKeys ' Create an instance of the Symmetric Keys structure
    Sub New()
        'Create a new symmetric key and a new initialization vector for this session
        RM.GenerateKey()
        RM.GenerateIV()
        'Copy the session key and initialisation vector into byte arrays
        keys.key = RM.Key
        keys.IV = RM.IV
    End Sub
2.  Exchange keys
Make a note of the values of Key and IV and hard code them into your programs.
3.  Use keys
Each program encrypts / decrypts data using hard-coded symmetric keys. Because both applications use exactly the same keys there cannot be any problems with user login ID, operating system version, .NET Framework version, or anything else to do with your mate's machine.
I leave it to you to finesse the stream IO. Hint: a VB string can contain approximately 2 billion characters.
#Region "Symmetric Key Encryption helpers"
Sub SymmetricEncrypt(ByVal strFileName As String, ByVal plainText As String)
        'Create a symmetrically encrypted (File) stream and write some data to it
        Try
            'Create a file stream
            Dim fs As New FileStream(strFileName, FileMode.OpenOrCreate, FileAccess.Write)
            'Create an encrypted stream that writes to the underlying file stream
            Dim CryptStream As New CryptoStream(fs, RM.CreateEncryptor(RM.Key, RM.IV), CryptoStreamMode.Write)
            'Create a StreamWriter to write to the encrypted stream.
            Dim SWriter As New StreamWriter(CryptStream)
            'Write the plain text string to the encrypted stream
            SWriter.Write(plainText)
            ' Close everything
            SWriter.Close()
            CryptStream.Close()
            fs.Close()
        Catch ex As Exception
            MessageBox.Show("Error : " & ex.ToString, "Crypto Object", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub
    Function SymmetricDecrypt(ByVal strfileName As String) As String
        'Read and return the contents of a symmetrically encrypted (File) stream
        Dim plainText As String
        Try
            'Create a file stream
            Dim fs As New FileStream(strfileName, FileMode.OpenOrCreate, FileAccess.Read)
            'Create an encrypted stream that reads from the underlying file stream
            Dim CryptStream As New CryptoStream(fs, RM.CreateDecryptor(RM.Key, RM.IV), CryptoStreamMode.Read)
            'Create a StreamReader to read the encrypted stream
            Dim SReader As New StreamReader(CryptStream)
            ' Read the encrypted stream and convert into plain text
            plainText = SReader.ReadToEnd()
            ' Close everything and return the plain text string
            SReader.Close()
            CryptStream.Close()
            fs.Close()
        Catch ex As Exception
            MessageBox.Show("Error : " & ex.ToString, "Crypto Object", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
        Return (plainText)
    End Function
#End Region
End Class
-R