I am trying to encrypt and decrypt a file. The file can be any file like txt, jpg, doc, pdf.
The IV is prepended to the cipher text. but while decrypting if i read first 8 bytes it gives me different value then the value of IV while encryption.
Here is my code to encrypt the file
fsOut = new FileStream(savepath, FileMode.OpenOrCreate, FileAccess.Write);
des = new DESCryptoServiceProvider();
des.Key = ASCIIEncoding.ASCII.GetBytes(secretkey);
des.GenerateIV();
desencrypt = des.CreateEncryptor();
cryptoStream = new CryptoStream(fsOut, desencrypt, CryptoStreamMode.Write);
//write the IV to beginning of encrypted data
BinaryWriter bw = new BinaryWriter(cryptoStream);
bw.Write(des.IV, 0, des.IV.Length);
// Now will initialize a buffer and will be
// processing the input file in chunks.
// This is done to avoid reading the whole file (which can be
// huge) into memory.
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
do
{
// read a chunk of data from the input file
bytesRead = filestream.Read(buffer, 0, bufferLen);
// Encrypt it
cryptoStream.Write(buffer, 0, bytesRead);
}
while (bytesRead != 0);
cryptoStream.FlushFinalBlock();
This produces an encrypted file to the specified location.
Now below is my decryption code
des = new DESCryptoServiceProvider();
des.Key = Encoding.ASCII.GetBytes(secretkey);
byte[] iv = new byte[8];
sourcefile.Read(iv, 0, 8);
des.IV = iv;
desdecrypt = des.CreateDecryptor();
msOut = new MemoryStream();
cryptoStream = new CryptoStream(sourcefile, desdecrypt, CryptoStreamMode.Read);
StreamWriter fsDecrypted = new StreamWriter("D:\\tempDecrypted.jpg");
fsDecrypted.Write(new StreamReader(cryptoStream).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
You are writing your IV to the CryptoStream so it will be transformed to ciphertext. The IV should be prepended to the ciphertext in plain, it should not be part of the ciphertext.
Related
i need to converting Byte() to stream then flush
its in asp.net application
here is my code :
Dim fileBytes As Byte() = Nothing
....
apiProp.BodyRequest = New JavaScriptSerializer().Serialize(entFile)
apiProp.EndPoint = "example.com/DownloadFile"
apiProp = api.MessageInvoke(apiProp)
entResponse = JsonConvert.DeserializeObject(Of FileResponse)(apiProp.BodyResponse)
fileBytes = Convert.FromBase64String(entFile.fileContent)
i've tried :
Response.BinaryWrite(fileBytes)
Response.Flush()
and i've tried any filestream, memorystream etc. the file ask to download, but if i download the file, the file get corrupted
i need the file converted to stream because i have to add the watermark on the image file. im using groupdocs.watermark for adding the watermark.
using (Stream InputStream = fl.PostedFile.InputStream)
{
Object o = new object();
lock (o)
{
byte[] buffer = new byte[InputStream.Length];
InputStream.Read(buffer, 0, (int)InputStream.Length);
lock (o)
{
File.WriteAllBytes(rpath, buffer);
buffer = null;
}
InputStream.Close();
}
}
I am trying to use AesCryptoServiceProvider to achieve the same encryption mechanism as Aes.
Here is my AesCryptoServiceProvider version of it:
public string version1(string plainText, string encryptionKey, string initializationVector)
{
AesCryptoServiceProvider provider = new AesCryptoServiceProvider
{
BlockSize = 128,
Padding = PaddingMode.PKCS7,
Key = Convert.FromBase64String(encryptionKey),
IV = Encoding.UTF8.GetBytes(initializationVector)
};
byte[] buffer = Encoding.ASCII.GetBytes(plainText);
byte[] encrypted = provider.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length);
return Convert.ToBase64String(encrypted);
}
And here is the Aes version of it:
public string version2(string plainText, string encryptionKey, string initializationVector)
{
byte[] clearBytes = Encoding.UTF8.GetBytes(plainText);
byte[] encryptedBytes;
byte[] iv = Encoding.UTF8.GetBytes(initializationVector);
using (Aes aes = Aes.Create())
{
aes.BlockSize = 128;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Convert.FromBase64String(encryptionKey);
aes.IV = iv;
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
encryptedBytes = ms.ToArray();
}
}
byte[] ivEncryptedBytes = new byte[iv.Length + encryptedBytes.Length];
Buffer.BlockCopy(iv, 0, ivEncryptedBytes, 0, iv.Length);
Buffer.BlockCopy(encryptedBytes, 0, ivEncryptedBytes, iv.Length, encryptedBytes.Length);
return Convert.ToBase64String(ivEncryptedBytes);
}
When I encrypt the same string using version1 and version2 they came out to be different. Any idea on how these two methods are different and how I can make version1 produces the same encrypted string as version2? (p.s. I am rather new to encryption so sorry if the answer is obvious) Thanks!
As #MichaelFehr pointed out, version2 only has the initialization vector and the encrypted bytes concatenated together before converting the bytes back to string. I have tested that if I concatenate the string the same way as version2 in version1, the result string will become the same.
With an AES key that I retrieve from a Key Vault I'm trying to decrypt a blob file. But I keep getting:
System.Security.Cryptography.CryptographicException: Specified key is
not a valid size for this
I'm trying to reverse engineer a python decrypt situation and this suggests to me that the value I'm retrieving from the key vault is a hex string or at least should be stored as hexstrings in a bytearray.
Python:
aes_key= bytes.fromhex(aes_key)
So because I get it from my configuration with var keyStringValue = _configuration.GetValue<string>("the-key-i-want"); I first convert to a bytearray to be able to convert it to hexstring. And then put it in a bytearray again.
//Where I convert my Keyvault keyStringValue to a hexString encoded bytearray
byte[] tempBytes = utf8.GetBytes(keyStringValue);
var hexString = BitConverter.ToString(tempBytes);
hexString = hexString.Replace("-", "").ToLower();
int NumberChars = hexString.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
byte[] pass = bytes;
I pass the pass variable to my decrypt function which looks like this:
var crypto = new AesCryptographyService();
var decryptedData = crypto.Decrypt(postSplitByteArray, pass, iv)
And finally my decrypt:
public class AesCryptographyService
{ public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
using var aes = Aes.Create();
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
aes.Key = key;
aes.IV = iv;
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
{
return PerformCryptography(data, decryptor);
}
}
private byte[] PerformCryptography(byte[] data, ICryptoTransform cryptoTransform)
{
using (var ms = new MemoryStream())
using (var cryptoStream = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ms.ToArray();
}
}
The hexstring is 128 characters long. And the resultant bytearray 64. Now I know that the array should only be 32 bytes big. But I can't see the point of just cutting my key to size. Nor do I get a properly decrypted result. This bugs me since the python function seems to be doing the same as I am.
cipher = AES.new(aes256_key, AES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(encrypted_data).decode('utf-8')
PS. I verified with an online converter that the conversion from string to hexstring is going well.
The solution was to not first convert my string into a bytearray and then do a hexstring conversion.
The string in the keyvault was already a "hexstring"
So getting rid of this.
byte[] tempBytes = utf8.GetBytes(keyStringValue);
var hexString = BitConverter.ToString(tempBytes);
hexString = hexString.Replace("-", "").ToLower();
And from
var keyStringValue = _configuration.GetValue<string>("the-key-i-want")
pass that to the hexstring conversion
private static byte[] FromHex(string keyStringValue)
{
int NumberChars = keyStringValue.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(keyStringValue.Substring(i, 2), 16);
return bytes;
}
And Bob is your uncle.
if I try to explain why I need to do what I'm trying to do it will take a long time, but basically it's this: I have FileUpload control for the user to choose a Jpeg file, I make the upload and after it I want to convert that file to bytes and use it as the source of an Image control.
My code is this one:
string fileName = Server.MapPath("~/TempImages") + #"\foto.jpg";
fileUpload1.SaveAs(fileName);
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
fs.Close();
fs.Dispose();
string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
The byte array is looking ok, but when I convert it to string it's full of unrecognized characters, I have another page where I do the same thing but instead of getting the bytes from the file I get it from a MySql database and using the same System.Text.Encoding.UTF8.GetString and it works withou a problem.
UPDATE
As asked, this is the code I use when retrieving the from the MySql database:
DataView dv = (DataView)SqlDataSource3.Select(DataSourceSelectArguments.Empty);
byte[] buffer = (byte[])dv.Table.Rows[0]["BIN_FOTO"];
string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
The select of this SqlDataSource3 is a simple Select BIN_FOTO from temp_image. I store this value in the database from a webcam capture WPF program, the code I use to convert the image the webcam captured is:
private string ImageToBase64String(System.Drawing.Image imageData, ImageFormat format)
{
string base64;
MemoryStream memory = new MemoryStream();
imageData.Save(memory, format);
base64 = System.Convert.ToBase64String(memory.ToArray());
memory.Close();
memory.Dispose();
return base64;
}
Then I save the base64 variable to the database.
Hope this clarifies my problem
So you want to read the image file and convert to base 64. After your reading code, do this:
string valor = Convert.ToBase64String(buffer);
Your original code was flawed because you're saving the image, as bytes, to the file with this line of code:
fileUpload1.SaveAs(fileName);
That's not saved as base64, so you have to convert it to base 64 after you read it. Your MySql reading worked because the data was converted to base64 before being saved.
By the way, there's no need for the BinaryReader in this code:
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
fs.Close();
fs.Dispose();
You can write this instead:
byte[] buffer;
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)
{
long byteLength = fs.Length;
buffer = new byte[byteLength];
int bytesRead = fs.Read(buffer, 0, byteLength);
// optional error check to see that you got all the bytes
if (bytesRead != byteLength)
{
// handle error
}
}
string valor = Convert.ToBase64String(buffer);
I've found the problem, looking at the WPF code I used to convert the image to a Base64String. I just created the same function ImageToBase64String and now it works:
string fileName = Server.MapPath("~/TempImages") + #"\foto.jpg";
fileUpload1.SaveAs(fileName);
System.Drawing.Image teste = System.Drawing.Image.FromFile(fileName);
string valor = ImageToBase64String(teste, System.Drawing.Imaging.ImageFormat.Jpeg);
//System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
//System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
//long byteLength = new System.IO.FileInfo(fileName).Length;
//byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
//buffer = File.ReadAllBytes(fileName);
//fs.Close();
//fs.Dispose();
//string valor = System.Text.Encoding.UTF8.GetString(buffer);
img.ImageUrl = "data:image/jpg;base64," + valor;
But I still don't know what was wrong with my previous code, anyone can clarify?
This solution worked for me:
System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(fs);
//Add this--------------------
fs.Seek(0, SeekOrigin.Begin);
//----------------------------
long byteLength = new System.IO.FileInfo(fileName).Length;
byte[] buffer = binaryReader.ReadBytes((Int32)byteLength);
Just add highlighted line.
I have a decrypted XML string which was sent over the wire to the receiving box where my code resides. Now, I want to write this XML string to an XML file.
Here's the Decrypt method which my code calls to generate this XML string... maybe this needs to be changed?
[Update]: My problem is that I can't see a way to write/create an XML file from a string of XML... I can see samples using a stream, a URL, but that doesn't help me here.
protected string DecryptForm(byte[] encryptedString, byte[] key, byte[] vector)
{
rijndael = new RijndaelManaged();
rijndael.Mode = CipherMode.CBC;
// Create a decryptor to perform the stream transform
ICryptoTransform decryptor = rijndael.CreateDecryptor(key, vector);
string plainText = null;
try
{
//Create the streams used for decryption
using (MemoryStream msStream = new MemoryStream(encryptedString))
{
using (CryptoStream csStream = new CryptoStream(msStream,
decryptor, CryptoStreamMode.Read))
{
using (StreamReader readerStream = new StreamReader(csStream))
{
// Read the decrypted bytes from the decrypting stream
plainText = readerStream.ReadToEnd();
}
}
}
finally
{
// Clear the RijndaelManaged object
if(rijndael != null)
rijndael.Clear();
}
// Return the decrypted string
return plainText;
}
}
xmlDoc = new XmlDocument();
xmlDoc.LoadXML(MyXMLString);
xmlDoc.Save(MyFilePath)