服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#中对称加密算法的踩坑日常记录

C#中对称加密算法的踩坑日常记录

2022-07-28 10:38ixysy C#

这篇文章主要给大家介绍了关于C#中对称加密算法的踩坑日常记录,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

1|0前言

有幸接触了一下传说中的对称加密算法3DES

感觉这些加密算法与我的工作是想去甚远的,一般没什么机会接触这些东西

今次了解了一下3DES这个对称算法

原理算不上明白,算是踩了C#中的一些坑吧

C#中对于密钥的处理比较奇怪,花费了一晚上一早上的时间才弄明白

期间偷窥了不少C#的源代码

下面由我娓娓道来

2|0简介

2|13DES算法命名

定义算法最早期的标准被放在ANS X9.52中并在1998年发布并将其描述为三重数据加密算法(简称TDEA),在ANSI X3.92中定义了该算法的三个操作但是并没有使用DES或者3DES,直到1999年发布的FIPS PUB 46-3在正式命名三重数据加密算法,大概在2004到2005的样子才正式引入三重数据加密算法,之前一直以TDEA存在着,也就是说TDEA就是3DES,但是没有使用3DES作为标准术语。

2|2基本逻辑

三重数据加密算法使用包括密钥K1,密钥K2和密钥约束K3,每一个包含56位不包含奇偶校验,算法实现公式如下:

?
1
ciphertext = EK3(DK2(EK1(plaintext)))

密文 = EK3(DK2(EK1(平文)))

用K1对数据进行加密,用K2对数据进行解密,用K3对数据再加密。

解密公式为如下:

?
1
plaintext = DK1(EK2(DK3(ciphertext)))

平文 = DK1(EK2(DK3(密文)))

用K3j对数据进行解密,用K2对数据进行加密,用K1对数据进行加密。每次加密都处理64位数据并形成一块。

2|33DES加密选项

定义了三种密钥选项。

(1)三个密钥相互独立。

(2)K1和K2密钥独立,但K1 = K3。

(3)三个密钥相等。

密钥选项1的强度最高,拥有3 x 56 = 168个独立的密钥位。

密钥选项2的安全性稍低,拥有2 x 56 = 112个独立的密钥位。该选项比简单的应用DES两次的强度较高,即使用K1和K2,因为它可以防御中途相遇攻击。

密钥选项3等同与DES,只有56个密钥位。这个选项提供了与DES的兼容性,因为第1和第2次DES操作相互抵消了。该选项不再为国家标准科技协会(NIST)所推荐,亦不为ISO/IEC 18033-3所支持。

2|4C#实现

讲真简介里用来凑字数的这些内容我其实没怎么看明白

