Encryption/ Decryption - c#

I want to decrypt an already encrypted file but getting the error "Bad Data". I think that that the method I used here to generate key is not generating same key while encrypting and decrypting. So, I want to declare my own key. How can i do this?
This is my code.
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
public static class crypto
{
public static String tempdir = Environment.ExpandEnvironmentVariables("%temp%");
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
Clipboard.SetText(desCrypto.Key.ToString());
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
public static void Encrypt(String table, String file)
{
GenerateKey();
try
{
String filepath = Path.Combine(tempdir + #"\Manager\data\" + table,file);
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc(sSecretKey, GCHandleType.Pinned);
// Encrypt the file.
EncryptFile(#"" + filepath,
#"" + Application.StartupPath + #"\data\"+ table + #"\" + file,
sSecretKey);
try
{
File.Delete(filepath);
}
catch (Exception ex1)
{
MessageBox.Show(ex1.Message, "Error while deletion of decrypted file");
}
// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error during encryption");
}
}
public static void Decrypt(String table, String file)
{
try
{
String filepath = Path.Combine(tempdir + #"\Manager\data\"+table, file);
create.folder("Manager", tempdir);
create.folder(table, tempdir + #"\Manager\");
create.file(file, tempdir + #"\Manager\" + table);
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc(sSecretKey, GCHandleType.Pinned);
// Decrypt the file.
DecryptFile(#".\data\" + table + #"\" + file,
#"" + filepath,
sSecretKey);
// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error during decryption");
}
}
}

Your GenerateKey Method generates a new (random) key every time you call it (like you already stated in the comments there). If you want to use a random key, store the generated key somewhere and use it for decryption and encryption.
You can use a own "password" for encryption by giving your encryption/decryption method a own string value. e.g.
crypto.EncryptFile(#"D:\Testing\brownfox.txt", #"D:\Testing\brownfox_enc.txt", "abcd1234");
crypto.DecryptFile(#"D:\Testing\brownfox_enc.txt", #"D:\Testing\brownfox_dec.txt", "abcd1234");
As you can see in the MSDN reference to "DES.Key", DES supports keys with a length of 64bit, so it's important to note, that the string must have 8 characters.

Related

The Length of Data is invalid while decrypting a txt file

I made a console app to decrypt a file . Please refer to the screenshot for detail error message.
If you copy paste the code in a console app . You should be able to debug .
1) Need to make folder SourceFolder\Newfolder\ and a new txt file destination.txt
2) Need to make folder for C:\DestinationFolder\source.txt(encrypted file cannot attach file here i hope you can make one
using System;
using System.IO;
using System.Security.Cryptography;
namespace ConsoleApp5
{
class Program
{
//SALT is a random data that is used as addition to a password to encrypt data
// The primary function is to protect against lists of often used password
private static readonly byte[] SALT = new byte[] {0x26,0xdc,0xff,0x76,0x76,
0xad,0xed,0x7a,0x64,0xc5,0xfe
,0x20,0xaf,0x4d,0x08,0x3c};
static void Main(string[] args)
{
//Need to make a SourceFolder and but the file in there abc.txt
string path = #"C:\SourceFolder\New folder\";
string[] txtFile = Directory.GetFiles(path, "*.txt");
string fileinnn = txtFile[0];
//Get the filepath of the decrypted file. Need to make this folder and add a new file that is what i am donig for now for this cosole app
string filepathDecrypted = #"C:\DestinationFolder\destination.txt"; //this is a new file need to create
//Get the password
string encrytionKey = "password.";
Decrypt(fileinnn, filepathDecrypted, encrytionKey);
}
public static void Decrypt(string fileIn, string fileOut, string Password)
{
//open filestreat for encrypted source file
using (System.IO.FileStream fsIn = new FileStream(fileIn, FileMode.Open, FileAccess.Read))
{
using (System.IO.FileStream fsOut = new FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write))
{
try
{
//Create Key and IV from the password with the SALT
Rfc2898DeriveBytes pdf = new Rfc2898DeriveBytes(Password, SALT);
//Create a symmetric algorithm with Rijndael
Rijndael alg = Rijndael.Create();
alg.Padding = PaddingMode.PKCS7;
//alg.BlockSize = 128;
//SET key and IV
alg.Key = pdf.GetBytes(32);
alg.IV = pdf.GetBytes(16);
//Create a cryptoStream
using (CryptoStream cs = new CryptoStream(fsOut, alg.CreateDecryptor(), CryptoStreamMode.Write))
{
//Intialize the buffer and process the input in chunks
// this is done to avoid reading the whole file which is huge and memory consumption.
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
do
{ //read a chunck of data from the input file
bytesRead = fsIn.Read(buffer, 0, bufferLen);
//Decrypt it
cs.Write(buffer, 0, bytesRead);
}
while (bytesRead != 0);
//close everything
cs.Close(); //this is where it throws exception
fsOut.Close();
fsIn.Close();
}
}
catch (Exception ex)
{
var error = ex.Message;
throw;
}
}
}
}
}
}
Error message that i am getting

CryptographicException: Length of the data to decrypt is invalid

I get "Length of the data to decrypt is invalid" when I try to decrypt my file.
public class EncryptDecrypt
{
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Function to Generate a 64 bits Key.
public static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
public static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
public static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
//ExportCSV.EncryptDecrypt c = new EncryptDecrypt();
// Get the Key for the file to Encrypt.
sSecretKey = EncryptDecrypt.GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc(sSecretKey, GCHandleType.Pinned);
// Encrypt the file.
EncryptDecrypt.EncryptFile(#"C:\Test\Sample.xml",
#"C:\Test\Encrypted.xml",
sSecretKey);
// Decrypt the file.
EncryptDecrypt.DecryptFile(#"C:\Test\Sample.xml",
#"C:\Test\Decrypted.xml",
sSecretKey);
// Remove the Key from memory.
EncryptDecrypt.ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
I get the error while trying to write the decrypted data to file
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
Please let me know what I am missing.

How to decrypt an AES-256-CBC encrypted string

I'm new to C# and I really need help. I need to encrypt/decrypt a string with AES-256-CBC in C#, I found this to encrypt a string:
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
try
{
MemoryStream ms = new MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(message);
sw.Close();
}
cs.Close();
}
byte[] encoded = ms.ToArray();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
I tried to write a decrypt function base on the above code, the following code is what I did:
// Decrypt a byte array into a byte array using a key and an IV
private byte[] Decrypt(byte[] cipherData, byte[] Key, byte[] IV)
{
byte[] decryptedData;
//string plaintext = null;
//MemoryStream ms = new MemoryStream(cipherData);
RijndaelManaged alg = new RijndaelManaged();
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = Key;
alg.IV = IV;
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.Zeros;
//Array.Copy(Key, 0, IV, 0, IV.Length);
ICryptoTransform decryptor = alg.CreateDecryptor(alg.Key, alg.IV);
using(MemoryStream ms = new MemoryStream(cipherData))
{
using (CryptoStream csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sw = new StreamReader(csDecrypt))
{
sw.ReadToEnd();
sw.Close();
}
csDecrypt.Close();
decryptedData = ms.ToArray();
}
}
//byte[] decryptedData = System.Text.Encoding.Unicode.GetBytes(plaintext);
return decryptedData;
}
But it's nonsense, it can't decrypt anything. I'm really confused and need help. Thank you for any help!
P/s: Please don't give me other similar answered questions, I already take a look at them. Their encrypt function doesn't have the same output like the above encrypt function, while I need to decrypt string which MUST be encrypt by the above function. I have two friend who wrote decrypt function in PHP and objective-C, which matched with the above encrypt function, it's bad to have them do it again.
Looking at your encryption, something like this should do it, passing the resulting string from your encryption in should give the original string back;
// Decrypt a string into a string using a key and an IV
public static string Decrypt(string cipherData, string keyString, string ivString)
{
byte[] key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
try
{
using (var rijndaelManaged =
new RijndaelManaged {Key = key, IV = iv, Mode = CipherMode.CBC})
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(cipherData)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(key, iv),
CryptoStreamMode.Read))
{
return new StreamReader(cryptoStream).ReadToEnd();
}
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
// You may want to catch more exceptions here...
}
A small note; you're getting the key using UTF8 encoding from the key string, UTF8 encoding may give you multiple bytes back for international characters, which may give a key or IV of the wrong length for encryption/decryption. Also, using the small range of passwords/keys with 8 characters and printable characters will not give you very secure encryption, you may want to run the string though SHA1 or similar before using it as a key (which will sadly make it incompatible with the current encryption)

C# DES File Decryption Breaking Non-Text Files

I have these two methods which are pretty much copy+pastes from http://support.microsoft.com/kb/307010.
When I decrypt the files, if they are any type of text file such as .txt, .xml, .html, etc. I can open them up and everything is fine. Any type of file not just text, such as .exe, .jpg, .pdf, etc. all break when decrypted. Is there anything I am doing wrong? Are these methods using binary to encrypt/decrypt the files? If not is there a way I can make it binary?
Any help is greatly appreciated!
public static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
public static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
fsread.Close();
cryptostreamDecr.Close();
}
I don't know what the guy that wrote that article was smoking, but:
DESCryptoServiceProvider desCrypto =
(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
will not get you a valid key. At least one problem is the fact that the key you use to encrypt is not the same key that you're using to decrypt, because you can't convert bytes to ASCII and back like that.
If you want to treat the key as a string, what you probably want is:
string keyAsString = Convert.ToBase64String(desCrypto.Key);
Then when you want to turn it back into bytes, instead of ASCIIEncoding.ASCII.GetBytes, you'll do:
byte[] key = Convert.FromBase64String(keyAsString);
EDIT
There's a ton more wrong with that article too. I'd say ignore that one and find a better example.
EDIT
Here's a very clean basic AES working example that I use for my standard encryption needs. Some of the major improvements over the article are:
Proper creation of a key
Current algorithm (AES 256-bit key)
Random IV
Buffered file access instead of reading/writing the entire file in one chunk
Wrapping all the disposable objects in using
Aside from that, it's the same basic idea.
using System;
using System.IO;
using System.Security.Cryptography;
namespace ConsoleApplication12
{
class Program
{
private const int KEY_SIZE_BYTES = 32;
private const int IV_SIZE_BYTES = 16;
static void Main(string[] args)
{
var rand = new Random();
using (var fs = File.Open(#"C:\temp\input.bin", FileMode.Create, FileAccess.Write, FileShare.None))
{
byte[] buffer = new byte[10000];
for (int i = 0; i < 100; ++i)
{
rand.NextBytes(buffer);
fs.Write(buffer, 0, buffer.Length);
}
}
string key = GenerateRandomKey();
Encrypt(#"C:\temp\input.bin", #"C:\temp\encrypted.bin", key);
Decrypt(#"C:\temp\encrypted.bin", #"C:\temp\decyrypted.bin", key);
}
static string GenerateRandomKey()
{
byte[] key = new byte[KEY_SIZE_BYTES];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(key);
}
return Convert.ToBase64String(key);
}
static void Encrypt(string inputFile, string outputFile, string key)
{
const int BUFFER_SIZE = 8192;
byte[] buffer = new byte[BUFFER_SIZE];
byte[] keyBytes = Convert.FromBase64String(key);
byte[] ivBytes = new byte[IV_SIZE_BYTES];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(ivBytes);
}
using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var outputStream = File.Open(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
outputStream.Write(ivBytes, 0, ivBytes.Length);
using (var cryptoAlgo = Aes.Create())
{
using (var encryptor = cryptoAlgo.CreateEncryptor(keyBytes, ivBytes))
{
using (var cryptoStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
{
int count;
while ((count = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
cryptoStream.Write(buffer, 0, count);
}
}
}
}
}
}
}
static void Decrypt(string inputFile, string outputFile, string key)
{
const int BUFFER_SIZE = 8192;
byte[] buffer = new byte[BUFFER_SIZE];
byte[] keyBytes = Convert.FromBase64String(key);
byte[] ivBytes = new byte[IV_SIZE_BYTES];
using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
inputStream.Read(ivBytes, 0, ivBytes.Length);
using (var outputStream = File.Open(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (var cryptoAlgo = Aes.Create())
{
using (var decryptor = cryptoAlgo.CreateDecryptor(keyBytes, ivBytes))
{
using (var cryptoStream = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read))
{
int count;
while ((count = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
{
outputStream.Write(buffer, 0, count);
}
}
}
}
}
}
}
}
}
Because the IV is random, you'll see another small difference in technique. When encrypting the file, you first write the IV to the encrypted file (it's not a secret, so you just write it straight out). When decrypting the file, you read the first few bytes to retrieve the IV, then the rest of the file contains the actual encrypted data. The purpose of a random IV is so the same plaintext file will encrypt into a different encrypted file every time you run it.
The Main method here demonstrates encryption with a random key. If you want to use a password, it's a little more work, but you can implement PBKDF2 with maybe a dozen or so extra lines of code.

Encryption and decryption with RSAServiceProvider in C#

I am trying the most basic thing - encrypt data using the public key and decrypt using private key:
X509Certificate2 cert = new X509Certificate2(#"c:\temp\CERT\mycert.pfx", "test1");
RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
RSACryptoServiceProvider publicKey = cert.PublicKey.Key as RSACryptoServiceProvider;
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes("Sample data");
byte[] enData = publicKey.Encrypt(plainData, true);
Console.WriteLine("Encrypted Output: {0}", bytConvertor.GetString(enData));
byte[] deData = privateKey.Decrypt(enData, true);
Console.WriteLine("Decrypted Output: {0}", bytConvertor.GetString(deData));
But the 2nd last line privateKey.Decrypt(...) throws the following exception:
System.Security.Cryptography.CryptographicException was unhandled
Message=Bad Key.
Source=mscorlib StackTrace:
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle
pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean
fOAEP, ObjectHandleOnStack ohRetDecryptedKey)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[]
rgb, Boolean fOAEP)
at ConsoleApplication4.Program.Main(String[] args) in `c:\users\kazia\documents\visual studio`
`2010\Projects\ConsoleApplication4\Program.cs`:line 44 ...
InnerException:
I must be missing something obvious. What is the standard way to use RSA encryption in both end (public and private) using .NET? Any help would be appreciated.
Thanks!
Found the answer here:
http://msdn.microsoft.com/en-us/library/ms148409.aspx
Great example:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Text;
// To run this sample use the Certificate Creation Tool (Makecert.exe) to generate a test X.509 certificate and
// place it in the local user store.
// To generate an exchange key and make the key exportable run the following command from a Visual Studio command prompt:
//makecert -r -pe -n "CN=CERT_SIGN_TEST_CERT" -b 01/01/2010 -e 01/01/2012 -sky exchange -ss my
namespace X509CertEncrypt
{
class Program
{
// Path variables for source, encryption, and
// decryption folders. Must end with a backslash.
private static string encrFolder = #"C:\Encrypt\";
private static string decrFolder = #"C:\Decrypt\";
private static string originalFile = "TestData.txt";
private static string encryptedFile = "TestData.enc";
static void Main(string[] args)
{
// Create an input file with test data.
StreamWriter sw = File.CreateText(originalFile);
sw.WriteLine("Test data to be encrypted");
sw.Close();
// Get the certifcate to use to encrypt the key.
X509Certificate2 cert = GetCertificateFromStore("CN=CERT_SIGN_TEST_CERT");
if (cert == null)
{
Console.WriteLine("Certificatge 'CN=CERT_SIGN_TEST_CERT' not found.");
Console.ReadLine();
}
// Encrypt the file using the public key from the certificate.
EncryptFile(originalFile, (RSACryptoServiceProvider)cert.PublicKey.Key);
// Decrypt the file using the private key from the certificate.
DecryptFile(encryptedFile, (RSACryptoServiceProvider)cert.PrivateKey);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", File.ReadAllText(originalFile));
Console.WriteLine("Round Trip: {0}", File.ReadAllText(decrFolder + originalFile));
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
}
private static X509Certificate2 GetCertificateFromStore(string certName)
{
// Get the certificate store for the current user.
X509Store store = new X509Store(StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);
// Place all certificates in an X509Certificate2Collection object.
X509Certificate2Collection certCollection = store.Certificates;
// If using a certificate with a trusted root you do not need to FindByTimeValid, instead:
// currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, true);
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
if (signingCert.Count == 0)
return null;
// Return the first certificate in the collection, has the right name and is current.
return signingCert[0];
}
finally
{
store.Close();
}
}
// Encrypt a file using a public key.
private static void EncryptFile(string inFile, RSACryptoServiceProvider rsaPublicKey)
{
using (AesManaged aesManaged = new AesManaged())
{
// Create instance of AesManaged for
// symetric encryption of the data.
aesManaged.KeySize = 256;
aesManaged.BlockSize = 128;
aesManaged.Mode = CipherMode.CBC;
using (ICryptoTransform transform = aesManaged.CreateEncryptor())
{
RSAPKCS1KeyExchangeFormatter keyFormatter = new RSAPKCS1KeyExchangeFormatter(rsaPublicKey);
byte[] keyEncrypted = keyFormatter.CreateKeyExchange(aesManaged.Key, aesManaged.GetType());
// Create byte arrays to contain
// the length values of the key and IV.
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
int lKey = keyEncrypted.Length;
LenK = BitConverter.GetBytes(lKey);
int lIV = aesManaged.IV.Length;
LenIV = BitConverter.GetBytes(lIV);
// Write the following to the FileStream
// for the encrypted file (outFs):
// - length of the key
// - length of the IV
// - ecrypted key
// - the IV
// - the encrypted cipher content
int startFileName = inFile.LastIndexOf("\\") + 1;
// Change the file's extension to ".enc"
string outFile = encrFolder + inFile.Substring(startFileName, inFile.LastIndexOf(".") - startFileName) + ".enc";
Directory.CreateDirectory(encrFolder);
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
outFs.Write(LenK, 0, 4);
outFs.Write(LenIV, 0, 4);
outFs.Write(keyEncrypted, 0, lKey);
outFs.Write(aesManaged.IV, 0, lIV);
// Now write the cipher text using
// a CryptoStream for encrypting.
using (CryptoStream outStreamEncrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
// By encrypting a chunk at
// a time, you can save memory
// and accommodate large files.
int count = 0;
int offset = 0;
// blockSizeBytes can be any arbitrary size.
int blockSizeBytes = aesManaged.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
int bytesRead = 0;
using (FileStream inFs = new FileStream(inFile, FileMode.Open))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamEncrypted.Write(data, 0, count);
bytesRead += blockSizeBytes;
}
while (count > 0);
inFs.Close();
}
outStreamEncrypted.FlushFinalBlock();
outStreamEncrypted.Close();
}
outFs.Close();
}
}
}
}
// Decrypt a file using a private key.
private static void DecryptFile(string inFile, RSACryptoServiceProvider rsaPrivateKey)
{
// Create instance of AesManaged for
// symetric decryption of the data.
using (AesManaged aesManaged = new AesManaged())
{
aesManaged.KeySize = 256;
aesManaged.BlockSize = 128;
aesManaged.Mode = CipherMode.CBC;
// Create byte arrays to get the length of
// the encrypted key and IV.
// These values were stored as 4 bytes each
// at the beginning of the encrypted package.
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
// Consruct the file name for the decrypted file.
string outFile = decrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".txt";
// Use FileStream objects to read the encrypted
// file (inFs) and save the decrypted file (outFs).
using (FileStream inFs = new FileStream(encrFolder + inFile, FileMode.Open))
{
inFs.Seek(0, SeekOrigin.Begin);
inFs.Seek(0, SeekOrigin.Begin);
inFs.Read(LenK, 0, 3);
inFs.Seek(4, SeekOrigin.Begin);
inFs.Read(LenIV, 0, 3);
// Convert the lengths to integer values.
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
// Determine the start postition of
// the ciphter text (startC)
// and its length(lenC).
int startC = lenK + lenIV + 8;
int lenC = (int)inFs.Length - startC;
// Create the byte arrays for
// the encrypted AesManaged key,
// the IV, and the cipher text.
byte[] KeyEncrypted = new byte[lenK];
byte[] IV = new byte[lenIV];
// Extract the key and IV
// starting from index 8
// after the length values.
inFs.Seek(8, SeekOrigin.Begin);
inFs.Read(KeyEncrypted, 0, lenK);
inFs.Seek(8 + lenK, SeekOrigin.Begin);
inFs.Read(IV, 0, lenIV);
Directory.CreateDirectory(decrFolder);
// Use RSACryptoServiceProvider
// to decrypt the AesManaged key.
byte[] KeyDecrypted = rsaPrivateKey.Decrypt(KeyEncrypted, false);
// Decrypt the key.
using (ICryptoTransform transform = aesManaged.CreateDecryptor(KeyDecrypted, IV))
{
// Decrypt the cipher text from
// from the FileSteam of the encrypted
// file (inFs) into the FileStream
// for the decrypted file (outFs).
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
int count = 0;
int offset = 0;
int blockSizeBytes = aesManaged.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
// By decrypting a chunk a time,
// you can save memory and
// accommodate large files.
// Start at the beginning
// of the cipher text.
inFs.Seek(startC, SeekOrigin.Begin);
using (CryptoStream outStreamDecrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamDecrypted.Write(data, 0, count);
}
while (count > 0);
outStreamDecrypted.FlushFinalBlock();
outStreamDecrypted.Close();
}
outFs.Close();
}
inFs.Close();
}
}
}
}
}
}
Nothing wrong with your code, the only thing that needs changing is the way you generated your key pair. In the answer:
//makecert -r -pe -n "CN=CERT_SIGN_TEST_CERT" -b 01/01/2010 -e 01/01/2012 -sky exchange -ss my
The relevant part is -sky exchange, which was probably omitted from the call to makecert.exe when you first reported the "Bad Key" error on Decrypt.

Categories