基本原理
对称算法&分组加密
密钥长度64bit,每连续8bit为一个部分,该部分中前7bit参与运算,第8bit为校验位
由于进行块加密,将明文拆分为n*64bit之后加密得到的n*64bit合在一起就是密文
加密过程
01:34

初始IP置换
16轮次迭代
逆置换
初始IP置换
05:12

# 两张表分别为初始IP置换和逆置换的表,表中的数字表示在进行置换时,该位应置换为第几位
16轮次迭代
将64bit数据分为L0&R0/H0&L0
L1/H1=R0/L0
R1/L1=L0/H0⨁F(R0/L0, K1) # F函数为将R0/H0与K1进行轮函数运算
重复2-3直到16次
轮函数F()
32bitR0/L0-->48bitR0/L0 # E扩展置换
48bitR0/L0⨁48bitK1 #K1通过密钥生成获得
48R0/L0--S盒压缩-->32bitR0/L0
32bitR0/L0--P盒置换-->32bitR0/L0
E扩展置换
06:04

S盒压缩处理
08:45

将48bit分为8*6bit
根据“8个6进4出S盒”进行压缩
6进4出S盒
09:14

09:34

6bit数据取出头尾两个bit组成2bit数据,将2bit数据转换为十进制,即为该盒子的行数 # 对第几个6bit进行压缩就使用第几个S盒
中间4bit数据转换为十进制即为该盒子的列数
将盒中对应数字转换为2进制即为压缩结果
P盒置换
10:55

# P盒置换之后就将结果与L0/H0进行异或
逆置换
经过16轮次迭代之后得到的L16&R16/H16&L16拼接结果根据逆置换表置换得到结果
逆置换拼接时L16&R16/H16&L16的顺序与初始置换时相反
密钥生成
12:11

14:18

15:50

