.NET Core加解密实战系列之——对称加密算法

简介

加解密现状,编写此系列文章的背景:

  • 需要考虑系统环境兼容性问题(Linux、Windows)
  • 语言互通问题(如C#、Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题)
  • 网上资料版本不一、或不全面
  • .NET官方库密码算法提供不全面,很难针对其他语言(Java)进行适配

本系列文章主要介绍如何在 .NET Core 中使用非对称加密算法、编码算法、消息摘要算法、签名算法、对称加密算法、国密算法等一系列算法,如有错误之处,还请大家批评指正。

本系列文章旨在引导大家能快速、轻松的了解接入加解密,乃至自主组合搭配使用BouncyCastle密码术包中提供的算法。

本系列代码项目地址:https://github.com/fuluteam/ICH.BouncyCastle.git

上一篇文章《.NET Core加解密实战系列之——消息摘要与数字签名算法》:https://www.cnblogs.com/fulu/p/13209066.html

功能依赖

BouncyCastle(https://www.bouncycastle.org/csharp) 是一个开放源码的轻量级密码术包;它支持大量的密码术算法,它提供了很多 .NET Core标准库没有的算法。

支持 .NET 4,.NET Standard 1.0-2.0,WP,Silverlight,MonoAndroid,Xamarin.iOS,.NET Core

功能 依赖
Portable.BouncyCastle Portable.BouncyCastle • 1.8.5

对称加密算法

算法介绍

对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。

具体算法有:DES,3DES,TDEA,Blowfish,RC5,IDEA。常见的有:DES,AES,3DES等等。

算法特点

对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。

不足之处是,交易双方都使用同样钥匙,安全性得不到保证。

此外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。

对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。而与公开密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。

对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性。

对称加密算法相比非对称加密算法来说,加解密的效率要高得多。但是缺陷在于对于秘钥的管理上,以及在非安全信道中通讯时,密钥交换的安全性不能保障。所以在实际的网络环境中,会将两者混合使用。

0ede9422ae5fe6121b7030ae71caa66d8bfcd15b

常见对称加密算法

DES

DES(数据加密标准)于 1976年推出,是最古老的对称加密方法之一。它是由 IBM 开发的,用于保护敏感的,未分类的电子政府数据,并于 1977年被正式采用,以供联邦机构使用。DES 使用 56 位加密密钥,它基于 Feistel 结构,该结构由密码学家 Horst Feistel 设计。DES 加密算法是 TLS(传输层安全性)版本 1.0 和 1.1 中包含的算法。

DES 通过将 64 位纯文本数据块划分为两个单独的 32 位块,并对每个块分别应用加密过程,将 64 位纯文本数据块转换为密文。这涉及 16 个回合的各种过程(例如扩展,置换,替换或使用回合密钥的 XOR 操作),数据将在加密后经历。最终,将生成 64 位加密文本块作为输出。

如今,DES 已不再使用,因为它已被许多安全研究人员破解。在 2005年,DES 被正式弃用,并被 AES 加密算法所取代, 我们将在稍后进行讨论。DES 的最大缺点是其加密密钥长度短,这使暴力破解变得很容易。TLS 1.2 是当今使用最广泛的 TLS 协议,它没有使用 DES 加密方法。

3DES

顾名思义,3DES(也称为 TDEA,代表三重数据加密算法)是已发布的 DES 算法的升级版本。3DES 的开发是为了克服 DES 算法的缺点,并于 1990年代后期开始投入使用。为此,它将 DES 算法三次应用于每个数据块。结果,此过程使 3DES 比其 DES 前身更难破解。它也已成为金融行业支付系统,标准和技术中广泛使用的加密算法。它也已成为 TLS,SSH,IPsec 和 OpenVPN 等加密协议的一部分。

所有加密算法最终都屈从于时间的力量,而 3DES 也不例外。研究人员 Karthikeyan Bhargavan 和 GaëtanLeurent 发现的 Sweet32 漏洞消除了 3DES 算法中存在的安全漏洞。这一发现导致安全行业考虑弃用该算法,美国国家标准技术研究院(NIST)在 2019年发布的指南草案中宣布弃用该算法。

根据该草案,到 2023年之后,将在所有新应用程序中废弃 3DES 的使用。 值得注意的是,TLS 1.3(SSL / TLS 协议的最新标准)也停止了 3DES 的使用。

AES

AES代表“高级加密系统”,是最广泛使用的加密算法之一,并且是DES算法的替代方法。AES也称为Rijndael,在2001年经NIST批准后成为一种加密标准。与DES不同,AES是一组分组密码,由不同密钥长度和分组大小的密码组成。

AES致力于替代和置换方法。首先,将明文数据转换为块,然后使用加密密钥应用加密。加密过程由各种子过程组成,例如子字节,移位行,混合列和添加回合密钥。根据密钥的大小,执行10、12或14次这样的回合。值得注意的是,上一轮不包括混合列的子过程以及为加密数据而执行的所有其他子过程。

使用AES加密算法的优势

所有这些可以归结为说AES是安全,快速和灵活的。与DES相比,AES是一种更快的算法。多个密钥长度选项是您最大的优势,因为密钥越长,破解它们的难度就越大。

如今,AES 是使用最广泛的加密算法,它已在许多应用程序中使用,包括:

  • 无线网络安全
  • 处理器安全性和文件加密
  • SSL / TLS 协议(网站安全)
  • Wi-Fi 安全性
  • 移动应用加密
  • VPN(虚拟专用网)等
  • 许多政府机构,包括国家安全局(NSA),都依靠 AES 加密算法来保护其敏感信息

示例代码

密文算法

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";

    public const string AES_CFB_NoPadding = "AES/CFB/NoPadding";
    public const string AES_CFB_PKCS7Padding = "AES/CFB/PKCS7Padding";
    public const string AES_CFB_ZerosPadding = "AES/CFB/ZerosPadding";
    public const string AES_CFB_ANSIX923Padding = "AES/CFB/ANSIX923Padding";
    public const string AES_CFB_ISO10126Padding = "AES/CFB/ISO10126Padding";

    public const string AES_CTS_NoPadding = "AES/CTS/NoPadding";
    public const string AES_CTS_PKCS7Padding = "AES/CTS/PKCS7Padding";
    public const string AES_CTS_ZerosPadding = "AES/CTS/ZerosPadding";
    public const string AES_CTS_ANSIX923Padding = "AES/CTS/ANSIX923Padding";
    public const string AES_CTS_ISO10126Padding = "AES/CTS/ISO10126Padding";

    public const string AES_CTR_NoPadding = "AES/CTR/NoPadding";
    public const string AES_CTR_PKCS7Padding = "AES/CTR/PKCS7Padding";
    public const string AES_CTR_ZerosPadding = "AES/CTR/ZerosPadding";
    public const string AES_CTR_ANSIX923Padding = "AES/CTR/ANSIX923Padding";
    public const string AES_CTR_ISO10126Padding = "AES/CTR/ISO10126Padding";

    public const string DES_CBC_NoPadding = "DES/CBC/NoPadding";
    public const string DES_CBC_PKCS7Padding = "DES/CBC/PKCS7Padding";
    public const string DES_CBC_ZerosPadding = "DES/CBC/ZerosPadding";
    public const string DES_CBC_ANSIX923Padding = "DES/CBC/ANSIX923Padding";
    public const string DES_CBC_ISO10126Padding = "DES/CBC/ISO10126Padding";

    public const string DES_ECB_NoPadding = "DES/ECB/NoPadding";
    public const string DES_ECB_PKCS7Padding = "DES/ECB/PKCS7Padding";
    public const string DES_ECB_ZerosPadding = "DES/ECB/ZerosPadding";
    public const string DES_ECB_ANSIX923Padding = "DES/ECB/ANSIX923Padding";
    public const string DES_ECB_ISO10126Padding = "DES/ECB/ISO10126Padding";

    public const string DES_OFB_NoPadding = "DES/OFB/NoPadding";
    public const string DES_OFB_PKCS7Padding = "DES/OFB/PKCS7Padding";
    public const string DES_OFB_ZerosPadding = "DES/OFB/ZerosPadding";
    public const string DES_OFB_ANSIX923Padding = "DES/OFB/ANSIX923Padding";
    public const string DES_OFB_ISO10126Padding = "DES/OFB/ISO10126Padding";

    public const string DES_CFB_NoPadding = "DES/CFB/NoPadding";
    public const string DES_CFB_PKCS7Padding = "DES/CFB/PKCS7Padding";
    public const string DES_CFB_ZerosPadding = "DES/CFB/ZerosPadding";
    public const string DES_CFB_ANSIX923Padding = "DES/CFB/ANSIX923Padding";
    public const string DES_CFB_ISO10126Padding = "DES/CFB/ISO10126Padding";

    public const string DES_CTS_NoPadding = "DES/CTS/NoPadding";
    public const string DES_CTS_PKCS7Padding = "DES/CTS/PKCS7Padding";
    public const string DES_CTS_ZerosPadding = "DES/CTS/ZerosPadding";
    public const string DES_CTS_ANSIX923Padding = "DES/CTS/ANSIX923Padding";
    public const string DES_CTS_ISO10126Padding = "DES/CTS/ISO10126Padding";

    public const string DESede_CBC_NoPadding = "DESede/CBC/NoPadding";
    public const string DESede_CBC_PKCS7Padding = "DESede/CBC/PKCS7Padding";
    public const string DESede_CBC_ZerosPadding = "DESede/CBC/ZerosPadding";
    public const string DESede_CBC_ANSIX923Padding = "DESede/CBC/ANSIX923Padding";
    public const string DESede_CBC_ISO10126Padding = "DESede/CBC/ISO10126Padding";

    public const string DESede_ECB_NoPadding = "DESede/ECB/NoPadding";
    public const string DESede_ECB_PKCS7Padding = "DESede/ECB/PKCS7Padding";
    public const string DESede_ECB_ZerosPadding = "DESede/ECB/ZerosPadding";
    public const string DESede_ECB_ANSIX923Padding = "DESede/ECB/ANSIX923Padding";
    public const string DESede_ECB_ISO10126Padding = "DESede/ECB/ISO10126Padding";

    public const string DESede_OFB_NoPadding = "DESede/OFB/NoPadding";
    public const string DESede_OFB_PKCS7Padding = "DESede/OFB/PKCS7Padding";
    public const string DESede_OFB_ZerosPadding = "DESede/OFB/ZerosPadding";
    public const string DESede_OFB_ANSIX923Padding = "DESede/OFB/ANSIX923Padding";
    public const string DESede_OFB_ISO10126Padding = "DESede/OFB/ISO10126Padding";

    public const string DESede_CFB_NoPadding = "DESede/CFB/NoPadding";
    public const string DESede_CFB_PKCS7Padding = "DESede/CFB/PKCS7Padding";
    public const string DESede_CFB_ZerosPadding = "DESede/CFB/ZerosPadding";
    public const string DESede_CFB_ANSIX923Padding = "DESede/CFB/ANSIX923Padding";
    public const string DESede_CFB_ISO10126Padding = "DESede/CFB/ISO10126Padding";

    public const string DESede_CTS_NoPadding = "DESede/CTS/NoPadding";
    public const string DESede_CTS_PKCS7Padding = "DESede/CTS/PKCS7Padding";
    public const string DESede_CTS_ZerosPadding = "DESede/CTS/ZerosPadding";
    public const string DESede_CTS_ANSIX923Padding = "DESede/CTS/ANSIX923Padding";
    public const string DESede_CTS_ISO10126Padding = "DESede/CTS/ISO10126Padding";
    
    ...
}

DES

代码

/// <summary>
/// 加密
/// </summary>
/// <param name="data">待加密原文数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>密文数据</returns>
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);
}

