I am trying to encrypt bytes with Aes. However, the output I get is really weird. Here is my functions (encrypt and decrypt). Am I doing something wrong?
public static byte[] encryptStream(byte[] plain, byte[] Key, byte[] IV)
{
byte[] encrypted; ;
using (MemoryStream mstream = new MemoryStream())
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
using (CryptoStream cryptoStream = new CryptoStream(mstream,
aesProvider.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
cryptoStream.Write(plain, 0, plain.Length);
}
}
encrypted = mstream.ToArray();
}
return encrypted;
}
public static byte[] decryptStream(byte[] encrypted, byte[] Key, byte[] IV)
{
byte[] plain;
using (MemoryStream mStream = new MemoryStream())
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
using (CryptoStream cryptoStream = new CryptoStream(mStream,
aesProvider.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
{
cryptoStream.Read(encrypted, 0, encrypted.Length);
}
}
plain = mStream.ToArray();
}
return plain;
}
The issue is in your decryptStream() method, when you read from the cryptoStream you read INTO the encrypted buffer. When you call Read() you are already reading from the encrypted buffer because you wrapped it with the memory stream. You want to read into a NEW buffer which concatenated together will be the decrypted bytes.
public static byte[] decryptStream(byte[] encrypted, byte[] Key, byte[] IV)
{
byte[] plain;
byte[] buffer = new byte[32768];
int totalRead = 0;
MemoryStream plainStream = new MemoryStream();
using (MemoryStream mStream = new MemoryStream(encrypted))
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
using (CryptoStream cryptoStream = new CryptoStream(mStream,
aesProvider.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
{
while (true)
{
int read = cryptoStream.Read(buffer, 0, encrypted.Length);
if (read == 0)
break;
else
plainStream.Write(buffer, totalRead, read);
totalRead += read;
}
}
}
plain = plainStream.ToArray();
}
return plain;
}
Related
I'm trying to use AesCryptoProvider to encrypt and decrypt byte arrays.
Here are my encrypt and decrypt methods:
public static byte[] EncryptAes(byte[] data, out byte[] key, out byte[] iv)
{
if (data == null || data.Length <= 0)
throw new ArgumentNullException("data");
try
{
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.KeySize = 256;
aesAlg.BlockSize = 128;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.CBC;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
key = aesAlg.Key;
iv = aesAlg.IV;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, aesAlg.CreateEncryptor(), CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
}
return msEncrypt.ToArray();
}
}
}
catch (CryptographicException e)
{
Log.Error(e);
key = null;
iv = null;
return null;
}
}
public static byte[] DecryptAes(byte[] encryptedData, byte[] key, byte[] iv)
{
if (encryptedData == null || encryptedData.Length <= 0)
throw new ArgumentNullException("encryptedData");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
try
{
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.KeySize = 256;
aesAlg.BlockSize = 128;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = key;
aesAlg.IV = iv;
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
{
csDecrypt.Write(encryptedData, 0, encryptedData.Length);
}
return msDecrypt.ToArray();
}
}
}
catch (CryptographicException e)
{
Log.Error(e);
return null;
}
}
Then to test it, I'm using this code:
originalMessage = "This is a test message.";
originalData = System.Text.Encoding.UTF8.GetBytes(originalMessage);
byte[] key, iv;
byte[] encryptedData = Encryption.EncryptAes(originalData, out key, out iv);
byte[] decryptedData = Encryption.DecryptAes(encryptedData, key, iv);
string decryptedMessage = System.Text.Encoding.UTF8.GetString(decryptedData);
Log.Debug(decryptedMessage); // This is a test message.?{?o?}??
The log output shows that the decrypted message has a bunch of garbage characters "?{?o?}??" at the end.
I've seen similar questions, but their answers don't seem to help. I've tried writing to another array during decryption like this:
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] decryptedData = new byte[encryptedData.Length];
csDecrypt.Write(decryptedData, 0, decryptedData.Length);
}
return msDecrypt.ToArray();
}
But that results in this exception:
System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
So there's gotta be something I'm missing. Any ideas? Thanks!
Yeah, reusing buffers is biting you. You generally don't expect the encrypted and decrypted data to be the same sizes, so reusing a buffer causes you to see left-over encrypted data in the decrypted data.
Make your decrypt similar to encrypt. Don't pass the buffer to the constructor of MemoryStream, let it allocate a buffer of the correct size:
using (MemoryStream msDecrypt = new MemoryStream())
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt,
aesAlg.CreateDecryptor(),
CryptoStreamMode.Write))
{
csDecrypt.Write(encryptedData, 0, encryptedData.Length);
}
return msDecrypt.ToArray();
}
I've tried writing to another array during decryption like this:
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt,
aesAlg.CreateDecryptor(),
CryptoStreamMode.Write))
{
byte[] decryptedData = new byte[encryptedData.Length];
csDecrypt.Write(decryptedData, 0, decryptedData.Length);
}
return msDecrypt.ToArray();
}
No read it back to yourself. You're still configuring the cryptostream to write rather than read. What you're doing here is allocating a new buffer and then telling AES to decrypt that empty buffer into the memory stream which was initialized with the encrypted data.
My problem is the following:
I have a client/server application connected over sockets. My client´s task is to send a file byte-wise to the server. The server gets the bytes, decrypt them, send it back to the client and he writes them in a new file on disk.
I get everytime a serverside exception (System.Security.Cryptography.Exception: Padding is invalid and cannot be removed) at this line of code: plaintext = sr.ReadToEnd();
Could somebody help me to solve my problem?
Here is the decryption code:
public byte[] Dec(byte[] content, byte[] Key, byte[] IV, int fileLength, string filepath, int chunkSize, int bytesToRead)
{
byte[] contentDec;
string plaintext = null;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream ms = new MemoryStream(content))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
plaintext = sr.ReadToEnd();
cs.FlushFinalBlock();
}
contentDec = encoding.GetBytes(plaintext);
}
}
}
return contentDec;
}
Here is my encryption code:
public byte[] Enc(byte[] content,byte[] Key, byte[] IV, int fileLength,string filepath, int chunkSize, int bytesToRead)
{
byte[] contentEnc;
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(content);
}
contentEnc = ms.ToArray();
}
}
}
return contentEnc;
}
On client side I call encryption method like this
int chunkSize = 1024;
byte[] chunk = new byte[chunkSize];
using (FileStream fileReader = new FileStream(plainPath, FileMode.Open, FileAccess.Read))
using (FileStream filewriter = new FileStream(pathEncrypt, FileMode.Create, FileAccess.ReadWrite))
using (BinaryReader binaryReader = new BinaryReader(fileReader))
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
myRijndael.GenerateKey();
myRijndael.GenerateIV();
Key = myRijndael.Key;
IV = myRijndael.IV;
int bytesToRead = (int)fileReader.Length;
do
{
chunk = service.Enc(binaryReader.ReadBytes(chunkSize), Key, IV,(int)fileReader.Length,
fileReader.Name, chunkSize, bytesToRead);
filewriter.Write(chunk, 0, chunk.Length);
bytesToRead -= chunkSize;
} while (bytesToRead > 0);
}
Key and IV are declared as private byte[]
On client side I call decryption method like this
int chunkSize = 1024;
byte[] chunk = new byte[chunkSize];
using (FileStream fileReader = new FileStream(pathEncrypt, FileMode.Open, FileAccess.Read))
using (FileStream filewriter = new FileStream(pathDecrypt, FileMode.Create, FileAccess.ReadWrite))
using (BinaryReader binaryReader = new BinaryReader(fileReader))
{
int bytesToRead = (int)fileReader.Length;
do
{
chunk = service.Dec(binaryReader.ReadBytes(chunkSize), Key, IV, (int)fileReader.Length,
fileReader.Name, chunkSize, bytesToRead);
filewriter.Write(chunk, 0, chunk.Length);
bytesToRead -= chunkSize;
} while (bytesToRead > 0);
}
Edit: This is my connection establishment between client and server.
Server:
var host = new ServiceHost(typeof(Service),
new Uri("net.pipe://localhost"));
host.AddServiceEndpoint(typeof(TiService),
new NetNamedPipeBinding(), "TestService");
host.Open();
Console.WriteLine("Server connection established...");
Console.ReadKey();
Client:
var callback = new Callback();
var context = new InstanceContext(callback);
var pipeFactory =
new DuplexChannelFactory<TiService>(context,
new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/TestService"));
service = pipeFactory.CreateChannel();
service.Connect();
Your problem start from using StreamWriter in the encryption. It's meant for writing Text file, not arbitrary file. When you call sw.Write(content), it simply call content.ToString(), which return "System.Byte[]", instead what you'd probably expect, each byte of the array. To fix it, simply write the CryptoStream, no need to use StreamWriter, like this :
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(content, 0, content.Length);
}
contentEnc = ms.ToArray();
}
}
You probably noticed I used AesCng instead of RijndaelManaged. Why? Because it's much faster in my test, and unless you really need non-standard block, there's no benefit of using RijndaelManaged. Also, I use the parameterless CreateEncryptor because you already set the Key & IV on the previous lines anyway.
Same deal in the decryption. You shouldn't treat them as text, thus :
var buffer = new byte[content.Length]; //at first its size is actual size+padding
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(content))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
var actualSize = cs.Read(buffer, 0, content.Length);
//we write the decrypted content to the buffer, and get the actual size
Array.Resize(ref buffer, actualSize);
//then we resize the buffer to the actual size
}
}
}
return buffer;
Also, your usage of the Enc and Dec is needlessly complex. It's already able to handle the whole file by itself. So to encrypt the file, simply use
var original = File.ReadAllBytes("originalPath");
var enc = Enc(original, rM.Key, rM.IV);
File.WriteAllBytes("encryptedPath", enc);
And to decrypt the file, just use
var enc = File.ReadAllBytes("encryptedPath");
var dec = Dec(enc, rM.Key, rM.IV);
File.WriteAllBytes("decryptedPath", dec);
As you can see, I throw away the fileLength,filepath, chunkSize, and bytesToRead on Enc & Dec, because your current code doesn't actually use them anyway. I've tried the code with short text file on ASCII, Unicode and UTF-8, and with large binary files, all encrypted & decrypted successfully with identical hash on the final decrypted files.
Edit :
Turning the code into direct filestream writing affair actually makes everything so much simpler.
public static void Transform(string source, string target, ICryptoTransform transf)
{
var bufferSize = 65536;
var buffer = new byte[bufferSize];
using (var sourceStream = new FileStream(source, FileMode.Open))
{
using (var targetStream = new FileStream(target, FileMode.OpenOrCreate))
{
using (CryptoStream cs = new CryptoStream(targetStream, transf, CryptoStreamMode.Write))
{
var bytesRead = 0;
do
{
bytesRead = sourceStream.Read(buffer, 0, bufferSize);
cs.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
}
}
}
public static void Enc(string source, byte[] Key, byte[] IV, string target)
{
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform encryptor = rijAlg.CreateEncryptor();
Transform(source, target, encryptor);
}
}
public static void Dec(string source, byte[] Key, byte[] IV, string target)
{
using (var rijAlg = new AesCng())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
ICryptoTransform decryptor = rijAlg.CreateDecryptor();
Transform(source, target, decryptor);
}
}
Usage is :
Enc(#"originalPath", key, iv, #"encryptedPath");
Dec(#"encrypedPath", key, iv, #"decryptedPath");
This is a beginner question,
Every time I search on the internet, decrypt with DESCryptoServiceProvider function always returning a string.
How can we get byte[] for the return?
This is the code. Thank you for any help.
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
cryptoProvider.Padding = PaddingMode.None;
cryptoProvider.Mode = CipherMode.CBC;
MemoryStream memoryStream = new MemoryStream(value);
CryptoStream cryptoStream = new CryptoStream(memoryStream,
cryptoProvider.CreateDecryptor(password, initVector), CryptoStreamMode.Read);
StreamReader reader = new StreamReader(cryptoStream);
return reader.ReadToEnd();
//how to return byte[];
I had this problem too, and I created a class with some functions to help me with this issues.
The function to perform the cryptography is:
private byte[] PerformCryptography(ICryptoTransform cryptoTransform, byte[] data)
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return memoryStream.ToArray();
}
}
}
The ICryptoTransform is either a spezific encryptor or decryptor.
This Method works for symmetric altorithm's
Just for example, the methods for encryption and decryption look like:
public byte[] Encrypt(byte[] data)
{
if (CanPerformCryptography(data))
{
using (var encryptor = _algorithm.CreateEncryptor(_key, _iv))
{
return PerformCryptography(encryptor, data);
}
}
return data;
}
public byte[] Decrypt(byte[] data)
{
if (CanPerformCryptography(data))
{
using (var decryptor = _algorithm.CreateDecryptor(_key, _iv))
{
return PerformCryptography(decryptor, data);
}
}
return data;
}
I'm writing an Aes decryption method and currently, I'm stuck on trying to read all the contents inside my CryptoStream and put it all into a byte[]. This is what I have for decryption:
public byte[] GetDecrypted()
{
byte[] toReturn;
using (Aes dec = Aes.Create())
{
dec.Key = Key;
dec.IV = IV;
ICryptoTransform cryptoTransform = dec.CreateDecryptor(dec.Key, dec.IV);
using (MemoryStream ms = new MemoryStream(Data))
{
using (CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Read))
{
using (MemoryStream decMs = new MemoryStream())
{
cs.CopyTo(decMs);
toReturn = decMs.ToArray();
}
}
}
}
return toReturn;
}
For encryption, I used very similar code; maybe something's wrong here:
public byte[] GetEncrypted()
{
byte[] toReturn;
using (Aes enc = Aes.Create())
{
enc.Key = Key;
enc.GenerateIV();
IV = enc.IV;
ICryptoTransform cryptoTransform = enc.CreateEncryptor(enc.Key, enc.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
{
cs.Write(Data, 0, Data.Length);
toReturn = ms.ToArray();
}
}
}
return toReturn;
}
Your problem indeed lies in your encrypt side. You must close the crypto stream to flush the data out to the underlying stream first. It is a easy fix, just move your .ToArray() outside of CryptoStream's using block.
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
{
cs.Write(Data, 0, Data.Length);
}
toReturn = ms.ToArray();
}
I use this function to decrypt a executable file :
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) ...
But, this function return a string output I can see the ASCII output of my corresponding decrypted file. But, I need to get a byte[] output.
I have try many thing but I'm stuck: I need a DecryptBytesToBytes function
That function is proprietary - i.e. it's part of your codebase, it's certainly not part of the BCL. So I suggest you find the source code and write a new version that returns a byte array.
As a variant:
static byte[] DecryptBytesToBytes (byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
byte[] encrypted = null;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
string encrypted_text = srDecrypt.ReadToEnd();
encrypted = new byte[encrypted_text.Length * sizeof(char)];
System.Buffer.BlockCopy(encrypted_text.ToCharArray(), 0, encrypted, 0, encrypted.Length);
}
}
}
}
return encrypted;
}
The code you posted is for encrypting strings. The following code will encrypt a file and decrypt it using the file path. It will write out the file to the hard disk.
static void EncryptFile(string sInputFilename, string sOutputFilename, byte[] key, byte[] iv)
{
FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
using (AesCryptoServiceProvider encryptor = new AesCryptoServiceProvider())
{
encryptor.Key = key;
encryptor.IV = iv;
ICryptoTransform transform = encryptor.CreateEncryptor();
using (CryptoStream cryptostream = new CryptoStream(fsEncrypted, transform, CryptoStreamMode.Write))
{
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
fsInput.Close();
fsEncrypted.Close();
}
}
static void DecryptFile(string sInputFilename, string sOutputFilename, byte[] key, byte[] iv)
{
using (AesCryptoServiceProvider encryptor = new AesCryptoServiceProvider())
{
encryptor.Key = key;
encryptor.IV = iv;
using (FileStream fsread = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read))
{
using (ICryptoTransform transform = encryptor.CreateDecryptor())
{
using (CryptoStream cryptostream = new CryptoStream(fsread, transform, CryptoStreamMode.Read))
{
using (BinaryWriter fsDecrypted = new BinaryWriter(File.Open(sOutputFilename, FileMode.Create)))
{
byte[] buffer = new byte[1024];
var read = cryptostream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
fsDecrypted.Write(buffer, 0, read);
read = cryptostream.Read(buffer, 0, buffer.Length);
}
fsDecrypted.Flush();
cryptostream.Flush();
}
}
}
}
}
}
This works without all the streams:
public static Byte[] Encrypt(Byte[] input, SymmetricAlgorithm crypto)
{
return Transform(crypto.CreateEncryptor(), input, crypto.BlockSize);
}
public static Byte[] Decrypt(Byte[] input, SymmetricAlgorithm crypto)
{
return Transform(crypto.CreateDecryptor(), input, crypto.BlockSize);
}
private static Byte[] Transform(ICryptoTransform cryptoTransform, Byte[] input, Int32 blockSize)
{
if (input.Length > blockSize)
{
Byte[] ret1 = new Byte[( ( input.Length - 1 ) / blockSize ) * blockSize];
Int32 inputPos = 0;
Int32 ret1Length = 0;
for (inputPos = 0; inputPos < input.Length - blockSize; inputPos += blockSize)
{
ret1Length += cryptoTransform.TransformBlock(input, inputPos, blockSize, ret1, ret1Length);
}
Byte[] ret2 = cryptoTransform.TransformFinalBlock(input, inputPos, input.Length - inputPos);
Byte[] ret = new Byte[ret1Length + ret2.Length];
Array.Copy(ret1, 0, ret, 0, ret1Length);
Array.Copy(ret2, 0, ret, ret1Length, ret2.Length);
return ret;
}
else
{
return cryptoTransform.TransformFinalBlock(input, 0, input.Length);
}
}