DES加解密原理及实现
这几天在写加解密相关的API,用来给Lua进行调用,其中一个加解密的算法是DES,底层是C/C++实现的。
当然我不是真的写一个DES加解密的实现,而是写一个接口就好。
顺便也了解了下DES加解密的相关事项,例如填充、加密模式等等。
DES是一种对称分组加密算法。
关键点在于:分组、加密、合并密文。
用简单的话来说明下DES分组和加密的概念吧。
现在我拥有开源的代码,接口要求一个8字节长度的数据作为DES密钥,要求一个8字节长度的数据作为待加密数据。
(你可能在想:密钥是8字节长度还可以接受,为啥待加密数据还要规定长度?别着急,继续往下看:)
我们拥有的开源代码接口大概是这个样子的:
const char *desEncrypt(char *data, char *desKey);
data是一个指针,指向一个8字节大小的字节数组(字符数组,包含待加密数据);
desKey是一个指针,也指向一个8字节大小的字节数组(字符数组);
返回值是一个指针,指向加密后的密文,是一个8字节大小的数据。
我们知道:
待加密数据是8字节,DES密钥也是8字节,最后的密文也是8字节。
现在我们想要的API接口是这个样子的:
size_t desEnc(char *plain, size_t plainLen, char *desKey, char *cipher)
plain是一个字节数组,长度不定(可能是8字节大小,可能是17字节大小,可能是29字节大小...);
plainLen指代plain的长度(因为plain是字节数据,有可能包含0x00);
desKey是8字节大小的DES密钥;
cipher是存放加密结果的地方;
函数返回值指代cipher的大小(因为cipher也有可能包含0x00);
OK。
用一个例子来解释:
假设你有下面的明文:
AAAAAAAABBBBBBBBCCCCCCCC
看到了吧?是8*3=24B长度的一个字符串。
注:
以上字符串实际对应的数据是:
0x410x410x410x410x410x410x410x41
0x420x420x420x420x420x420x420x42
0x430x430x430x430x430x430x430x43
应该说:这个待加密数据“恰好是可打印字符组成”,实际待加密的数据并不一定是可打印的哟!
我们的DES密钥:
DDDDDDDD
这是一个8字节长度的数据。
注:
以上密钥对应的二进制数据是:
0x440x440x440x440x440x440x440x44
道理也是同上,这个DES密钥也“恰好是可打印字符组成”,实际并不一定是可打印的。
假定我们默认使用的是PKCS#5填充模式。
详见:
http://blog.csdn.net/test1280/article/details/75268255
待加密数据刚好是24字节,是8的整数倍,那么进行PKCS#5填充,填充8个0x08字节;
填充完毕后,待加密数据为:
0x410x410x410x410x410x410x410x41
0x420x420x420x420x420x420x420x42
0x430x430x430x430x430x430x430x43
0x080x080x080x080x080x080x080x08
分成四组(每8字节一组):
待加密数据:
0x410x410x410x410x410x410x410x41
DES密钥:
0x440x440x440x440x440x440x440x44
经过desEncrypt加密后,密文为:
0x580x580x580x580x580x580x580x58
待加密数据:
0x420x420x420x420x420x420x420x42
DES密钥:
0x440x440x440x440x440x440x440x44
经过desEncrypt加密后,密文为:
0x590x590x590x590x590x590x590x59
待加密数据:
0x430x430x430x430x430x430x430x43
DES密钥:
0x440x440x440x440x440x440x440x44
经过desEncrypt加密后,密文为:
0x600x600x600x600x600x600x600x60
待加密数据:
0x080x080x080x080x080x080x080x08
DES密钥:
0x440x440x440x440x440x440x440x44
经过desEncrypt加密后,密文为:
0x570x570x570x570x570x570x570x57
最后将四组密文拼成一个密文:
0x580x580x580x580x580x580x580x58
0x590x590x590x590x590x590x590x59
0x600x600x600x600x600x600x600x60
0x570x570x570x570x570x570x570x57
大功告成!
用desEnc来说明:
size_t cipherLen = 0;
cipherLen = desEnc(plain, plainLen, desKey, cipher);
其中,plain内容为:
0x410x410x410x410x410x410x410x41
0x420x420x420x420x420x420x420x42
0x430x430x430x430x430x430x430x43
plainLen为:24;
desKey为:
0x440x440x440x440x440x440x440x44;
加密后,cipher为:
0x580x580x580x580x580x580x580x58
0x590x590x590x590x590x590x590x59
0x600x600x600x600x600x600x600x60
0x570x570x570x570x570x570x570x57
cipherLen为32;
记住,DES只是做了加密,指的是8字节数据和8字节的密钥进行加密变换。
至于填充方式,是在你的外部包装的API(就是这里的desEnc)里面来做的,你可以用PKCS#5来进行填充,保证其总是8字节的整数倍。
总的来说,真正的DES加密是对8字节数据进行加密,但实际运用中我们的待加密数据很有可能不是8字节大小,这个时候就要先进行填充,将其填充到8字节的整数倍,然后分组、加密,最后将各分组的密文数据进行整合,成为一个密文。
关键点:
填充、分组、加密、合并。