C#中使用TripleDESCryptoServiceProvider类来实现相关功能

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static string DesEncrypt(string input, string key)
{
  byte[] inputArray = Encoding.UTF8.GetBytes(input);
  TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
  tripleDES.Key = Encoding.UTF8.GetBytes(key);
 
  tripleDES.Mode = CipherMode.ECB;
  tripleDES.Padding = PaddingMode.PKCS7;
  ICryptoTransform cTransform = tripleDES.CreateEncryptor();
  byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
  tripleDES.Clear();
  return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
 
public static string DesDecrypt(string input, string key)
{
  byte[] inputArray = Convert.FromBase64String(input);
  TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
  tripleDES.Key = Encoding.UTF8.GetBytes(key);
  tripleDES.Mode = CipherMode.ECB;
  tripleDES.Padding = PaddingMode.PKCS7;
  ICryptoTransform cTransform = tripleDES.CreateDecryptor();
  byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
  tripleDES.Clear();
  return Encoding.UTF8.GetString(resultArray);
}

从下面源码中看出,该类接收的Key为16位或24位

C#中对称加密算法的踩坑日常记录

然后对于这个Key,C#似乎有自己的处理方式

以下为个人理解:

这个24位的key会被处理成3个8字节的独立密钥参与运算

当提供24位key时并没有什么不妥

但是当提供16位的key时 会把提供的key拆分成两个块(block) 并以第一个块作为第三个块组成一个24位的密钥

如下:

输入密钥:49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55

实际使用:49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55, 49, 50, 51, 52, 53, 54, 55, 56

可以看出使用了前8位来进行后面8位的补全

这时候你可能要问,如果提供一个不是16位也不是24位的密钥时会发生什么

会抛异常

以上理解都是在.NetFramework中的体现

如果换到NetCore中,效果就又不一样了

2|5NetCore

在NetCore中不存在TripleDESCryptoServiceProvider 取而代之的是 TripleDES

所以此时我们的代码需要稍作修改

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static string DesEncrypt(string input, string key)
    {
 
      byte[] inputArray = Encoding.UTF8.GetBytes(input);
      var tripleDES = TripleDES.Create();
      var byteKey = Encoding.UTF8.GetBytes(key);
      tripleDES.Key = byteKey;
      tripleDES.Mode = CipherMode.ECB;
      tripleDES.Padding = PaddingMode.PKCS7;
      ICryptoTransform cTransform = tripleDES.CreateEncryptor();
      byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
      return Convert.ToBase64String(resultArray, 0, resultArray.Length);
    }
 
    public static string DesDecrypt(string input, string key)
    {
      byte[] inputArray = Convert.FromBase64String(input);
      var tripleDES = TripleDES.Create();
      var byteKey = Encoding.UTF8.GetBytes(key);
      tripleDES.Key = byteKey;
      tripleDES.Mode = CipherMode.ECB;
      tripleDES.Padding = PaddingMode.PKCS7;
      ICryptoTransform cTransform = tripleDES.CreateDecryptor();
      byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
      return Encoding.UTF8.GetString(resultArray);
    }

NetCore中同样要求我们提供24位的Key

但是不在兼容16位的Key,如果你提供一个非24位的Key就会异常

不过没关系,对于16位的Key我们可以自行处理一下

同理使用前8位补全后8位

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static string DesEncrypt(string input, string key)
{
 
  byte[] inputArray = Encoding.UTF8.GetBytes(input);
  var tripleDES = TripleDES.Create();
  var byteKey = Encoding.UTF8.GetBytes(key);
  //复制前8位补全后8位
  byte[] allKey = new byte[24];
  Buffer.BlockCopy(byteKey, 0, allKey, 0, 16);
  Buffer.BlockCopy(byteKey, 0, allKey, 16, 8);
  tripleDES.Key = allKey;
  tripleDES.Mode = CipherMode.ECB;
  tripleDES.Padding = PaddingMode.PKCS7;
  ICryptoTransform cTransform = tripleDES.CreateEncryptor();
  byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
  return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
 
public static string DesDecrypt(string input, string key)
{
  byte[] inputArray = Convert.FromBase64String(input);
  var tripleDES = TripleDES.Create();
  var byteKey = Encoding.UTF8.GetBytes(key);
  //复制前8位补全后8位
  byte[] allKey = new byte[24];
  Buffer.BlockCopy(byteKey, 0, allKey, 0, 16);
  Buffer.BlockCopy(byteKey, 0, allKey, 16, 8);
  tripleDES.Key = allKey;
  tripleDES.Mode = CipherMode.ECB;
  tripleDES.Padding = PaddingMode.PKCS7;
  ICryptoTransform cTransform = tripleDES.CreateDecryptor();
  byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
  return Encoding.UTF8.GetString(resultArray);
}

至此就可以正常兼容NetFramework的代码了

3|0小结

至此写下此文,也算是对3DES有了些许了解吧

需要记住

在.NET Core中利用3DES加密和解密必须要给出3个密钥即24个字节即使密钥3和密钥1相等,它不会像.NET Framework中会重用密钥1中的位数。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。

原文链接:https://www.cnblogs.com/ixysy/p/11057807.html

延伸 · 阅读

精彩推荐
  • C#详解C# 不能用于文件名的字符

    详解C# 不能用于文件名的字符

    在 Windows 有一些字符是不能作为文件名,尝试重命名一个文件,输入/ 就可以看到windows 提示的不能作为文件名的字符,那么具体是包括哪些符号不能作为文...

    lindexi7752022-02-20
  • C#C#实现的微信网页授权操作逻辑封装示例

    C#实现的微信网页授权操作逻辑封装示例

    这篇文章主要介绍了C#实现的微信网页授权操作逻辑封装,分析了微信网页授权操作的原理、步骤并给出了C#实现的网页授权操作逻辑封装类,需要的朋友可以...

    天马37987542021-12-08
  • C#C#实现QQ截图功能及相关问题

    C#实现QQ截图功能及相关问题

    这篇文章主要为大家详细介绍了C#实现QQ截图功能及相关问题,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Audient5352022-01-25
  • C#理解C#中参数的值和引用以及传递结构和类引用的区别

    理解C#中参数的值和引用以及传递结构和类引用的区别

    这篇文章主要介绍了理解C#中参数的值和引用以及传递结构和类引用的区别,文中举了两段代码例子来简单说明,需要的朋友可以参考下...

    C#教程网4872021-11-09
  • C#C#连接到sql server2008数据库的实例代码

    C#连接到sql server2008数据库的实例代码

    这篇文章主要介绍了C#连接到sql server2008数据库的实例代码,需要的朋友可以参考下...

    醉墨重生11592022-01-21
  • C#C#使用SQL DataReader访问数据的优点和实例

    C#使用SQL DataReader访问数据的优点和实例

    今天小编就为大家分享一篇关于C#使用SQL DataReader访问数据的优点和实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起...

    Czhenya10362022-03-03
  • C#C#中的 == 和equals()区别浅析

    C#中的 == 和equals()区别浅析

    这篇文章主要介绍了C#中的 == 和equals()的区别,对不同点进行了阐述,感兴趣的小伙伴们可以参考一下...

    C#教程网10532021-11-01
  • C#C# GroupBy的基本使用教程

    C# GroupBy的基本使用教程

    这篇文章主要给大家介绍了关于C# GroupBy的基本使用教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    weilence11162022-03-09