Search code examples
c#vb.netencryptioncryptographyrijndael

How Can I Protect Encrypted Files From Being Corrupted Before Decryption


I am encrypting a pdf file using the Rijndael algorithm. Encryption and decryption works fine. Encryption will convert the pdf file to a file with a .key extension.

The problem is that I am able to open this file in notepad(it shows some Unicode characters) and corrupt it. Consider the scenario that:

I have opened the file and delete some characters/add Some characters and save the notepad file. If I Passed this file to the Decryption method, I will get the corrupted file as output. I know this is happening because the byteStream gets varied(padding changed)while adding or deleting the characters in the file.

Here is my question:

Is there any way to overcome this issue? In other words, disable Editing to the encrypted file?**

Following is method am using for encryption,

VB code

   Dim plainFile As String = basePath & "\cryptoText.pdf"
   Dim password As String = "somePass"
   Dim UE As New UnicodeEncoding()
   Dim key As Byte() = UE.GetBytes(password)
   Dim cryptFile As String = basePath & "\cryptoText.key"
   Dim fsCrypt As New FileStream(cryptFile, FileMode.Create)
   Dim RMCrypto As New RijndaelManaged()
   Using csKey As New CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write)
         Dim FsIn As New FileStream(plainFile, FileMode.Open)
         Dim data As Integer
         While (data = FsIn.ReadByte()) <> -1
                csKey.WriteByte(CByte(data))
         End While
         FsIn.Close()
    End Using
    fsCrypt.Close()

C# code

    string plainFile = basePath + "\\cryptoText.pdf";
    string password = "somePass";
    UnicodeEncoding UE = new UnicodeEncoding();
    byte[] key = UE.GetBytes(password);
    string cryptFile = basePath + "\\cryptoText.key";
    FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
    RijndaelManaged RMCrypto = new RijndaelManaged();
    using (CryptoStream csKey = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write)) {
        FileStream FsIn = new FileStream(plainFile, FileMode.Open);
        int data = 0;
        while ((data == FsIn.ReadByte()) != -1) {
            csKey.WriteByte(Convert.ToByte(data));
        }
        FsIn.Close();
    }
    fsCrypt.Close();

note: i have tried it both in c# and vb.net so that am tagging my question to both.


Solution

  • The answer is do two things,

    1. Encrypt,
    2. Add an HMAC to it (like SHA256 using same key), on the encrypted data, and tack it to the end of the cryptostream

    https://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha256%28v=vs.110%29.aspx

    Then when you decrypt, you

    1. Verify that HMAC is valid,
    2. IFF #1 verifies, then and only then decrypt

    Furthermore, if this is not local files but some sort of network stream, then you have to do verification in constant time - you can't use normal byte comparison functions. This is because of timing attacks. But for local files, you can do whatever comparison you like since there is no timing attacks.