C#实现DES加密时无法取到完整的64bit明文块
虽然这样的代码很垃圾,但毕竟你拿到了64bit的明文块了!你中间的方框中不正是64bit块组成的吗?这有什么疑问吗?
说到块,必须先说一下这些加密的方式就是块加密,把密文进行分组(块),然后依次进行加密,每块输出的长度也是固定的,最后把这些输出块依次排好也就是明文了。
不过,这里边有几个问题要考虑一下:
块的大小是固定的吗?
是预知的,并非固定。比如DES加密块就是64bit,而AES则是128~256之间变化,当然TDES则是128~192之间变化,同一种方式在执行时可以设置好块大小了然后执行。算法上块大小是被选择的,不固定,但运行时必须是设置为固定的值。DES只支持64bit。
密文若不是块的整数倍,也就是分组时最后一组不够块大小怎么办?
答案是使用填充(部分算法可以不填充),ModePadding属性可以控制填充方式。
对称加密中密钥指的是什么?
对称加密中我们学说的密钥指的是密钥串和向量串两部分,也就是Key和IV,Key被称为密钥串,这个概念其实与密钥是有差异的,但由于翻译上的习惯等多种原因,key也被称为密钥,但是对于对称加密中所指的密钥来说,指定的是Key和IV两部分,而不是专指的Key。虽然如此,称Key为对称加密中的密钥也不能算错,这与IV的功能有一定的关系。
对称加密中的IV的作用是什么?
IV我们称之为初始向量或向量,引用这个值的作用类似于MD5中的加盐(但不完全一样,这个留到下个问题中说),在加密过程中会存在同一内容相似密文块多的情况,这样情况下,不同的加密方式(C#默认电子本CBC加密)会有异同,若使用相同的块加密会导致加密结果相似,从而通过统计方式进行反解,所以有些加密方式是通过向量给以变化,然后上一块的结果会变成下一块的IV使用(CBC加密,这样相同块由于输入的IV不同,明文也不会相同,但这种情况下会需要IV,体现了初始向量概念中初始的概念),而有些由是每个块使用相同的IV(初始IV),更有甚者根本没有使用IV。这些具体的要求要看具体的加密方式(模式)。但由于DES对象会检查,所以在C#中无论是否使用都检查IV的值。DESCryptoServiceProvider只是CSP容器实现DES而已。
使用完全一样的Key和IV,相同的加密算法与填充模式,对相同的密文加密,结果是一样的吗?
不一样!加密算法了为对抗反向工程,使用同一类对象加密相同的内容,结果也不尽相同(IV只是保密加密过程中块重叠问题,而这个是为了保证不同的加密过程结果不同,所以这个更象是MD5的不同加盐方式)。虽然加密后的结果是不同的,但解密都会是正确的结果。
对称加密和解密使用的是相同的算法吗?
这个很多人有误解,算法概念本身被含混了。严格来说,算法是相同的!密码学中的算法包含加密算法和解密算法(广义上还是签名算法和验签算法也是算法)!所以可以说加解密算法是一个,比如DES算法,AES算法等;狭义上的算法往往指的是加密/解密的具体实施算法,比如DES中的CBC等,其实更多的时候为了区分我们称之为加/解密模式或块算法或块模式。而更多的程序员却把实现(类库)中的函数(成员方法)称为算法——比如EnCrypto和DesCrypto之类的,这种其实是算是狭义中的加解密算法,更多的时候我们还是称之为方法而不是算法,假定出现重载时,你难道还称其为有多个“算法”吗?所以算法到底是加密方法是否相同,并不一定——有些精巧点的算法可能会相同——对称算法只是说使用的是相同的密钥,加密和解密时间相差不多,并不是说一定是方法相同!不少人以为对称算法中使用了相同的密钥,所使用的方法必须是同一个——没这回事!比如我封装一个:Crypto(byte[] orgData, byte[] keyIv, bool enCrypto); 最后一个使用布称或枚举让你选择是加密还是解密,这不就算是所谓的一个方法了吗?所以说实现(类中的方法)与加密中理论完全是两码事,很多人喜欢往一块混!
加密学中的位指的是bit吗?
确实是!比如64bit,其实就是8Bytes(Byte[8])而已。很多人在问,为什么加密出来却是16byte?比如上文中的16个十六进制字符?其实是完全扯*蛋——byte[8]如果用16进制表示,每4个bit用0~F表示,正好是16个,很多人喜欢把十六进制与字符串乱整一通(基本知识的问题),把十六进制转成字符,然后再大言不惭地说,就是16个字符嘛——确实是,问题在于十六进制转成字符后,把每个4bit给转成了8bit表示出来了!所以自己都不知道多少bit了!十六进制的"FF"其实只是一个字节(1111 1111),转成字符串“FF”就是"0100 0110 0100 0110"了(0100 0110是字符F的编码)!
其实加/解密涉及的内容并不多,比如上文的几个问题就基本上全是对称加密的一些重点了,然后要有处理字节的能力就可以了!别动不动转成字符串看看,那对你没有什么好处!很多应用程序员都喜欢把字节处理成字符串,然后转来转去浪费计算机性能!举个例子来说,把一个文本文件加密,加密后的结果就使用二进制方式直接存储就可以了,解密时直接读二进制文件。为什么非要转成十六进制字符呢?我知道打开后是乱码——就算是你保存成不乱码的十六进制,除了文件大小增加一倍外,你还自己真能看懂?可能其他人会跟题主一样说,我不会犯这样的毛病——那么Key和IV为什么会是Encoding.GetBytes()?本身的设计是key和IV的容量都是非常的大的——现在就剩下一些可显示字符了!加上标点才85个而已(如果只是数字和字母只有36个了),按Key加密方法来算只有85^8了,事实设计了64bit,也就是2^64方个!为什么这个参数不是byte[8]?就算你想使用户接口,也应该是用户接口的成员方法处理。
所以,Key/IV输入的一定要是Byte[],就算是图形界面与方法不能直接交互,那么你可以设计一个密码的输入框,然后把用户输入的内容MD5,前64bit做Key后64bit做IV不是更好么?