DES加密系统的实现

时间:2021-11-25 04:01:28

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

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

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

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

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

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

 /*
表示64位以下的数据
可以做常见的位运算
*/
class Bit {
private:
unsigned long long bit;// 表示数据,最多64位
int size;// 表示数据的位数,不超过64位
public:
// 值为0的64位数据
Bit(); // 值为_bit的64位数据
Bit(unsigned long long _bit); // 值为_bit的n位数据,当n>64位时截断
Bit(unsigned long long _bit, int n); Bit(const Bit& b);
Bit& operator=(Bit& b);
//Bit& operator=(unsigned char num); // 由byte构造8位Bit对象
void Byte(unsigned char num); // 直接左移d位
void LeftShift(int d); // 循环左移d位
void LeftRotate(int d); // 直接右移d位
void RightShift(int d); // 循环右移d位
void RightRotate(int d); // 将第pos位设置为1
// pos从左向右从0开始计数,超过size位时无效
void Set(int pos); // 将所有位都设置为1
void Set(); // 将第pos位设置为0
// pos从左向右从0开始计数,超过size位时无效
void Reset(int pos); // 将所有位都设置为0
void Reset(); // 将第pos位取反
// pos从左向右从0开始计数,超过size位时无效
void Flip(int pos); // 将所有位都取反
void Flip(); // 当所有位都为0时返回true
bool None(); // 当任意位为1时返回true
bool Any(); // 统计所有位中1的个数
int Count(); // 数据的有效位数
int Size(); // 当第pos位的值为1时返回true
// pos从左向右从0开始计数,超过size位时无效
bool operator[](int pos); // 将数据以unsigned long long的形式返回
unsigned long long ToULL(); // 将所有二进制位以二进制串形式返回
std::string ToString(); // 静态方法,将数据bit从中间分割为两份数据
static std::pair<Bit, Bit> Split(Bit bit); // 静态方法,把数据bit平分为n份,n为偶数,bit的size能被n整除
static std::vector<Bit> Split(Bit bit, int n); // 静态方法,将两份数据合并为一份数据
static Bit Merge(Bit L, Bit R); // 静态方法,将Bit数组中从L到R之间的数据合并为一份数据
static Bit Merge(Bit b[], int L, int R); // 静态方法,求两份数据的异或值
static Bit Xor(Bit x, Bit y); // 静态方法,求两份数据的OR
static Bit Or(Bit x, Bit y); // 静态方法,求两份数据的AND
static Bit And(Bit x, Bit y);
};

Bit类

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

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

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

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

 /*
主密钥产生子密钥的接口
单例模式
*/
class IKeyManager :public Uncopyable {
public:
// 通过主密钥产生子密钥
virtual std::vector<Bit> GetKeys(Bit MasterKey) = ;
};

IKeyManager接口

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

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

IFunction接口

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

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

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

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

 /*
Data Encryption Standard 接口
继承此接口的派生类可以完成以下操作:
1-接受一个主密钥
2-对一组数据加密
3-对一组数据解密
*/
class IDes {
public:
// 将64位的key设置为主密钥
virtual void SetMasterKey(Bit key) = ; // 加密明文组dat
virtual Bit Encryption(Bit dat) = ; // 解密密文组dat
virtual Bit Decryption(Bit dat) = ;
};

IDes接口

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

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

 /*
置换表接口
*/
class IPermutationTable {
public:
// 置换表中元素个数
virtual int Size() = ; // 获取表中第pos个元素
// pos从0开始计数
virtual int Get(int pos) = ;
};

IPermutationTable接口

 /*
DES中置换表的管理器接口
单例模式
它管理所有DES中要用到的置换表
*/
class IPmtTableManager :public Uncopyable {
public:
// 获取初始置换表IP
virtual IPermutationTable* GetIPTable() = ; // 获取逆初始置换表IP-1
virtual IPermutationTable* GetIPRevTable() = ; // 获取扩增排列表E
virtual IPermutationTable* GetETable() = ; // 获取缩减排列表P
virtual IPermutationTable* GetPTable() = ; // 获取密钥排列PC-1
virtual IPermutationTable* GetPC1Table() = ; // 获取密钥排列PC-2
virtual IPermutationTable* GetPC2Table() = ;
};

IPmtTableManager接口

 // S-Box的接口
class ISBox {
public:
// 通过6位数据pos获取S-Box中的值
virtual Bit Get(Bit pos) = ; // 通过指定的坐标(i,j)获取S-Box中的值
virtual Bit Get(int i, int j) = ;
};

ISBox接口

 /*
S-Box管理器的接口
单例模式
它能够返回指定编号的S-Box
*/
class ISBoxManager :public Uncopyable {
public:
// 返回指向编号为i的S-Box的指针
virtual SBox* GetSBox(int i) = ;
};

ISBoxManager接口

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

 /*
置换操作的接口
单例模式
*/
class IPermutationManager :public Uncopyable {
public:
// 用置换表table对数据bit进行置换
virtual Bit Permutation(Bit bit, IPermutationTable* table) = ;
// 用置换表table对数据bit进行逆置换
virtual Bit InversePermutation(Bit bit, IPermutationTable* table) = ;
};

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

IEncryptor接口

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

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

IMode接口