Information Security 21 min read

Symmetric Encryption Algorithms in .NET Core Using BouncyCastle

This article introduces symmetric encryption algorithms such as DES, 3DES, and AES, explains their principles, advantages and drawbacks, and provides complete .NET Core sample code using the BouncyCastle library for encryption and decryption with various padding modes.

Fulu Network R&D Team
Fulu Network R&D Team
Fulu Network R&D Team
Symmetric Encryption Algorithms in .NET Core Using BouncyCastle

Introduction

The series was created to address the current state of encryption, including compatibility across Linux and Windows, language interoperability (C#, Java, etc.), inconsistent online resources, and the incompleteness of .NET's built‑in cryptographic algorithms.

System environment compatibility (Linux, Windows)

Language interoperability (e.g., C#, Java) – encryption itself is language‑agnostic.

Online documentation is often outdated or incomplete.

.NET official libraries do not provide a full set of algorithms, making cross‑language adaptation difficult.

This series explains how to use asymmetric encryption, encoding, hash, signature, symmetric encryption, and national‑standard algorithms in .NET Core, and invites readers to point out any mistakes.

The goal is to help readers quickly and easily understand encryption integration and to combine algorithms from the BouncyCastle cryptographic package.

Project repository: https://github.com/fuluteam/ICH.BouncyCastle.git

Previous article: .NET Core Encryption Series – Message Digest and Digital Signature Algorithms

Functional Dependency

BouncyCastle ( https://www.bouncycastle.org/csharp ) is an open‑source lightweight cryptographic library that supports many algorithms not available in the standard .NET Core libraries.

Supported platforms: .NET 4, .NET Standard 1.0‑2.0, WP, Silverlight, MonoAndroid, Xamarin.iOS, .NET Core.

Feature

Dependency

Portable.BouncyCastle

Portable.BouncyCastle • 1.8.5

Symmetric Encryption Algorithms

Algorithm Overview

Symmetric encryption is an early and mature technology where the sender encrypts plaintext with a secret key, producing ciphertext. The receiver must possess the same key to decrypt the data, meaning both parties share a single secret key that must be exchanged securely beforehand.

Common algorithms include DES, 3DES, TDEA, Blowfish, RC5, IDEA, with the most widely used being DES, AES, and 3DES.

Algorithm Characteristics

Symmetric algorithms are public, have low computational overhead, and provide fast encryption with high efficiency.

However, because both parties use the same key, key management becomes a major challenge, especially in large distributed systems where the number of keys grows exponentially.

Key management complexity and the lack of built‑in signing capabilities limit the use of symmetric algorithms compared to asymmetric ones.

Despite these drawbacks, symmetric encryption offers high speed and strong resistance to brute‑force attacks when long keys are used.

Common Symmetric Algorithms

DES

DES (Data Encryption Standard) was introduced in 1976, uses a 56‑bit key, and is based on the Feistel structure. It is no longer considered secure due to its short key length and has been replaced by AES.

3DES

3DES (also known as TDEA) applies the DES algorithm three times to each data block, providing stronger security than DES. It has been deprecated in many standards (e.g., TLS 1.3) because of vulnerabilities such as the Sweet32 attack.

AES

AES (Advanced Encryption Standard), also known as Rijndael, was approved by NIST in 2001 and supports key sizes of 128, 192, and 256 bits. It is the most widely used symmetric algorithm today, employed in Wi‑Fi security, SSL/TLS, file encryption, VPNs, and many government systems.

Sample Code

Cipher Algorithm Constants

public class Algorithms
{
    public const string AES_CBC_NoPadding = "AES/CBC/NoPadding";
    public const string AES_CBC_PKCS7Padding = "AES/CBC/PKCS7Padding";
    public const string AES_CBC_ZerosPadding = "AES/CBC/ZerosPadding";
    public const string AES_CBC_ANSIX923Padding = "AES/CBC/ANSIX923Padding";
    public const string AES_CBC_ISO10126Padding = "AES/CBC/ISO10126Padding";
    
    public const string AES_ECB_NoPadding = "AES/ECB/NoPadding";
    public const string AES_ECB_PKCS7Padding = "AES/ECB/PKCS7Padding";
    public const string AES_ECB_ZerosPadding = "AES/ECB/ZerosPadding";
    public const string AES_ECB_ANSIX923Padding = "AES/ECB/ANSIX923Padding";
    
    public const string AES_ECB_ISO10126Padding = "AES/ECB/ISO10126Padding";
    
    public const string AES_OFB_NoPadding = "AES/OFB/NoPadding";
    public const string AES_OFB_PKCS7Padding = "AES/OFB/PKCS7Padding";
    public const string AES_OFB_ZerosPadding = "AES/OFB/ZerosPadding";
    public const string AES_OFB_ANSIX923Padding = "AES/OFB/ANSIX923Padding";
    public const string AES_OFB_ISO10126Padding = "AES/OFB/ISO10126Padding";
    
    // ... similar constants for DES, DESede, etc.
}

DES Implementation

Code

///
/// Encrypt
///
///
Plain data to encrypt
///
Secret key
///
Initialization vector (not needed for ECB)
///
Cipher algorithm
///
Encrypted data
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    if (data == null) throw new ArgumentNullException(nameof(data));
    if (key == null) throw new ArgumentNullException(nameof(key));
    if (algorithm == null) throw new ArgumentNullException(nameof(algorithm));

    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(true, ParameterUtilities.CreateKeyParameter("DES", key));
    else
        cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("DES", key), iv));
    return cipher.DoFinal(data);
}

