Modern String Encryption and Decryption in C# Using AES

Oct 31, 2025 · Programming · 15 views · 7.8

Keywords: C# | Encryption | AES | String | Security

Abstract: This article explores a modern approach to encrypting and decrypting strings in C# using the AES algorithm with PBKDF2 key derivation. It provides a detailed analysis of symmetric encryption principles, the use of random salt and initialization vectors, complete code examples, and security considerations to help developers simplify encryption processes while ensuring data security. Based on high-rated Stack Overflow answers and supplemented by reference articles, it emphasizes practicality and rigor.

Introduction

In modern software development, data security is a critical aspect. Encryption techniques protect sensitive information from unauthorized access. C#, as a widely used programming language, offers robust cryptographic library support. This article introduces a simple and secure method for string encryption and decryption using the AES (Advanced Encryption Standard) algorithm combined with PBKDF2 key derivation, avoiding complex low-level operations and enabling quick integration into projects.

Background on Encryption

Encryption algorithms are broadly categorized into symmetric, asymmetric, and hashing methods. Symmetric encryption uses the same key for both encryption and decryption, making it suitable for data protection scenarios. AES is an international standard symmetric algorithm known for its high security and efficiency. In C#, the System.Security.Cryptography namespace provides AES implementations, and key derivation functions like PBKDF2 can generate secure encryption keys from user-provided passwords.

Implementation Details

This implementation utilizes the AES algorithm with random salt and initialization vector (IV) to enhance security. Salt and IV are randomly generated for each encryption and appended to the ciphertext, ensuring that the same plaintext and password produce different ciphertexts. The key is derived from the password using PBKDF2 with 1000 iterations to resist brute-force attacks. The code is encapsulated in a static class, offering simple Encrypt and Decrypt methods that abstract away byte array and stream operations.

Code Example

The following is a rewritten StringCipher class based on a deep understanding of AES and PBKDF2. It uses the Aes class instead of RijndaelManaged to align with modern standards. During encryption, random salt and IV are generated, the key is derived, and encryption is performed; during decryption, salt and IV are extracted from the ciphertext to re-derive the key for decryption. The example code ensures thread safety and proper resource disposal.

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

public static class StringCipher
{
    private const int Keysize = 256; // Key size in bits
    private const int DerivationIterations = 1000; // PBKDF2 iteration count

    public static string Encrypt(string plainText, string passPhrase)
    {
        // Generate random salt and IV
        var saltStringBytes = GenerateRandomBytes(32); // 32-byte salt
        var ivStringBytes = GenerateRandomBytes(16); // 16-byte IV
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8); // Derive key
            using (var aes = Aes.Create())
            {
                aes.Key = keyBytes;
                aes.IV = ivStringBytes;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                using (var encryptor = aes.CreateEncryptor())
                using (var memoryStream = new MemoryStream())
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    var cipherTextBytes = memoryStream.ToArray();
                    // Combine salt, IV, and ciphertext
                    var resultBytes = saltStringBytes.Concat(ivStringBytes).Concat(cipherTextBytes).ToArray();
                    return Convert.ToBase64String(resultBytes);
                }
            }
        }
    }

    public static string Decrypt(string cipherText, string passPhrase)
    {
        var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
        // Extract salt, IV, and ciphertext
        var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(32).ToArray();
        var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(32).Take(16).ToArray();
        var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip(48).ToArray();

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var aes = Aes.Create())
            {
                aes.Key = keyBytes;
                aes.IV = ivStringBytes;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                using (var decryptor = aes.CreateDecryptor())
                using (var memoryStream = new MemoryStream(cipherTextBytes))
                using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }
    }

    private static byte[] GenerateRandomBytes(int length)
    {
        var randomBytes = new byte[length];
        using (var rng = new RNGCryptoServiceProvider())
        {
            rng.GetBytes(randomBytes);
        }
        return randomBytes;
    }
}

Usage example: In a console application, users input a password and string, then call the Encrypt and Decrypt methods. For instance, with password "myPassword" and string "Hello World", encryption outputs a Base64 string, and decryption restores the original string.

Security Analysis

This implementation provides basic privacy protection but is unauthenticated, potentially vulnerable to tampering. In practical applications, if authenticated encryption is needed, consider using HMAC or AEAD modes. The use of random salt and IV increases entropy, preventing pattern recognition attacks. Developers should adjust iteration counts and key sizes based on specific scenarios to balance security and performance. Referencing other answers and articles, thorough testing and review are recommended for production environments.

Conclusion

By employing the AES algorithm and PBKDF2 key derivation, this method achieves simple and secure string encryption and decryption. The code abstracts underlying complexities, allowing developers to apply it quickly. Future work could extend to support asynchronous operations or integrate more advanced encryption modes for enhanced security and flexibility.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.