/// <summary>
/// 解密
/// </summary>
/// <param name="data">待解密数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>未加密原文数据</returns>
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));
    }

    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);
}

示例

private static void DES_Sample()
{
    Console.WriteLine("加密算法:DES,加密模式:CBC,填充:PKCS7Padding,字符集:utf8 ");

    var keyBytes = DES.GenerateKey();

    var keyBase64Str = Base64.ToBase64String(keyBytes);  //key转base64

    Console.WriteLine($"密码长度:192bit,密码(转Base64):{keyBase64Str}");

    var ivStr = Str.GenerateRandom(8);
    var iv = Strings.ToByteArray(ivStr);      //模式为ECB时不支持初始化向量IV

    Console.WriteLine($"初始向量:{ivStr}");

    var content = "hello des";

    Console.WriteLine($"待加密文本:{content}");

    var cipherStr = Base64.ToBase64String(DES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.DES_CBC_PKCS7Padding));

    Console.WriteLine($"加密结果(输出为Base64字符串):{cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(DES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.DES_CBC_PKCS7Padding));

    Console.WriteLine($"解密结果(输入为Base64字符串):{originalStr}");

    Console.WriteLine();
}

20200907143712

3DES

代码

/// <summary>
/// 加密
/// </summary>
/// <param name="data">待加密原文数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>密文数据</returns>
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));
    }

    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);
}

