DES加密算法|密码学|信息安全
普拉诺格涅斯Planegenes
编辑于 2022年11月22日 02:16

基本原理

  • 对称算法&分组加密

  • 密钥长度64bit,每连续8bit为一个部分,该部分中前7bit参与运算,第8bit为校验位

  • 由于进行块加密,将明文拆分为n*64bit之后加密得到的n*64bit合在一起就是密文

加密过程

01:34

  1. 初始IP置换

  2. 16轮次迭代

  3. 逆置换

初始IP置换

05:12

# 两张表分别为初始IP置换和逆置换的表,表中的数字表示在进行置换时,该位应置换为第几位

16轮次迭代

  1. 将64bit数据分为L0&R0/H0&L0

  2. L1/H1=R0/L0

  3. R1/L1=L0/H0⨁F(R0/L0, K1) # F函数为将R0/H0与K1进行轮函数运算

  4. 重复2-3直到16次

轮函数F()

  1. 32bitR0/L0-->48bitR0/L0 # E扩展置换

  2. 48bitR0/L0⨁48bitK1 #K1通过密钥生成获得

  3. 48R0/L0--S盒压缩-->32bitR0/L0

  4. 32bitR0/L0--P盒换-->32bitR0/L0

E扩展置换

06:04

S盒压缩处理

08:45

  1. 将48bit分为8*6bit

  2. 根据“8个6进4出S盒”进行压缩

6进4出S盒

09:14

09:34

  1. 6bit数据取出头尾两个bit组成2bit数据,将2bit数据转换为十进制,即为该盒子的行数 # 对第几个6bit进行压缩就使用第几个S盒

  2. 中间4bit数据转换为十进制即为该盒子的列数

  3. 将盒中对应数字转换为2进制即为压缩结果

P盒置换

10:55

# P盒置换之后就将结果与L0/H0进行异或

逆置换

经过16轮次迭代之后得到的L16&R16/H16&L16拼接结果根据逆置换表置换得到结果

逆置换拼接时L16&R16/H16&L16的顺序与初始置换时相反

密钥生成

12:11

14:18

15:50

  1. 将64bit密钥K0根据PC-1表进行换得到56bit数据

  2. 将56bit数据分为28bit的C0&D0

  3. C0&D0根据移位次数表移位得到C1&D1 # 该处位移为2*28bit的循环左移

  4. C1&D1结果拼接之后的56bit数据根据PC-2表进行换得到48bit密钥K1

  5. 重复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

需要自己引入类然后使用!