将64bit密钥K0根据PC-1表进行置换得到56bit数据
将56bit数据分为28bit的C0&D0
C0&D0根据移位次数表移位得到C1&D1 # 该处位移为2*28bit的循环左移
C1&D1结果拼接之后的56bit数据根据PC-2表进行置换得到48bit密钥K1
重复3-4直到16次 # 每一次的移位都是在上一对C&D的基础上移位
解密时密钥的使用顺序与加密时的顺序应当相反
附上鄙人花了两天写出来的乐色代码QAQ
由于字数限制,置换表、盒子等就被我省略掉了(╯°□°)╯︵ ┻━┻
la=c++
首先是使用数组实现的方法
// STRDES.hpp
#pragma once
#include "cstdint"
typedef uint8_t bit;
class __attribute__((unused)) STRDES {
private:
bit mkey[17][64]{}; // 密钥
bit mword[64]{}; // 数据
bit L[17][32]{};
bit R[17][32]{};
private:
void F(bit *source, const bit *Ri, const bit *Ki); // 轮函数F
void E(bit *Ri); // E扩展运算
void S(bit *Ri); // S盒压缩
void P(bit *Ri); // P盒置换
void makeKey(); // 密钥生成
void initialPermutation(); // 初始IP置换
void iterate(bool flag); // 16次迭代
void finalPermutation(); // 逆置换
public:
explicit STRDES(uint64_t word = 0, uint64_t key = 0); // 构造函数
~STRDES(); // 析构函数
__attribute__((unused)) uint64_t encode(); // 一步加密
__attribute__((unused)) uint64_t decode(); // 一步解密
__attribute__((unused)) uint64_t getResult() const; // 获取运算结果
};
// STRDES.cpp
#include "STRDES.hpp"
STRDES::STRDES(uint64_t word, uint64_t key) {
for (int i = 0; i < 64; ++i) {
mword[63 - i] = word & 1;
mkey[0][63 - i] = key & 1;
word >>= 1;
key >>= 1;
}
makeKey();
} // 构造函数
STRDES::~STRDES() = default; // 析构函数
__attribute__((unused)) uint64_t STRDES::encode() {
initialPermutation();
iterate(true);
finalPermutation();
return getResult();
} // 一步加密
__attribute__((unused)) uint64_t STRDES::decode() {
initialPermutation();
iterate(false);
finalPermutation();
return getResult();
} // 一步解密
void STRDES::initialPermutation() {
bit temp[64];
for (int i = 0; i < 64; ++i) {
temp[i] = mword[initial[i] - 1];
}
for (int i = 0; i < 64; ++i) {
mword[i] = temp[i];
}
} // 初始IP置换
void STRDES::finalPermutation() {
bit temp[64];
for (int i = 0; i < 64; ++i) {
mword[i] = i < 32 ? R[16][i] : L[16][i - 32];
}
for (int i = 0; i < 64; ++i) {
temp[i] = mword[final[i] - 1];
}
for (int i = 0; i < 64; ++i) {
mword[i] = temp[i];
}
} // 逆置换
void STRDES::iterate(bool flag) {
for (int i = 0; i < 32; ++i) {
L[0][i] = mword[i];
R[0][i] = mword[i + 32];
}
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 32; ++j) {
L[i + 1][j] = R[i][j];
}
bit temp[32];
F(temp, R[i], mkey[flag ? i + 1 : 16 - i]);
for (int j = 0; j < 32; ++j) {
R[i + 1][j] = L[i][j] ^ temp[j];
}
}
} // 16次迭代
void STRDES::F(bit *source, const bit *Ri, const bit *Ki) {
bit temp[48];
for (int i = 0; i < 48; ++i) {
temp[i] = Ri[i];
}
E(temp);
for (int i = 0; i < 48; ++i) {
temp[i] ^= Ki[i];
}
S(temp);
P(temp);
for (int i = 0; i < 32; ++i) {
source[i] = temp[i];
}
} // 轮函数F
void STRDES::E(bit *Ri) {
bit temp[48];
for (int i = 0; i < 48; ++i) {
temp[i] = Ri[EBox[i] - 1];
}
for (int i = 0; i < 48; ++i) {
Ri[i] = temp[i];
}
} // E扩展运算
void STRDES::S(bit *Ri) {
bit temp[8][6] = {0};
for (int i = 0; i < 48; ++i) {
temp[0][i] = Ri[i];
}
for (int i = 0; i < 8; ++i) {
uint8_t n = 0;
n = SBox[i][(temp[i][0] << 1) | temp[i][5]][(temp[i][1] << 3) | (temp[i][2] << 2) | (temp[i][3] << 1) |
temp[i][4]];
for (int j = 0; j < 4; ++j) {
temp[i][j] = (n >> (3 - j)) & 1;
}
}
for (int i = 0; i < 32; ++i) {
Ri[i] = temp[i / 4][i % 4];
}
} // S盒压缩
void STRDES::P(bit *Ri) {
bit temp[32];
for (int i = 0; i < 32; ++i) {
temp[i] = Ri[i];
}
for (int i = 0; i < 32; ++i) {
Ri[i] = temp[PBox[i] - 1];
}
} // P盒置换
void STRDES::makeKey() {
bit temp[56] = {0}, C[29] = {0}, D[29] = {0};
for (int i = 0; i < 56; ++i) {
temp[i] = mkey[0][PC1[i] - 1];
}
for (int i = 0; i < 28; ++i) {
C[i] = temp[i];
D[i] = temp[i + 28];
}
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < shiftTimes[i]; ++j) {
C[28] = C[0];
D[28] = D[0];
for (int k = 0; k < 28; ++k) {
C[k] = C[k + 1];
D[k] = D[k + 1];
}
}
for (int j = 0; j < 28; ++j) {
temp[j] = C[j];
temp[j + 28] = D[j];
}
for (int j = 0; j < 48; ++j) {
mkey[i + 1][j] = temp[PC2[j] - 1];
}
}
} // 密钥生成
__attribute__((unused)) uint64_t STRDES::getResult() const {
uint64_t temp = 0;
for (bit i : mword) {
temp <<= 1;
temp |= (uint64_t) i;
}
return temp;
} // 获取运算结果
本来想用bool类型来设置bit类型,但是bool会产生bool(204)和bool(205)的错误,所以还是用了uint8_t
写DES的代码最需要注意的是数字在计算机中二进制存储的形式,以及如何进行运算,如果能够将这两点理解透彻,写起代码来将会轻松很多。
休息几天再更新用整数的位运算实现的版本( ̄¬ ̄)毕竟也不是天天能熬夜到五点
竟然只花了一天就把另一版写出来了(我真勤奋)
// BITDES.hpp
#pragma oce
#include "cstdint"
#define MOV28(a, n) (a = ((a << n) | (a >> (28 - n))) & 0x0FFFFFFF)
class __attribute__((unused)) BITDES {
private:
uint64_t mkey[17]{};
uint64_t mword;
uint32_t L[17]{};
uint32_t R[17]{};
private:
uint32_t F(uint32_t Ri, uint64_t Ki); // 轮函数F
uint64_t E(uint32_t Ri); // E扩展运算
uint32_t S(uint64_t Ri); // S盒压缩
uint32_t P(uint32_t Ri); // P盒置换
void makeKey(); // 密钥生成
void initialPermutation(); // 初始IP置换
void iterate(bool flag); // 16次迭代
void finalPermutation(); // 逆置换
public:
explicit BITDES(uint64_t word = 0, uint64_t key = 0); // 构造函数
~BITDES(); // 析构函数
__attribute__((unused)) uint64_t encode(); // 一步加密
__attribute__((unused)) uint64_t decode(); // 一步解密
__attribute__((unused)) uint64_t getResult() const; // 获取运算结果
};
// BITDES.cpp
#include "BITDES.hpp"
BITDES::BITDES(uint64_t word, uint64_t key) : mword(word) {
mkey[0] = key;
makeKey();
}
BITDES::~BITDES() = default;
__attribute__((unused)) uint64_t BITDES::encode() {
initialPermutation();
iterate(true);
finalPermutation();
return getResult();
}
__attribute__((unused)) uint64_t BITDES::decode() {
initialPermutation();
iterate(false);
finalPermutation();
return getResult();
}
void BITDES::initialPermutation() {
uint64_t temp = 0;
for (uint8_t i : initial) {
temp <<= 1;
temp |= (mword >> (64 - i)) & 0x01;
}
mword = temp;
}
void BITDES::finalPermutation() {
uint64_t temp = 0;
temp = ((uint64_t)R[16] << 32) | L[16];
for (uint8_t i : final) {
mword <<= 1;
mword |= (temp >> (64 - i)) & 0x01;
}
}
void BITDES::iterate(bool flag) {
L[0] = mword >> 32;
R[0] = mword & 0xFFFFFFFF;
for (int i = 0; i < 16; ++i) {
L[i + 1] = R[i];
R[i + 1] = L[i] ^ F(R[i], mkey[flag ? i + 1 : 16 - i]);
}
}
uint32_t BITDES::F(uint32_t Ri, uint64_t Ki) {
uint64_t temp = E(Ri);
temp ^= Ki;
return P(S(temp));
}
uint64_t BITDES::E(uint32_t Ri) {
uint64_t temp = 0;
for (uint8_t i : EBox) {
temp <<= 1;
temp |= (((uint64_t)Ri) >> (32 - i)) & 0x01;
}
return temp;
}
uint32_t BITDES::S(uint64_t Ri) {
uint32_t temp1 = 0;
uint8_t temp2[8]{};
for (int i = 0; i < 8; ++i) {
temp2[7 - i] = Ri & 0x3F;
Ri >>= 6;
}
for (int i = 0; i < 8; ++i) {
temp2[i] = SBox[i][((temp2[i] >> 4) & 0x02) | (temp2[i] & 0x01)][(temp2[i] >> 1) & 0x0F];
}
for (uint8_t i : temp2) {
temp1 <<= 4;
temp1 |= i;
}
return temp1;
}
uint32_t BITDES::P(uint32_t Ri) {
uint32_t temp = 0;
for (uint8_t i : PBox) {
temp <<= 1;
temp |= (Ri >> (32 - i)) & 0x01;
}
return temp;
}
void BITDES::makeKey() {
uint64_t temp = 0;
uint32_t C = 0, D = 0;
for (uint8_t i : PC1) {
temp <<= 1;
temp |= ((mkey[0]) >> (64 - i)) & 0x01;
}
C = temp >> 28;
D = temp & 0x0FFFFFFF;
for (int i = 0; i < 16; ++i) {
MOV28(C, shiftTimes[i]);
MOV28(D, shiftTimes[i]);
temp = (((uint64_t)C) << 28) | D;
for (uint8_t j : PC2) {
mkey[i + 1] <<= 1;
mkey[i + 1] |= (temp >> (56 - j)) & 0x01;
}
}
}
__attribute__((unused)) uint64_t BITDES::getResult() const {
return mword;
}
这次是通过整数的位运算实现的,虽然运算速度有了极大的提升(STRDES类运行时间为281毫秒/万次加密,BITDES类运行时间为94毫秒/万次加密,时间缩短为原来的三分之一左右),但是其运算逻辑会更加复杂(头都想炸了),所以不建议一上来就用这种方法( ̄¬ ̄)
Github已开源( ̄¬ ̄):https://github.com/ranhengzhang/DES