/// <summary>
/// 解密
/// </summary>
/// <param name="data">待解密数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>未加密原文数据</returns>
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));
    }

    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);
}

示例

private static void TripleDES_Sample()
{
    Console.WriteLine("加密算法:3DES,加密模式:CBC,填充:PKCS7Padding,字符集:utf8 ");

    var keyBytes = TripleDES.GenerateKey(192);

    var keyBase64Str = Base64.ToBase64String(keyBytes);  //key转base64

    Console.WriteLine($"密码长度:192bit,密码(转Base64):{keyBase64Str}");

    var ivStr = Str.GenerateRandom(8);
    var iv = Strings.ToByteArray(ivStr);      //模式为ECB时不支持初始化向量IV

    Console.WriteLine($"初始向量:{ivStr}");

    var content = "hello 3des";

    Console.WriteLine($"待加密文本:{content}");

    var cipherStr = Base64.ToBase64String(TripleDES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.DESede_CBC_PKCS7Padding));

    Console.WriteLine($"加密结果(输出为Base64字符串):{cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(TripleDES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.DESede_CBC_PKCS7Padding));

    Console.WriteLine($"解密结果(输入为Base64字符串):{originalStr}");

    Console.WriteLine();
}

20200907143736

AES

代码

/// <summary>
/// 加密
/// </summary>
/// <param name="data">待加密原文数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>密文数据</returns>
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));
    }

    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);
}

