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位不包含奇偶校验,算法实现公式如下:
ciphertext = ek3(dk2(ek1(plaintext)))
即
密文 = ek3(dk2(ek1(平文)))
用k1对数据进行加密,用k2对数据进行解密,用k3对数据再加密。
解密公式为如下:
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类来实现相关功能
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中,效果就又不一样了
2|5netcore
在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的代码了
3|0小结
至此写下此文,也算是对3des有了些许了解吧
需要记住
在.net core中利用3des加密和解密必须要给出3个密钥即24个字节即使密钥3和密钥1相等,它不会像.net framework中会重用密钥1中的位数。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
下一篇: 怎么调肉馅好吃又嫩的小秘诀是什么