cyendra

Azarath Metrion Zinthos

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

这是一个高内聚低耦合可复用的DES加密系统的实现。

Github 链接:https://github.com/cyendra/CyDES

 

要实现加密系统,先考虑数据的基本单位。

在DES加密中,数据是以64位为一组的(unsigned long long),我们称它为Bit。

加密过程中会对Bit做位移操作(左移、右移、循环左移、循环右移),也会做位运算(And、Or、Xor),还会做分割以及合并等操作。

我们设计一个类Bit来封装这些操作,作为数据的基本单位。

  1 /*
  2     表示64位以下的数据
  3     可以做常见的位运算
  4 */
  5 class Bit {
  6 private:
  7     unsigned long long bit;// 表示数据,最多64位
  8     int size;// 表示数据的位数,不超过64位
  9 public:
 10     // 值为0的64位数据
 11     Bit();
 12 
 13     // 值为_bit的64位数据
 14     Bit(unsigned long long _bit);
 15 
 16     // 值为_bit的n位数据,当n>64位时截断
 17     Bit(unsigned long long _bit, int n);
 18 
 19     Bit(const Bit& b);
 20     Bit& operator=(Bit& b);
 21     //Bit& operator=(unsigned char num);
 22     
 23     // 由byte构造8位Bit对象
 24     void Byte(unsigned char num);
 25 
 26     // 直接左移d位
 27     void LeftShift(int d);
 28 
 29     // 循环左移d位
 30     void LeftRotate(int d);
 31 
 32     // 直接右移d位
 33     void RightShift(int d);
 34 
 35     // 循环右移d位
 36     void RightRotate(int d);
 37 
 38     // 将第pos位设置为1
 39     // pos从左向右从0开始计数,超过size位时无效
 40     void Set(int pos);
 41 
 42     // 将所有位都设置为1
 43     void Set();
 44 
 45     // 将第pos位设置为0
 46     // pos从左向右从0开始计数,超过size位时无效
 47     void Reset(int pos);
 48 
 49     // 将所有位都设置为0
 50     void Reset();
 51 
 52     // 将第pos位取反
 53     // pos从左向右从0开始计数,超过size位时无效
 54     void Flip(int pos);
 55 
 56     // 将所有位都取反
 57     void Flip();
 58 
 59     // 当所有位都为0时返回true
 60     bool None();
 61 
 62     // 当任意位为1时返回true
 63     bool Any();
 64 
 65     // 统计所有位中1的个数
 66     int Count();
 67 
 68     // 数据的有效位数
 69     int Size();
 70 
 71     // 当第pos位的值为1时返回true
 72     // pos从左向右从0开始计数,超过size位时无效
 73     bool operator[](int pos);
 74 
 75     // 将数据以unsigned long long的形式返回
 76     unsigned long long ToULL();
 77 
 78     // 将所有二进制位以二进制串形式返回
 79     std::string ToString();
 80 
 81     // 静态方法,将数据bit从中间分割为两份数据
 82     static std::pair<Bit, Bit> Split(Bit bit);
 83 
 84     // 静态方法,把数据bit平分为n份,n为偶数,bit的size能被n整除
 85     static std::vector<Bit> Split(Bit bit, int n);
 86 
 87     // 静态方法,将两份数据合并为一份数据
 88     static Bit Merge(Bit L, Bit R);
 89 
 90     // 静态方法,将Bit数组中从L到R之间的数据合并为一份数据
 91     static Bit Merge(Bit b[], int L, int R);
 92 
 93     // 静态方法,求两份数据的异或值
 94     static Bit Xor(Bit x, Bit y);
 95 
 96     // 静态方法,求两份数据的OR
 97     static Bit Or(Bit x, Bit y);
 98 
 99     // 静态方法,求两份数据的AND
100     static Bit And(Bit x, Bit y);
101 };
Bit类

 

DES加密过程的原理其实就是16轮迭代,而迭代过程中有两个重要的处理:子密钥生成和f函数。

所以先不考虑主加密过程,考虑子密钥和f函数的抽象。

虽然子密钥有16之多,但是我们只要有了主密钥就可以生成全部的16个子密钥。

我们把这个过程抽象出来,即输入主密钥,得到一个装有16个子密钥的动态数组:

1 /*
2     主密钥产生子密钥的接口
3     单例模式
4 */
5 class IKeyManager :public Uncopyable {
6 public:
7     // 通过主密钥产生子密钥
8     virtual std::vector<Bit> GetKeys(Bit MasterKey) = 0;
9 };
IKeyManager接口

 

接下来考虑f函数,它接受一个32位的数据和一个48位的子密钥,返回32位的加密数据。

 1 /*
 2     DES中f函数的接口
 3     单例模式
 4     其值通过32位的数据与48位的子密钥计算而来
 5 */
 6 class IFunction :public Uncopyable {
 7 public:
 8     // f函数
 9     // bit为32位的R_{i-1},Key为48位的K_i
10     virtual Bit ProcessKey(Bit bit, Bit Key) = 0;
11 };
IFunction接口

 

有了这两个类,主加密过程就容易实现了。

考虑到主加密过程一次只能处理64位的数据,而实际应用中要多次调用主加密过程来加密长数据。

因此为了避免重复计算子密钥,要在调用主加密过程之前先设置好主秘钥。