/// <summary>
/// 解密
/// </summary>
/// <param name="data">待解密数据</param>
/// <param name="key">密钥</param>
/// <param name="iv">偏移量,ECB模式不用填写!</param>
/// <param name="algorithm">密文算法</param>
/// <returns>未加密原文数据</returns>
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));
    }

    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);
}

示例

private static void AES_Sample()
{
    Console.WriteLine("加密算法:AES,加密模式:CBC,填充:PKCS7Padding,字符集:utf8 ");

    var keyBytes = AES.GenerateKey();

    var keyBase64Str = Base64.ToBase64String(keyBytes);  //key转base64

    Console.WriteLine($"密码长度:192bit,密码(转Base64):{keyBase64Str}");

    var ivStr = Str.GenerateRandom(16);
    var iv = Strings.ToByteArray(ivStr);      //模式为ECB时不支持初始化向量IV

    Console.WriteLine($"初始向量:{ivStr}");

    var content = "hello aes";

    Console.WriteLine($"待加密文本:{content}");

    var cipherStr = Base64.ToBase64String(AES.Encrypt(Strings.ToUtf8ByteArray(content), Base64.Decode(keyBase64Str), iv, Algorithms.AES_CBC_PKCS7Padding));

    Console.WriteLine($"加密结果(输出为Base64字符串):{cipherStr}");

    var originalStr = Strings.FromUtf8ByteArray(AES.Decrypt(Base64.Decode(cipherStr), Base64.Decode(keyBase64Str), iv, Algorithms.AES_CBC_PKCS7Padding));

    Console.WriteLine($"解密结果(输入为Base64字符串):{originalStr}");

    Console.WriteLine();
}

20200907143631

下期预告

下一篇将介绍证书相关操作,敬请期待。。。

福禄ICH·架构组 福禄娃
posted @ 2020-09-11 10:08  福禄网络研发团队  阅读(3272)  评论(8编辑  收藏  举报