Encrypt and Decrypt Files with Symmetric Algorithms

117 views Asked by At

i want to encrypt and decrypt files using Symmetric Algorithms. for small file there is no issue but if our file is large for example (100 mb, 1 GB, 5 GB,...) simple codes does not work and We have to use different methods to solve this problem. i used ChatGPT to Create a Encrypt and Decrypt Methods, Encrypt Method works fine and read large file without issues and encrypt and write encryped file on disk. but when i want to decrypt file, i get Com Exception in CryptographicEngine.Decrypt line. i tested for a tiny 3 kb Text file and issue exist. so i found that if encrypting file goes wrong decryption will be failed. so what is wrong with my encrypt method? how to fix this?

public static async Task EncryptFileAsync(string inputFile, string outputFile)
{
    var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
    var keyMaterial = CryptographicBuffer.GenerateRandom(provider.BlockLength);
    var iv = CryptographicBuffer.GenerateRandom(provider.BlockLength);

    var key = provider.CreateSymmetricKey(keyMaterial);
    const int bufferSize = 4096; // Choose an appropriate buffer size

    var file = await StorageFile.GetFileFromPathAsync(inputFile);

    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
    {
        using (IInputStream inputStream = stream.GetInputStreamAt(0))
        {
            using (DataReader dataReader = new DataReader(inputStream))
            {
                using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                {
                    while (stream.Position < stream.Size)
                    {
                        dataReader.InputStreamOptions = InputStreamOptions.Partial;
                        uint bytesRead = await dataReader.LoadAsync(bufferSize);

                        if (bytesRead > 0)
                        {
                            // Convert the buffer to IBuffer
                            IBuffer buffer = dataReader.ReadBuffer(bytesRead);
                            IBuffer bufferEncrypt = CryptographicEngine.Encrypt(key, buffer, iv);
                            var byteArray = bufferEncrypt.ToArray();

                            await fs.WriteAsync(byteArray, 0, byteArray.Length);

                            // Your processing logic with the IBuffer goes here
                        }
                        else
                        {
                            // Break the loop if no more bytes can be read
                            break;
                        }
                    }
                }
            }
        }
    }

    // Save the key and iv for later decryption
    SaveKeyAndIV(keyMaterial, iv);
}

public static async Task DecryptFileAsync(string inputFile, string outputFile)
{
    // Load the key and iv used for encryption
    var (keyMaterial, iv) = LoadKeyAndIV();

    var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
    var key = provider.CreateSymmetricKey(keyMaterial);
    const int bufferSize = 4096; // Choose an appropriate buffer size

    var file = await StorageFile.GetFileFromPathAsync(inputFile);

    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
    {
        using (IInputStream inputStream = stream.GetInputStreamAt(0))
        {
            using (DataReader dataReader = new DataReader(inputStream))
            {
                using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                {
                    while (stream.Position < stream.Size)
                    {
                        dataReader.InputStreamOptions = InputStreamOptions.Partial;
                        uint bytesRead = await dataReader.LoadAsync(bufferSize);

                        if (bytesRead > 0)
                        {
                            // Convert the buffer to IBuffer
                            IBuffer buffer = dataReader.ReadBuffer(bytesRead);
                            IBuffer bufferDecrypt = CryptographicEngine.Decrypt(key, buffer, iv);

                            // Convert the decrypted buffer to byte array
                            var decryptedBytes = bufferDecrypt.ToArray();

                            await fs.WriteAsync(decryptedBytes, 0, decryptedBytes.Length);

                            // Your processing logic with the decrypted data goes here
                        }
                        else
                        {
                            // Break the loop if no more bytes can be read
                            break;
                        }
                    }
                }
            }
        }
    }
}
1

There are 1 answers

2
Miles On

When you put 'try catch blocks' around parts of code, you can find out more clearly where errors are coming from. This is how they work in C#.

For the encription method:

public static async Task EncryptFileAsync(string inputFile, string outputFile)
{
    try
    {
        var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
        var keyMaterial = CryptographicBuffer.GenerateRandom(provider.BlockLength);
        var iv = CryptographicBuffer.GenerateRandom(provider.BlockLength);

        var key = provider.CreateSymmetricKey(keyMaterial);
        const int bufferSize = 4096; // Choose an appropriate buffer size

        var file = await StorageFile.GetFileFromPathAsync(inputFile);

        using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
        {
            using (IInputStream inputStream = stream.GetInputStreamAt(0))
            {
                using (DataReader dataReader = new DataReader(inputStream))
                {
                    using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                    {
                        while (stream.Position < stream.Size)
                        {
                            dataReader.InputStreamOptions = InputStreamOptions.Partial;
                            uint bytesRead = await dataReader.LoadAsync(bufferSize);

                            if (bytesRead > 0)
                            {
                                IBuffer buffer = dataReader.ReadBuffer(bytesRead);
                                IBuffer bufferEncrypt = CryptographicEngine.Encrypt(key, buffer, iv);
                                var byteArray = bufferEncrypt.ToArray();

                                await fs.WriteAsync(byteArray, 0, byteArray.Length);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }

        SaveKeyAndIV(keyMaterial, iv);
    }
    catch (Exception ex)
    {
        // Handle the exception
        Console.WriteLine($"Encryption failed with exception: {ex.Message}");
    }
}

For the decryption method:

public static async Task DecryptFileAsync(string inputFile, string outputFile)
{
    try
    {
        var (keyMaterial, iv) = LoadKeyAndIV();

        var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
        var key = provider.CreateSymmetricKey(keyMaterial);
        const int bufferSize = 4096; // Choose an appropriate buffer size

        var file = await StorageFile.GetFileFromPathAsync(inputFile);

        using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
        {
            using (IInputStream inputStream = stream.GetInputStreamAt(0))
            {
                using (DataReader dataReader = new DataReader(inputStream))
                {
                    using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                    {
                        while (stream.Position < stream.Size)
                        {
                            dataReader.InputStreamOptions = InputStreamOptions.Partial;
                            uint bytesRead = await dataReader.LoadAsync(bufferSize);

                            if (bytesRead > 0)
                            {
                                IBuffer buffer = dataReader.ReadBuffer(bytesRead);
                                IBuffer bufferDecrypt = CryptographicEngine.Decrypt(key, buffer, iv);
                                var decryptedBytes = bufferDecrypt.ToArray();

                                await fs.WriteAsync(decryptedBytes, 0, decryptedBytes.Length);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        // Handle the exception
        Console.WriteLine($"Decryption failed with exception: {ex.Message}");
    }
}