You want to use symmetric encryption (perhaps because you need to encrypt a large amount of data, or performance is very important), but there is no shared secret that you can use.
Create a random symmetric key, and use this key to encrypt your data
Asymmetric encryption is typically 1000 times slower than symmetric encryption, and the encrypted data it creates is several times larger. You can avoid these limitations by generating a random symmetric key, and using it to encrypt the bulk of your data. The trick is to encrypt the random key using asymmetric encryption with the recipient's public key, and then add it to the encrypted document. The recipient can retrieve the encrypted symmetric key, decrypt it using his or her private key, and then use it to decrypt the remainder of the document. This technique is commonly used; two examples are SSL (which negotiates a symmetric session key for each interaction) and the Windows Encrypting File System (which generates a random symmetric key for each file it encrypts).
The following example rewrites the code from recipe 18.7 to use this technique.
Public Class FileEncryptor Inherits System.Windows.Forms.Form Private RSA As New RSACryptoServiceProvider() Private Sub Form_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Check for file with key data. ' This file will contain the full public and private key pair. If File.Exists("key.bin") Then Dim fs As New FileStream("key.bin", FileMode.Open) Dim r As New StreamReader(fs) RSA.FromXmlString(r.ReadToEnd()) fs.Close() Else Dim fs As New FileStream("key.bin", FileMode.CreateNew) Dim w As New StreamWriter(fs) w.Write(RSA.ToXmlString(True)) w.Flush() fs.Close() End If End Sub Private Sub cmdEncrypt_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles cmdEncrypt.Click ' Open a file for writing. Dim fs As New FileStream("testfile.bin", FileMode.Create) ' Create a new (random) symmetric key. Dim Rijndael As New RijndaelManaged() ' Encrypt the symmetric key and IV using the RSA public key. Dim EncryptedKey() As Byte = RSA.Encrypt(Rijndael.Key, False) Dim EncryptedIV() As Byte = RSA.Encrypt(Rijndael.IV, False) ' Write the asymmetrically encrypted key and IV to the file. fs.Write(EncryptedKey, 0, EncryptedKey.Length) fs.Write(EncryptedIV, 0, EncryptedIV.Length) ' Write the remainder of the file using symmetric encryption. Dim Transform As ICryptoTransform = Rijndael.CreateEncryptor() Dim cs As New CryptoStream(fs, Transform, CryptoStreamMode.Write) Dim w As New StreamWriter(cs) w.Write(txtSource.Text) w.Flush() cs.FlushFinalBlock() w.Close() End Sub Private Sub cmdDecrypt_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles cmdDecrypt.Click ' Open a file for reading. Dim fs As New FileStream("testfile.bin", FileMode.Open) ' The key size is measured in bits. 8 bits = 1 byte. ' The amount of bytes in an encrypted block of data is always ' the same as the key
size
. Dim EncryptedBlockSize As Integer = CType(RSA.KeySize / 8, Integer) ' Retrieve the encrypted key and IV. Dim Rijndael As New RijndaelManaged() Dim EncryptedKey(EncryptedBlockSize - 1) As Byte Dim EncryptedIV(EncryptedBlockSize - 1) As Byte fs.Read(EncryptedKey, 0, EncryptedKey.Length) fs.Read(EncryptedIV, 0, EncryptedIV.Length) Rijndael.KeySize = EncryptedBlockSize Rijndael.Key = RSA.Decrypt(EncryptedKey, False) Rijndael.IV = RSA.Decrypt(EncryptedIV, False) ' Use the symmetric key to read the remainder of the file. Dim Transform As ICryptoTransform = Rijndael.CreateDecryptor() Dim cs As New CryptoStream(fs, Transform, CryptoStreamMode.Read) Dim r As New StreamReader(cs) txtFileContents.Text = r.ReadToEnd() r.Close() End Sub End Class