This is my current implementation of the Data Encryption Standard algorithm in .NET, both encryption and decryption:
static string Encrypt(string text, string key)
{
byte[] textBytes = ASCIIEncoding.ASCII.GetBytes(text);
byte[] keyBytes = ASCIIEncoding.ASCII.GetBytes(key);
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
provider.Mode = CipherMode.OFB;
ICryptoTransform transform = provider.CreateEncryptor(keyBytes, keyBytes);
CryptoStreamMode mode = CryptoStreamMode.Write;
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, mode);
cryptoStream.Write(textBytes, 0, textBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedTextBytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(encryptedTextBytes, 0, encryptedTextBytes.Length);
string encryptedText = Convert.ToBase64String(encryptedTextBytes);
return encryptedText;
}
static string Decrypt(string text, string key)
{
byte[] textBytes = Convert.FromBase64String(text);
byte[] keyBytes = ASCIIEncoding.ASCII.GetBytes(key);
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
provider.Mode = CipherMode.OFB;
ICryptoTransform transform = provider.CreateDecryptor(keyBytes, keyBytes);
CryptoStreamMode mode = CryptoStreamMode.Write;
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, mode);
cryptoStream.Write(textBytes, 0, textBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] decryptedMessageBytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(decryptedMessageBytes, 0, decryptedMessageBytes.Length);
string decryptedText = ASCIIEncoding.ASCII.GetString(decryptedMessageBytes);
return decryptedText;
}
But it returns exception: OFB is not supported by this implementation.
Any ideas how to fix it, or where to find working OFB implementation?
Related
I use this code below to encrypt and decrypt a string, but it returns a value including special characters and length of returned value is not specific.
I want to use this to generate a serial key, so is it possible to turn result to specific length and specific character set like A-Z,0-9 ?
static readonly string PasswordHash = "P##Sw0rd";
static readonly string SaltKey = "S#LT&KEY";
static readonly string VIKey = "#1B2c3D4e5F6g7H8";
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
return Convert.ToBase64String(cipherTextBytes);
}
public static string Decrypt(string encryptedText)
{
byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };
var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
var memoryStream = new MemoryStream(cipherTextBytes);
var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
}
The two padding modes do not match. Especially PaddingMode.None does not make sense if your data is not block-aligned.
PaddingMode.Zeros also does not make sense because it causes the padding to be not removable.
It seems you have fiddled with settings until it seemed to work. That is very dangerous with cryptography. It is also an unsound development practice in general.
This question already has answers here:
Encrypt and decrypt a string in C#? [closed]
(29 answers)
Closed 9 years ago.
I'm looking for an easy way to encrypt and decrypt some data using a fixed key (which will be stored in my configurations) and store the result as string (base16 or hex).
Something like
string myString = "hello world";
string myKey = "k2k3aij3h";
string enc = new Algorithm().Encrypt(myString, myKey);
string dec = new Alrorithm().Decrypt(enc, myKey);
try this
private const string initVector = "tu89geji340t89u2";
private const int keysize = 256;
public static string Encrypt(string Text, string Key)
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(Text);
PasswordDeriveBytes password = new PasswordDeriveBytes(Key, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] Encrypted = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(Encrypted);
}
public static string Decrypt(string EncryptedText, string Key)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] DeEncryptedText = Convert.FromBase64String(EncryptedText);
PasswordDeriveBytes password = new PasswordDeriveBytes(Key, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(DeEncryptedText);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[DeEncryptedText.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
it's from here
in my project i write tow method to encrypt and decrypt string some string in my xml file
but know i want to encrypt a whole xml file
i want to edit methods to encrypt and decrypt a whole file Instead of string
public static string Encrypt(string plainText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes("teto1620##$%asdf");
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = Encoding.Unicode.GetBytes("_+)&qwer9512popo");
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}
public static string Decrypt(string cipherText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes("teto1620##$%asdf");
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
byte[] keyBytes = Encoding.Unicode.GetBytes("_+)&qwer9512popo");
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
return plainText;
}
File.ReadAllText() returns a string so you can just ReadAllText() encrypt using your normal string method, and then use File.WriteAllText() to write the encrypted version back to file.
For large files however, you can read and process line by line instead. e.g.
using (StreamReader sr = new StreamReader("xmlfile.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
File.WriteAllText("mynewxmfile.xml", MyEncryptMethod(line));
}
}
Its very simple, Convert your XML to string and pass it to encrypt/decrypt function.
What classes are you using to create XML ? iF You are using XMLDocument, then following function could be used to convert your XML to string
public string ConvertToString(XmlDocument xml)
{
StringWriter sw = new StringWriter();
XmlTextWriter tx = new XmlTextWriter(sw);
xml.WriteTo(tx);
string str = sw.ToString();
return str;
}
Similarly you could while decrypting, you could convert your decrypted string to XML as following
XmlDocument doc = new XmlDocument();
doc.LoadXml(decruptString);
I have a problem with decryption of data previously encrypted. I am using the sequential encrypt-decrypt-encrypt with three different keys to get triple des effect. The encryption function works correctly (returns 8-byte array), but the decryption function returns empty array.
public static byte[] EncryptDES(byte[] clearData, byte[] key)
{
DES desEncrypt = new DESCryptoServiceProvider();
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = key;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream encryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(encryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(clearData, 0, clearData.Length);
byte [] encryptedData = encryptedStream.ToArray();
return encryptedData;
}
public static byte[] DecryptDES(byte[] clearData, byte[] key)
{
DES desDecrypt = new DESCryptoServiceProvider();
desDecrypt.Mode = CipherMode.ECB;
desDecrypt.Key = key;
ICryptoTransform transForm = desDecrypt.CreateDecryptor();
MemoryStream decryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(decryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(clearData, 0, clearData.Length);
byte[] encryptedData = decryptedStream.ToArray();
return encryptedData;
}
public static byte[] Encrypt3DES(byte[] clearData, byte[] key0, byte[] key1, byte[] key2)
{
byte[] encryptedData1 = new byte[clearData.Length];
byte[] encryptedData2 = new byte[clearData.Length];
byte[] encryptedData3 = new byte[clearData.Length];
encryptedData1 = DESCrypto.EncryptDES(clearData , key0);
encryptedData2 = DESCrypto.DecryptDES(encryptedData1, key1);
encryptedData3 = DESCrypto.EncryptDES(encryptedData2, key2);
return encryptedData3;
}
What am I doing wrong?
TripleDES already exist in the Framework but I guess you want to roll your own implementation for educational purposes.
You're making things more complicated than necessary. Since you are using streams why don't you chain them all instead:
public static byte[] TripleDESEncrypt(byte[] plainText, byte[] key1, byte[] key2, byte[] key3)
{
var des = DES.Create();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
des.Key = key3;
var encryptor1 = des.CreateEncryptor();
des.Key = key2;
var decryptor = des.CreateDecryptor();
des.Padding = PaddingMode.PKCS7;
des.Key = key1;
var encryptor2 = des.CreateEncryptor();
byte[] result;
using (var ms = new MemoryStream())
{
using (var cs1 = new CryptoStream(ms, encryptor1, CryptoStreamMode.Write))
using (var cs2 = new CryptoStream(cs1, decryptor, CryptoStreamMode.Write))
using (var cs3 = new CryptoStream(cs2, encryptor2, CryptoStreamMode.Write))
cs3.Write(plainText, 0, plainText.Length);
result = ms.ToArray();
}
return result;
}
public static byte[] TripleDESDecrypt(byte[] cipherText, byte[] key1, byte[] key2, byte[] key3)
{
var des = DES.Create();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
des.Key = key1;
var decryptor1 = des.CreateDecryptor();
des.Padding = PaddingMode.None;
des.Key = key2;
var encryptor = des.CreateEncryptor();
des.Key = key3;
var decryptor2 = des.CreateDecryptor();
byte[] result;
using (var ms = new MemoryStream())
{
using (var cs1 = new CryptoStream(ms, decryptor1, CryptoStreamMode.Write))
using (var cs2 = new CryptoStream(cs1, encryptor, CryptoStreamMode.Write))
using (var cs3 = new CryptoStream(cs2, decryptor2, CryptoStreamMode.Write))
cs3.Write(cipherText, 0, cipherText.Length);
result = ms.ToArray();
}
return result;
}
Make note of the usage of using blocks and also how the padding is applied to the different streams.
The framework TripleDES is about 2.5 times faster than the above code.
public static byte[] TripleDESEncryptFramework(byte[] plainText, byte[] key)
{
var tdes = TripleDES.Create();
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
tdes.Key = key;
var encryptor = tdes.CreateEncryptor();
byte[] result;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
cs.Write(plainText, 0, plainText.Length);
result = ms.ToArray();
}
return result;
}
If you want to compare the results of the two different encryption methods then you need to remember that the 24-bit key for TripleDES is actually the 3 keys put in one array:
[ key1 ][ key2 ][ key3 ]
==============================
[ key ]
Just need cryptoStream.FlushFinalBlock(). Its code works great:
//ENCRYPT
public static byte[] EncryptDES(byte[] clearData, byte[] key)
{
DES desEncrypt = new DESCryptoServiceProvider();
desEncrypt.Mode = CipherMode.ECB;
desEncrypt.Key = key;
ICryptoTransform transForm = desEncrypt.CreateEncryptor();
MemoryStream encryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(encryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.FlushFinalBlock();
return encryptedStream.ToArray();
}
//DECRYPT
public static byte[] DecryptDES(byte[] clearData, byte[] key)
{
DES desDecrypt = new DESCryptoServiceProvider();
desDecrypt.Mode = CipherMode.ECB;
desDecrypt.Key = key;
ICryptoTransform transForm = desDecrypt.CreateDecryptor();
MemoryStream decryptedStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(decryptedStream, transForm, CryptoStreamMode.Write);
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.FlushFinalBlock();
return decryptedStream.ToArray();
}
I am trying to encrypt/decrypt an XML file. I found this sample for encrypting but I do not know how to decrypt? Any idea? Thanks!
// Load this XML file
System.Xml.XmlDocument myDoc = new System.Xml.XmlDocument();
myDoc.Load(#"c:\persons.xml");
// Get a specified element to be encrypted
System.Xml.XmlElement element = myDoc.GetElementsByTagName("Persons")[0] as System.Xml.XmlElement;
// Create a new TripleDES key.
System.Security.Cryptography.TripleDESCryptoServiceProvider tDESkey = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
// Form a Encrypted XML with the Key
System.Security.Cryptography.Xml.EncryptedXml encr = new System.Security.Cryptography.Xml.EncryptedXml();
encr.AddKeyNameMapping("Deskey", tDESkey);
// Encrypt the element data
System.Security.Cryptography.Xml.EncryptedData ed = encr.Encrypt(element, "Deskey");
// Replace the existing data with the encrypted data
System.Security.Cryptography.Xml.EncryptedXml.ReplaceElement(element, ed, false);
// saves the xml file with encrypted data
myDoc.Save(#"c:\encryptedpersons.xml");
But I do not know how I would decrypt that? Any ideas? Thanks!
Something like this:
public static class Encryption
{
private const string InitVector = "T=A4rAzu94ez-dra";
private const int KeySize = 256;
private const int PasswordIterations = 1000; //2;
private const string SaltValue = "d=?ustAF=UstenAr3B#pRu8=ner5sW&h59_Xe9P2za-eFr2fa&ePHE#ras!a+uc#";
public static string Decrypt(string encryptedText, string passPhrase)
{
byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
byte[] initVectorBytes = Encoding.UTF8.GetBytes(InitVector);
byte[] passwordBytes = Encoding.UTF8.GetBytes(passPhrase);
string plainText;
byte[] saltValueBytes = Encoding.UTF8.GetBytes(SaltValue);
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(passwordBytes, saltValueBytes, PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged rijndaelManaged = new RijndaelManaged { Mode = CipherMode.CBC };
try
{
using (ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(encryptedTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
//TODO: Need to look into this more. Assuming encrypted text is longer than plain but there is probably a better way
byte[] plainTextBytes = new byte[encryptedTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
catch (CryptographicException)
{
plainText = string.Empty; // Assume the error is caused by an invalid password
}
return plainText;
}
public static string Encrypt(string plainText, string passPhrase)
{
string encryptedText;
byte[] initVectorBytes = Encoding.UTF8.GetBytes(InitVector);
byte[] passwordBytes = Encoding.UTF8.GetBytes(passPhrase);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] saltValueBytes = Encoding.UTF8.GetBytes(SaltValue);
Rfc2898DeriveBytes password = new Rfc2898DeriveBytes(passwordBytes, saltValueBytes, PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged rijndaelManaged = new RijndaelManaged {Mode = CipherMode.CBC};
using (ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
encryptedText = Convert.ToBase64String(cipherTextBytes);
}
}
}
return encryptedText;
}
}
Edit:
Sani Huttunen pointed out that my static implementation above has a severe performance issue if you will be encrypting multiple pieces of data using the same password. You can read more about it here: http://jmpstart.wordpress.com/2009/09/29/proper-use-of-rfc2898derivebytes/
Edit: A non-static implementation that is much more efficient if you need to perform multiple encryptions/decryptions using the same password (~32ms original ~1ms new).
public class SimpleEncryption
{
#region Constructor
public SimpleEncryption(string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltValueBytes = Encoding.UTF8.GetBytes(SaltValue);
_DeriveBytes = new Rfc2898DeriveBytes(passwordBytes, saltValueBytes, PasswordIterations);
_InitVectorBytes = Encoding.UTF8.GetBytes(InitVector);
_KeyBytes = _DeriveBytes.GetBytes(32);
}
#endregion
#region Private Fields
private readonly Rfc2898DeriveBytes _DeriveBytes;
private readonly byte[] _InitVectorBytes;
private readonly byte[] _KeyBytes;
#endregion
private const string InitVector = "T=A4rAzu94ez-dra";
private const int PasswordIterations = 1000; //2;
private const string SaltValue = "d=?ustAF=UstenAr3B#pRu8=ner5sW&h59_Xe9P2za-eFr2fa&ePHE#ras!a+uc#";
public string Decrypt(string encryptedText)
{
byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
string plainText;
RijndaelManaged rijndaelManaged = new RijndaelManaged { Mode = CipherMode.CBC };
try
{
using (ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(_KeyBytes, _InitVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(encryptedTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
//TODO: Need to look into this more. Assuming encrypted text is longer than plain but there is probably a better way
byte[] plainTextBytes = new byte[encryptedTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
catch (CryptographicException exception)
{
plainText = string.Empty; // Assume the error is caused by an invalid password
}
return plainText;
}
public string Encrypt(string plainText)
{
string encryptedText;
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
RijndaelManaged rijndaelManaged = new RijndaelManaged {Mode = CipherMode.CBC};
using (ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor(_KeyBytes, _InitVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
encryptedText = Convert.ToBase64String(cipherTextBytes);
}
}
}
return encryptedText;
}
}
There's a complete example on MSDN, although is uses RSA and not TripleDES.