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();
}
Related
take a look at this to methods:
public void CompressAndEncrypt(Stream input, Stream output)
{
Aes aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
aes.Padding = PaddingMode.PKCS7;
aes.BlockSize = 128;
ICryptoTransform aesEncryptor = aes.CreateEncryptor();
using (CryptoStream cryptoStream = new(output, aesEncryptor, CryptoStreamMode.Write))
using (GZipStream compressedStream = new(cryptoStream, CompressionLevel.SmallestSize))
{
input.CopyTo(compressedStream);
cryptoStream.FlushFinalBlock();
}
}
and
public void DecryptAndDecompress(Stream input, Stream output)
{
Aes aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
aes.Padding = PaddingMode.PKCS7;
aes.BlockSize = 128;
ICryptoTransform aesDecryptor = aes.CreateDecryptor();
using (CryptoStream cryptoStream = new(input, aesDecryptor, CryptoStreamMode.Read))
using (GZipStream decompressedStream = new(cryptoStream, CompressionMode.Decompress))
{
decompressedStream.CopyTo(output);
}
}
The input and output Stream can be considered as FileStream. As you can see, the first method compresses and encrypt a Stream, while the second method decrypts and decompress a Stream.
The first method works fine, but if a take the result of the first method and pass it to the second, .NET says:
System.IO.InvalidDataException. "The archive entry was compressed using an unsupported compression method."
Any suggestion?
I suspect that the problem is with cryptoStream.FlushFinalBlock(); before disposing/flushing the compression stream. This slightly altered example works for me:
[Test]
public void EncryptDecrypt()
{
var source = new MemoryStream();
var data = new byte[] {42, 3, 5, 100, 255, 100, 255, 100, 255, 100, 255, 100, 255, 100, 255, 100, 255};
source.Write(data, 0, data.Length);
source.Position = 0;
var encrypted = new MemoryStream();
var (key, iv) = CompressAndEncrypt(source, encrypted);
var result = new MemoryStream();
encrypted.Position = 0;
DecryptAndDecompress(encrypted, result, key, iv);
result.Position = 0;
var resultData = new byte[data.Length];
result.Read(resultData, 0, resultData.Length);
CollectionAssert.AreEquivalent(data, resultData);
}
public (byte[] key, byte[] Iv) CompressAndEncrypt(Stream input, Stream output)
{
Aes aes = Aes.Create("AesManaged");
aes.GenerateIV();
aes.GenerateKey();
aes.Padding = PaddingMode.PKCS7;
aes.BlockSize = 128;
ICryptoTransform aesEncryptor = aes.CreateEncryptor();
using CryptoStream cryptoStream = new(output, aesEncryptor, CryptoStreamMode.Write, true);
using GZipStream compressedStream = new(cryptoStream, CompressionLevel.Optimal, true);
input.CopyTo(compressedStream);
return (aes.Key, aes.IV);
}
public void DecryptAndDecompress(Stream input, Stream output, byte[] key, byte[] iv)
{
Aes aes = Aes.Create("AesManaged");
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.PKCS7;
aes.BlockSize = 128;
ICryptoTransform aesDecryptor = aes.CreateDecryptor();
using CryptoStream cryptoStream = new(input, aesDecryptor, CryptoStreamMode.Read, true);
using GZipStream decompressedStream = new(cryptoStream, CompressionMode.Decompress, true);
decompressedStream.CopyTo(output);
}
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?
I want to encrypt a string using AES 256-bit encryption algorithm with ECB and PKCS7Padding. I had gone through many sites but none of them were suitable.
Please suggest a solution
public static string Encrypt(string PlainText, string Password,
string Salt = "Kosher", string HashAlgorithm = "SHA1",
int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
int KeySize = 256)
{
if (string.IsNullOrEmpty(PlainText))
return "";
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
byte[] CipherTextBytes = null;
using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
{
using (MemoryStream MemStream = new MemoryStream())
{
using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
{
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
}
}
}
SymmetricKey.Clear();
return Convert.ToBase64String(CipherTextBytes);
}
source
Note: you can change the mode by changing SymmetricKey.Mode = CipherMode.CBC;
and you can add SymmetricKey.Padding = PaddingMode.PKCS7; for padding
with bounty castle you should be able to do this :
cipher = CipherUtilities.GetCipher("AES/ECB/PKCS7");
cipher.Init(false, new KeyParameter(key));
Please help me modify this code to encrypt/decrypt in blocks instead of huge byte arrays! the code that converts the file and calls the encryption class is:
Console.Write("Enter File Path: ");
docPath = Console.ReadLine();
extension = docPath.Substring(docPath.IndexOf(".")).Trim();
byte[] binarydata = File.ReadAllBytes(docPath);
text = System.Convert.ToBase64String(binarydata, 0, binarydata.Length);
var Encrypted = AESCryptography.Encrypt(text, m.ToString(), extension);
using (FileStream fs = File.Create(docPath.Substring(0,docPath.IndexOf(".")) + ".aent"))
{
Byte[] info = new UTF8Encoding(true).GetBytes(Encrypted);
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
And the class that does the actual encryption is this:
public static class AESCryptography
{
private const int keysize = 256;
public static string Encrypt(string plainText, string passPhrase, string extention)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.GenerateIV();
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, symmetricKey.IV))
{
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();
return Convert.ToBase64String(cipherTextBytes) + "\n" + Convert.ToBase64String(symmetricKey.IV) + "\n" + extention;
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase, string initVector)
{
byte[] initVectorBytes = Convert.FromBase64String(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
}
I need the encryption class to be able to encrypt files as big as ~2.5GB.
I have tried multiple times, most didn't work others didn't even encrypt!
Please Help! I need to present this tomorrow!
You can 'chain' streams to encrypt large files, so you don't need to hold them in memory.
See answer from anton-gogolev https://stackoverflow.com/a/38629596/1776231 for question AES-Encrypt-then-MAC a large file with .NET
using(var encryptedFileStream = File.OpenWrite("..."))
using(var macCryptoStream = new CryptoStream(encryptedFileStream, mac, CryptoStreamMode.Write))
using(var encryptCryptoStream = new CryptoStream(macCryptoStream, encryptor, CryptoStreamMode.Write))
using(var inputFileStream = File.OpenRead("..."))
inputFileStream.CopyTo(encryptCryptoStream);
public static byte[] AES_Encrypt(byte[] data, string[] aes_key)
{
var aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.Default.GetBytes(aes_key[0]);
aes.IV = Encoding.Default.GetBytes(aes_key[1]);
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
public static byte[] AES_Decrypt(byte[] data, string[] aes_key)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.Default.GetBytes(aes_key[0]);
aes.IV = Encoding.Default.GetBytes(aes_key[1]);
var decrypt = aes.CreateDecryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
Somewhere in code:
string key = "788b0adbcf8b9211282fe613b18630d2";
string iv = "7fbb16b806fcc24396653b3218552d39";
byte[] test_byte = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] enc_byte = AES_Encrypt(test_byte, new string[] { key, iv }); //getting zero array
byte[] dec_byte = AES_Decrypt(enc_byte, new string[] { key, iv });
You need using blocks around your streams to ensure they are closed and flushed. Try this:
public static byte[] AES_Encrypt(byte[] data, string[] aes_key)
{
var aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.Default.GetBytes(aes_key[0]);
aes.IV = Encoding.Default.GetBytes(aes_key[1]);
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
using(MemoryStream ms = new MemoryStream())
{
using(CryptoStream cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
}
public static byte[] AES_Decrypt(byte[] data, string[] aes_key)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.Default.GetBytes(aes_key[0]);
aes.IV = Encoding.Default.GetBytes(aes_key[1]);
var decrypt = aes.CreateDecryptor();
using(MemoryStream ms = new MemoryStream())
{
using(CryptoStream cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
}
If you use using statements with your CryptoStreams, it will flush and close so that it actually updates your MemoryStreams. The documentation for CryptoStream documents this behavior: you should always Close when you're done writing to it. Here's how that looks (very similar for encrypt and decrypt):
using (CryptoStream cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
cs.Write(data, 0, data.Length);
return ms.ToArray();
Call FlushFinalBlock before converting the stream to array.