解密操作是加密操作的逆操作,所以放在一起实现。

 1 /*
 2     Data Encryption Standard 接口
 3     继承此接口的派生类可以完成以下操作:
 4     1-接受一个主密钥
 5     2-对一组数据加密
 6     3-对一组数据解密
 7 */
 8 class IDes {
 9 public:
10     // 将64位的key设置为主密钥
11     virtual void SetMasterKey(Bit key) = 0;
12     
13     // 加密明文组dat
14     virtual Bit Encryption(Bit dat) = 0;
15     
16     // 解密密文组dat
17     virtual Bit Decryption(Bit dat) = 0;
18 };
IDes接口

 

这样一来,DES的框架就准备好了,实现的时候有两个较复杂的逻辑:置换表操作和S-Box取值操作。

因此单独把这两个操作抽象出来。设计一个类表示置换表,一个类管理置换表,一个类表示S-Box,一个类管理S-Box。

 1 /*
 2     置换表接口
 3 */
 4 class IPermutationTable {
 5 public:
 6     // 置换表中元素个数
 7     virtual int Size() = 0;
 8 
 9     // 获取表中第pos个元素
10     // pos从0开始计数
11     virtual int Get(int pos) = 0;
12 };
IPermutationTable接口
 1 /*
 2     DES中置换表的管理器接口
 3     单例模式
 4     它管理所有DES中要用到的置换表
 5 */
 6 class IPmtTableManager :public Uncopyable {
 7 public:
 8     // 获取初始置换表IP
 9     virtual IPermutationTable* GetIPTable() = 0;
10 
11     // 获取逆初始置换表IP-1
12     virtual IPermutationTable* GetIPRevTable() = 0;
13     
14     // 获取扩增排列表E
15     virtual IPermutationTable* GetETable() = 0;
16     
17     // 获取缩减排列表P
18     virtual IPermutationTable* GetPTable() = 0;
19     
20     // 获取密钥排列PC-1
21     virtual IPermutationTable* GetPC1Table() = 0;
22     
23     // 获取密钥排列PC-2
24     virtual IPermutationTable* GetPC2Table() = 0;
25 };
IPmtTableManager接口
1 // S-Box的接口
2 class ISBox {
3 public:
4     // 通过6位数据pos获取S-Box中的值
5     virtual Bit Get(Bit pos) = 0;
6 
7     // 通过指定的坐标(i,j)获取S-Box中的值
8     virtual Bit Get(int i, int j) = 0;
9 };
ISBox接口
 1 /*
 2     S-Box管理器的接口
 3     单例模式
 4     它能够返回指定编号的S-Box
 5 */
 6 class ISBoxManager :public Uncopyable {
 7 public:
 8     // 返回指向编号为i的S-Box的指针
 9     virtual SBox* GetSBox(int i) = 0;
10 };
ISBoxManager接口

 

只有置换表还不够,置换操作也是一个较复杂的操作,应该单独抽象出来处理。

 1 /*
 2     置换操作的接口
 3     单例模式
 4 */
 5 class IPermutationManager :public Uncopyable {
 6 public:
 7     // 用置换表table对数据bit进行置换
 8     virtual Bit Permutation(Bit bit, IPermutationTable* table) = 0;
 9     // 用置换表table对数据bit进行逆置换
10     virtual Bit InversePermutation(Bit bit, IPermutationTable* table) = 0;
11 };
IPermutationManager接口

 

如此一来,在添加具体实现细节以后,DES主加密过程就能顺利实现了。

为了加密长数据,我们为之前的代码套上一层外壳。

用一个类来与用户进行交互,使它可以以用户指定的分组方式来对数据分组并调用主加密过程。

/*
    加密器接口
*/
class IEncryptor {
public:
    // 分组操作方案
    enum Type {
        ECB, CBC, CFB, OFB
    };

    // 加密字符串 
    virtual std::vector<unsigned char> EncryptString(const std::string& string, Bit MasterKey, Type type) = 0;
    
    // 解密字符串
    virtual std::string DecryptString(const std::vector<unsigned char>& bins, Bit MasterKey, Type type) = 0;
    
    // 加密二进制串
    virtual std::vector<unsigned char> EncryptBinary(const std::vector<unsigned char>& bins, Bit MasterKey, Type type) = 0;
    
    // 解密二进制串
    virtual std::vector<unsigned char> DecryptBinary(const std::vector<unsigned char>& bins, Bit MasterKey, Type type) = 0;
    
    // 加密文件
    virtual std::vector<unsigned char> EncryptFile(char *filename, Bit MasterKey, Type type) = 0;
    
    // 解密文件
    virtual std::vector<unsigned char> DecryptFile(char *filename, Bit MasterKey, Type type) = 0;
    
    // 保存二进制串到文件
    virtual void SaveBinaryAsFile(const std::vector<unsigned char>& bins, char *filename) = 0;
};
IEncryptor接口

 

最后将具体的分组过程实现即可。

1 /*
2     区块加密法的操作模式接口
3 */
4 class IMode :public Uncopyable {
5 public:
6     virtual std::vector<unsigned char> EncryptBinary(IDes* des, const std::vector<unsigned char>& bins, Bit MasterKey) = 0;
7     virtual std::vector<unsigned char> DecryptBinary(IDes* des, const std::vector<unsigned char>& bins, Bit MasterKey) = 0;
8 };
IMode接口

 

posted on 2014-09-19 16:48  cyendra  阅读(604)  评论(0编辑  收藏  举报