对称加密算法在C#中的踩坑日常
前言
有幸接触了一下传说中的对称加密算法3DES
感觉这些加密算法与我的工作是想去甚远的,一般没什么机会接触这些东西
今次了解了一下3DES这个对称算法
原理算不上明白,算是踩了C#中的一些坑吧
C#中对于密钥的处理比较奇怪,花费了一晚上一早上的时间才弄明白
期间偷窥了不少C#的源代码
下面由我娓娓道来
简介
3DES算法命名
定义算法最早期的标准被放在ANS X9.52中并在1998年发布并将其描述为三重数据加密算法(简称TDEA),在ANSI X3.92中定义了该算法的三个操作但是并没有使用DES或者3DES,直到1999年发布的FIPS PUB 46-3在正式命名三重数据加密算法,大概在2004到2005的样子才正式引入三重数据加密算法,之前一直以TDEA存在着,也就是说TDEA就是3DES,但是没有使用3DES作为标准术语。
基本逻辑
三重数据加密算法使用包括密钥K1,密钥K2和密钥约束K3,每一个包含56位不包含奇偶校验,算法实现公式如下:
ciphertext = EK3(DK2(EK1(plaintext)))
即
密文 = EK3(DK2(EK1(平文)))
用K1对数据进行加密,用K2对数据进行解密,用K3对数据再加密。
解密公式为如下:
plaintext = DK1(EK2(DK3(ciphertext)))
即
平文 = DK1(EK2(DK3(密文)))
用K3j对数据进行解密,用K2对数据进行加密,用K1对数据进行加密。每次加密都处理64位数据并形成一块。
3DES加密选项
定义了三种密钥选项。
(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所支持。
C#实现
讲真简介里用来凑字数的这些内容我其实没怎么看明白
C#中使用TripleDESCryptoServiceProvider类来实现相关功能
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位

然后对于这个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中,效果就又不一样了
NetCore
在NetCore中不存在TripleDESCryptoServiceProvider 取而代之的是 TripleDES
所以此时我们的代码需要稍作修改
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位
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的代码了
小结
至此写下此文,也算是对3DES有了些许了解吧
需要记住
在.NET Core中利用3DES加密和解密必须要给出3个密钥即24个字节即使密钥3和密钥1相等,它不会像.NET Framework中会重用密钥1中的位数。
对称加密算法在C#中的踩坑日常的更多相关文章
- 『vue踩坑日常』 在index.html中引入静态文件不生效
Vue日常踩坑日常 -- 在index.html中引入静态文件不生效问题 本文针对的是Vue小白,不喜勿喷,谢谢 出现该问题的标志如下 控制台warning(Resource interpreted ...
- Vue packages version mismatch的解决方法 初来乍到,踩坑日常
初来乍到,踩坑日常 这个问题也是我也是接受别人项目,出现的问题,在下载好依赖后运行的时候报这样的错误 它上面显示两个版本一个vue的版本,一个vue-template-compiler版本,我这边忘了 ...
- 避坑手册 | JAVA编码中容易踩坑的十大陷阱
JAVA编码中存在一些容易被人忽视的陷阱,稍不留神可能就会跌落其中,给项目的稳定运行埋下隐患.此外,这些陷阱也是面试的时候面试官比较喜欢问的问题. 本文对这些陷阱进行了统一的整理,让你知道应该如何避免 ...
- Next.js 在 Serverless 中从踩坑到破茧重生
作者 杨苏博,偏后端的全栈开发,目前负责腾云扣钉的 Cloud Studio 产品.在团队中负责接技术架构设计与 Review.Cloud Studio 编辑器内核设计与开发.部分核心插件设计与开发: ...
- python学习过程中的踩坑记录<若干,随时更新>
问题1:python中print的连串输出与java不一样? 输入print(code +"+++"); --在代码中写入,界面未报错,但是告诉你不行 会报错,如图: 解决办法: ...
- Vue中axios踩坑之路-POST传参
https://blog.csdn.net/call_me_fly/article/details/79012581
- router路由去掉#!的踩坑记
项目中在研究去掉router#!的过程中的踩坑过程.
- DES、3DES、AES、PBE对称加密算法实现及应用
1.对称加密算法概述 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文 ...
- 使用java库中的对称加密算法
对称加密算法是说加密方和解密方使用相同的密钥.常见的对称加密算法包括4个,DES,DESede(3DES),AES,PBE. 本文讨论的内容是加密算法,不是Message Digest,不是编码.下面 ...
随机推荐
- Python 之 copy() 与 deepcopy() 之间的区别
在 Python 之中,如果想要复制一个对象就免不了要理解浅复制与深复制.这也是 Python 与其他语言的区别之一. Python 的数据存储方式与其他语言不同.当你定义了一个变量: a = [, ...
- LeetCode | 707. 设计链表
设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...
- LeetCode | 287. 寻找重复数
特别感谢LeetCode大佬陈牧远的科普知识 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找 ...
- echar图柱状图和折线图混合加双侧y轴坐
代码如下: floorSalesBar(){//方法名====这个方法应该放在methods中并在mounted中调用哦 methods let _this = this; let myChart = ...
- LocalStorage与SessionStorage
localStorage与sessionStorage 每日更新前端基础,如果觉得不错,点个star吧
- 各种WAF绕过手法学习
原文:https://mp.weixin.qq.com/s/aeRi1lRnKcs_N2JLcZZ0Gg 0X00 Fuzz/爆破 fuzz字典 1.Seclists/Fuzzing https ...
- oracle数据库表用序列实现主键自增长
原理注意:序列和触发器必须建立在同一个用户名下否则运行出错1.建立数据表create table 表名( userid number(10) primary key, ...
- nmap端口扫描工具安装和使用方法
nmap(Network Mapper)是一款开源免费的针对大型网络的端口扫描工具,nmap可以检测目标主机是否在线.主机端口开放情况.检测主机运行的服务类型及版本信息.检测操作系统与设备类型等信息. ...
- Python datetime 时间处理
读入的时间数据是字符串格式,转换成datetime格式 data['time1'] = pd.to_datetime(data['time1'],format="%H:%M:%S:%f&qu ...
- 开始 Keras 序列模型(Sequential model)
开始 Keras 序列模型(Sequential model) 序列模型是一个线性的层次堆栈. 你可以通过传递一系列 layer 实例给构造器来创建一个序列模型. The Sequential mod ...