///
/// Decrypt
///
///
Cipher data to decrypt
///
Secret key
///
Initialization vector (not needed for ECB)
///
Cipher algorithm
///
Plain data
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    if (data == null) throw new ArgumentNullException(nameof(data));
    if (key == null) throw new ArgumentNullException(nameof(key));
    if (algorithm == null) throw new ArgumentNullException(nameof(algorithm));

    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(false, ParameterUtilities.CreateKeyParameter("DES", key));
    else
        cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("DES", key), iv));
    return cipher.DoFinal(data);
}

Sample Usage

private static void DES_Sample()
{
    Console.WriteLine("Encryption algorithm: DES, mode: CBC, padding: PKCS7Padding, charset: utf8");

    var keyBytes = DES.GenerateKey();
    var keyBase64Str = Base64.ToBase64String(keyBytes);
    Console.WriteLine($"Key length: 192bit, Key (Base64): {keyBase64Str}");

    var ivStr = Str.GenerateRandom(8);
    var iv = Strings.ToByteArray(ivStr);
    Console.WriteLine($"IV: {ivStr}");

    var content = "hello des";
    Console.WriteLine($"Plain text: {content}");

    var cipherStr = Base64.ToBase64String(DES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.DES_CBC_PKCS7Padding));
    Console.WriteLine($"Cipher (Base64): {cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(DES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.DES_CBC_PKCS7Padding));
    Console.WriteLine($"Decrypted text: {originalStr}");
    Console.WriteLine();
}

3DES Implementation

Code

///
/// Encrypt using 3DES
///
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    // Same validation as DES
    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(true, ParameterUtilities.CreateKeyParameter("DESEDE", key));
    else
        cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("DESEDE", key), iv));
    return cipher.DoFinal(data);
}

///
/// Decrypt using 3DES
///
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(false, ParameterUtilities.CreateKeyParameter("DESEDE", key));
    else
        cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("DESEDE", key), iv));
    return cipher.DoFinal(data);
}

Sample Usage

private static void TripleDES_Sample()
{
    Console.WriteLine("Encryption algorithm: 3DES, mode: CBC, padding: PKCS7Padding, charset: utf8");
    var keyBytes = TripleDES.GenerateKey(192);
    var keyBase64Str = Base64.ToBase64String(keyBytes);
    Console.WriteLine($"Key length: 192bit, Key (Base64): {keyBase64Str}");

    var ivStr = Str.GenerateRandom(8);
    var iv = Strings.ToByteArray(ivStr);
    Console.WriteLine($"IV: {ivStr}");

    var content = "hello 3des";
    Console.WriteLine($"Plain text: {content}");

    var cipherStr = Base64.ToBase64String(TripleDES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.DESede_CBC_PKCS7Padding));
    Console.WriteLine($"Cipher (Base64): {cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(TripleDES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.DESede_CBC_PKCS7Padding));
    Console.WriteLine($"Decrypted text: {originalStr}");
    Console.WriteLine();
}

AES Implementation

Code

///
/// Encrypt using AES
///
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    // Validation omitted for brevity
    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(true, ParameterUtilities.CreateKeyParameter("AES", key));
    else
        cipher.Init(true, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
    return cipher.DoFinal(data);
}

///
/// Decrypt using AES
///
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv, string algorithm)
{
    var cipher = CipherUtilities.GetCipher(algorithm);
    if (iv == null)
        cipher.Init(false, ParameterUtilities.CreateKeyParameter("AES", key));
    else
        cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", key), iv));
    return cipher.DoFinal(data);
}

Sample Usage

private static void AES_Sample()
{
    Console.WriteLine("Encryption algorithm: AES, mode: CBC, padding: PKCS7Padding, charset: utf8");
    var keyBytes = AES.GenerateKey();
    var keyBase64Str = Base64.ToBase64String(keyBytes);
    Console.WriteLine($"Key length: 192bit, Key (Base64): {keyBase64Str}");

    var ivStr = Str.GenerateRandom(16);
    var iv = Strings.ToByteArray(ivStr);
    Console.WriteLine($"IV: {ivStr}");

    var content = "hello aes";
    Console.WriteLine($"Plain text: {content}");

    var cipherStr = Base64.ToBase64String(AES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.AES_CBC_PKCS7Padding));
    Console.WriteLine($"Cipher (Base64): {cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(AES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.AES_CBC_PKCS7Padding));
    Console.WriteLine($"Decrypted text: {originalStr}");
    Console.WriteLine();
}

Next Issue Preview

The next article will cover certificate‑related operations. Stay tuned.

CBouncyCastlecryptographySymmetric EncryptionAESDES.NET Core3DES
Fulu Network R&D Team
Written by

Fulu Network R&D Team

Providing technical literature sharing for Fulu Holdings' tech elite, promoting its technologies through experience summaries, technology consolidation, and innovation sharing.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.