There are quite a lot of similar questions on SO about this but "none" match my problem.
I a creating a file which is filled with encrypted random bytes. Then within this file at a specific location I write a few encrypted bytes. When I attempt to read in that section of bytes I get the "Length of data to decrypt is invalid".
This is the Encrypt and Decrypt Methods (found at some point on SO)
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c };
//TODO: The SALT needs to be derived and unique for each user!
internal byte[] Encrypt(byte[] plain)
{
string password = Properties.Settings.Default.PasswordOne;
MemoryStream memoryStream;
CryptoStream cryptoStream;
Rijndael rijndael = Rijndael.Create();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
rijndael.Key = pdb.GetBytes(32);
rijndael.IV = pdb.GetBytes(16);
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(plain, 0, plain.Length);
cryptoStream.Close();
return memoryStream.ToArray();
}
internal byte[] Decrypt(byte[] cipher)
{
string password = Properties.Settings.Default.PasswordOne;
MemoryStream memoryStream;
CryptoStream cryptoStream;
Rijndael rijndael = Rijndael.Create();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
rijndael.Key = pdb.GetBytes(32);
rijndael.IV = pdb.GetBytes(16);
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write);
cryptoStream.Write(cipher, 0, cipher.Length);
cryptoStream.Close();
return memoryStream.ToArray();
}
I save the new data within the first file using this
private void InsertDEFT2NameLength(FileSystemEncryption fse, string Deft2FileName, FileStream fs, StreamWriter sw)
{
string deft2NameLength = "0"; // init the length
if (DrivesLog != null) DrivesLog("Converting DEFT2 Name to Bytes");
byte[] bdeft2Name = GetBytes(Deft2FileName); // convert filename to bytes
if (DrivesLog != null) DrivesLog("Encrypting DEFT2 Name");
byte[] ebdeft2Name = fse.Encrypt(bdeft2Name); // Encrypt
if (DrivesLog != null) DrivesLog("Getting Length of Encrypted DEFT2 Name");
long ebdeft2NameLength = ebdeft2Name.LongLength; // Get Length of the Encrypted Bytes as a long
if (DrivesLog != null) DrivesLog("Converting DEFT2 Name Length to String");
string sebdeft2NameLength = ebdeft2NameLength.ToString() + "!"; // Convert Length to string Add Exclamation so we know when we have read the full length
if (DrivesLog != null) DrivesLog("Converting DEFT2 Name Length to Bytes");
byte[] bsebdeft2NameLength = GetBytes(sebdeft2NameLength); // Convert length string to bytes
if (DrivesLog != null) DrivesLog("Encrypting DEFT2 Name Length");
byte[] ebsebdeft2NameLength = fse.Encrypt(bsebdeft2NameLength); // Encrypt
if (DrivesLog != null) DrivesLog("Converting Encrypted DEFT2 Name Length to String");
deft2NameLength = GetString(ebsebdeft2NameLength); // Convert to string
if (DrivesLog != null) DrivesLog("Seeking to Correct Location");
long startPos = GenerateDEFT2LengthStartPosition();
fs.Seek(startPos, SeekOrigin.Current); // Seek to correct location
if (DrivesLog != null) DrivesLog("New Position " + startPos.ToString("N0"));
if (DrivesLog != null) DrivesLog("Writing Encrypted Name Length to New Position");
sw.Write(deft2NameLength); // Write the Encrypted length
fs.Flush(); // Flush the buffer immediately
}
I attempt to re-read in the encrypted data at that location using this method:
private long ReadDEFT2Len(string DEFT, long lenPos, FileSystemEncryption fse)
{
if (DrivesLog != null) DrivesLog("Reading DEFT2 Name Length");
StringBuilder sb = new StringBuilder();
FileStream fs = null;
StreamReader sr = null;
try
{
fs = new FileStream(DEFT, FileMode.Open, FileAccess.Read, FileShare.Read);
sr = new StreamReader(fs, Encoding.Unicode);
char[] C = new char[101];
fs.Seek(lenPos, SeekOrigin.Begin);
sr.Read(C, 0, 100);
string sC = new string(C);
byte[] bsC = GetBytes(sC);
byte[] dRes = fse.Decrypt(bsC); // This is where the Exception is thrown.
foreach(char ic in GetString(dRes))
{
if (ic == '!') break;
sb.Append(ic.ToString());
}
sr.Close();
fs.Close();
if (DrivesLog != null) DrivesLog("DEFT2 Name Length = " + sb.ToString());
return long.Parse(sb.ToString());
}
catch (Exception ex)
{
if (DrivesLog != null) DrivesLog("ERROR Reading DEFT2 Name Length " + ex.Message);
if (sr != null) sr.Close();
if (fs != null) fs.Close();
return -1;
}
}
I have saved and loaded using Unicode Encoding so that is not the problem.. any ideas on why this exception is being thrown and how to resolve it?
The Rijndael cipher only works on specific block sizes (16, 24, or 32 bytes). You're getting an exception here because the length of data you're decrypting is not an exact multiple of the block size.