C# 如何仅加密/解密一定数量的字节(文件)?

C# 如何仅加密/解密一定数量的字节(文件)?,c#,security,encryption,cryptography,partial,C#,Security,Encryption,Cryptography,Partial,我正在实现文件的加密/解密,其中只应加密一定数量的字节。 例如:我有500 MB的大文件,我只想加密(当然也要解密)2 MB的文件。 我已经实现了所有功能,加密工作正常(没有错误),但当我运行解密时,它总是抛出以下错误: System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. at System.Security.Cryptography.CapiSymmetri

我正在实现文件的加密/解密,其中只应加密一定数量的字节。 例如:我有500 MB的大文件,我只想加密(当然也要解密)2 MB的文件。

我已经实现了所有功能,加密工作正常(没有错误),但当我运行解密时,它总是抛出以下错误:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
at System.Security.Cryptography.CapiSymmetricAlgorithm.DepadBlock(Byte[] block, Int32 offset, Int32 count) at  System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at ...
然后我尝试将填充设置为
encryptor.Padding=PaddingMode.None(还尝试了PaddingMode.zero等)。使用此填充模式运行加密和解密后,解密的结果没有错误/异常,但文件的加密部分仍然加密,但略有不同。我还检查了密码是否正确

现在我没有更多的解决方案如何处理这种文件的“部分”加密。有什么想法吗?如何处理这种填充或字节

这是我的加密和解密过程代码,包含一定数量的字节(抱歉,长度太长了,但只有您知道:):

static byte[] FILE_HEADER = Encoding.Default.GetBytes("header_of_file"); //this is written to the first line of encrypted file
static long limitBytes = 4096 * 8; //limit encryption to this amount of bytes

public static bool Encrypt(string inputFilePath, string outputfilePath, string EncryptionKey)
{
int bytesRead = 1;
long byteWriteCounter = 0;
long encryptedByteCounter = 0;
byte[] blength = null;
byte[] intBytes = null;
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
blength = new byte[FILE_HEADER.Length];
long sumBytesRead = 0;

try
{
    using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
    {                    
        fsInput.Read(blength, 0, blength.Length);

        if (!blength.SequenceEqual(FILE_HEADER)) //read the FILE_HEADER - if not equal that we can encrypt otherwise is already encrypted
        {
            fsInput.Position = 0;

            using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
            {                            
                using (Aes encryptor = Aes.Create())
                {

                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);

                    using (CryptoStream cs = new CryptoStream(fsOutput, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        try
                        {

                            while (bytesRead != 0)
                            {
                                bytesRead = fsInput.Read(buffer, 0, bufferLen);
                                sumBytesRead += bytesRead;

                                if (sumBytesRead <= limitBytes) //limit encryption
                                {                                  

                                    if (bytesRead < bufferLen)
                                    {                                                   

                                        cs.Write(buffer, 0, bytesRead);
                                        encryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                        intBytes = Encoding.Default.GetBytes(encryptedByteCounter.ToString("D7"));

                                        fsOutput.Position = 0;
                                        fsOutput.Write(FILE_HEADER, 0, FILE_HEADER.Length); //we write our header to file, to know which is encrypted
                                        fsOutput.Write(intBytes, 0, intBytes.Length); //we write number of encrypted bytes next to header, for decryption to know
                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        encryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                    }
                                }
                                else //if the file is bigger than limit, we continue to write normal data (unencrypted)
                                {
                                    if (bytesRead < bufferLen)
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                        intBytes = Encoding.Default.GetBytes(encryptedByteCounter.ToString("D7"));

                                        fsOutput.Position = 0;
                                        fsOutput.Write(FILE_HEADER, 0, FILE_HEADER.Length);
                                        fsOutput.Write(intBytes, 0, intBytes.Length);
                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                    }
                                }

                            }

                        }
                        catch (SystemException se)
                        {
                            Console.WriteLine("Exception ENC: " + se);
                        }
                    }
                }
            }
            return true;

        }
        else
        {
            //file is already encrypted
            return false;
        }
    }


}
catch (SystemException se)
{

    Console.WriteLine("Main ENC exception: "+se);

    return false;
}

}
public static bool Decrypt(string inputFilePath, string outputfilePath, string EncryptionKey)
{
byte[] blength = null;
blength = new byte[FILE_HEADER.Length];
long byteWriteCounter = 0;
int bufferLen = 4096; 
byte[] buffer = new byte[bufferLen];
int bytesRead = 1;
long decryptedByteCounter = 0;
long sumBytesRead = 0;
byte[] bufferEncBytes = new byte[7];

try
{

    using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
    {

        fsInput.Read(blength, 0, blength.Length);

        if (blength.SequenceEqual(FILE_HEADER))//check if is our encrypted file
        {


            fsInput.Read(bufferEncBytes, 0, bufferEncBytes.Length);

            int numOfDecBytes = Convert.ToInt32(Encoding.Default.GetString(bufferEncBytes)); //get number of encrypted bytes

            using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
            {                   
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);                        

                    using (CryptoStream cs = new CryptoStream(fsOutput, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        try
                        {

                            while (bytesRead != 0)
                            {
                                bytesRead = fsInput.Read(buffer, 0, bufferLen);
                                sumBytesRead += bytesRead;

                                if (sumBytesRead <= numOfDecBytes) //decrypt until limit
                                {

                                    if (bytesRead < bufferLen)
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        decryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                        bytesRead = 0; //we are at the end of file, end everything
                                    }
                                    else
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        decryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;                                         
                                    }
                                }
                                else //if we have decrypted encrypted bytes, continue with rest of the (normal) data
                                {
                                    if (bytesRead < bufferLen)
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;

                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                    }
                                }

                            }

                        }
                        catch (SystemException se)
                        {
                            Console.WriteLine("Exception DECR: " + se);
                        }

                    }

                }

            }
            return true;
        }
        else
        {
            //not right file for decryption
            return false;
        }
    }

}
catch (SystemException eks)
{
    Console.WriteLine("Error: " + eks); //here the exception of Invalid Padding is thrown

    return false;
}
}
static byte[]FILE_HEADER=Encoding.Default.GetBytes(“文件头_”)//这将写入加密文件的第一行
静态长limitBytes=4096*8//将加密限制在此字节数内
公共静态布尔加密(字符串输入文件路径、字符串输出文件路径、字符串加密密钥)
{
int字节读取=1;
长字节写计数器=0;
长加密字节计数器=0;
字节[]blength=null;
字节[]intBytes=null;
int bufferLen=4096;
byte[]buffer=新字节[bufferLen];
blength=新字节[文件头.Length];
长sumBytesRead=0;
尝试
{
使用(FileStream fsInput=newfilestream(inputFilePath,FileMode.Open))
{                    
fsInput.Read(blength,0,blength.Length);
if(!blength.SequenceEqual(文件_头))//读取文件_头-如果不相等,则我们可以加密,否则已加密
{
fsInput.Position=0;
使用(FileStream fsOutput=newfilestream(outputfilePath,FileMode.Create))
{                            
使用(Aes encryptor=Aes.Create())
{
Rfc2898DeriveBytes pdb=新的Rfc2898DeriveBytes(加密密钥,新字节[]{0x49,0x76,0x61,0x6e,0x20,0x4d,0x65,0x64,0x76,0x65,0x64,0x76});
encryptor.Key=pdb.GetBytes(32);
encryptor.IV=pdb.GetBytes(16);
使用(CryptoStream cs=new CryptoStream(fsOutput,encryptor.CreateEncryptor(),CryptoStreamMode.Write))
{
尝试
{
while(字节读取!=0)
{
bytesRead=fsInput.Read(buffer,0,bufferLen);
sumBytesRead+=字节读取;

如果(sumBytesRead当您使用块密码加密时,大多数模式将添加填充。这意味着由于额外的填充,加密数据将比原始明文更长。您需要使用加密数据保留填充,否则您将得到错误的填充错误

您可以确保小心地处理填充,或者切换到CTR模式,该模式不使用填充,使密码文本的长度与明文相同


使用流密码(如Rabbit或Salsa20)也会有同样的效果。

这基本上相当于调试文件处理。假设密文与纯文本一样大是错误的。假设您读取到要加密的纯文本的末尾也是错误的。密文也可能更大总的来说,有很多错误,加密/解密方法试图做所有事情,而不是做一个好的设计。为什么你只想加密文件的一部分?这显然是不安全的。@MaartenBodewes-owlstead我知道,有很多错误,我正在开发阶段测试它是否符合我的逻辑。但是你能帮助和rovide解决方案如何实现加密字节的数量,即在解密中可以计数和解密?还是应该使用其他加密算法?@CodesInChaos我没有找到任何其他解决方案来加密大量2GB+(.iso)文件速度更快。如果你加密如此大的文件中的一小部分,总体结果是相同的-文件无法使用。@OnlyKing For DRM可能是可以接受的(无论如何它都会被破坏),对于任何与安全相关的内容,它都不是。如果只加密开始部分,有能力的攻击者将能够从该iso文件中提取大部分文件。但即使对于DRM,它也没有什么意义,因为您只需要在受IO性能限制的情况下进行动态解密,而不需要CPU解密成本。在这个c中,我如何小心处理填充ase?此算法不支持CTR模式。如果将明文大小存储在密文前面,则可以尝试实现块大小的填充(即AES为0..15字节)。在这种情况下,请确保您的缓冲区和要加密的字节数都是块大小的倍数。然后您可以使用
NoPadding
对所需的字节进行加密/解密。如果您已加密到最大值,则无需填充。在另一种情况下,您可以仅通过在缓冲区的最后部分填充零来填充。在您的情况下,我当然会考虑为明文的大小存储64位。加密并记录加密字节的大小。将这些字节准备到文件的未加密部分的前面。保持一个固定大小的记录,将密文大小设置为密文。在解密结束时,首先读取密文。大小。然后精确解密这么多字节(填充应自动消失)。将解密后的明文前置到文件未加密的其余部分。确保固定大小长度