一. 个人感悟
该程序实现了DES加密算法的软件实现,使用Golang语言实现核心算法,使用Python实现前端展示程序,功能有字符串的加解密演示、文件的加解密演示。
1. 首先,DES是第一次写, 还是花费了一天多的时间, 包括在网上学习, 手动实现. 同样使用go语言实现, 并且封装了exe.
2. 这次遇到的bug主要是,
1. s盒的时候, 列索引没有初始化变量, 导致越界访问
2. 密钥生成的移位运算没有将结果暂存, 然后进行第二次移位, 而是使用原始的C再进行第二次移位, 导致计算错误,后来修改.
3. 对于DES的这个算法, 网上很多教程, 都是使用置换表去做, 但是我细想, E置换还有一些其他的置换也可以用for来实现的, 但是无奈, 我真的时间不够了, 就先写成这样吧
4. 对于加解密演示程序的密钥生成, 这里暂时没有考虑校验位的值, 算的时候也会被抛弃掉, 后续再看情况补充吧
二. 结果验证
-
我的计算结果:
-
网站验证
-
多余的我就不验证了, 我已经测试好了, 都是对的.
三. 程序源码
-
des.go
/*
************************************************************************
> File Name: des.go
> Author: Yu/Jinyang
> Created Time: 2022/11/15
***********************************************************************
*/
package des
import (
"fmt"
"math"
"strconv"
)
type Des struct {
plain_text string //明文字符串
key string //密钥字符串
key_inter_v [64]uint64
internediate [64]uint64
left [32]uint64
right [32]uint64
eachKey [16][48]uint64
}
func (des *Des) SetVariable(p, k string) {
des.plain_text = p
des.key = k
des.dataFormat()
}
func (des *Des) dataFormat() {
for i := 0; i < 16; i++ {
tem, err := strconv.ParseUint(des.plain_text[i:i+1], 16, 64)
des.internediate[(i*4)+3] = (tem & 0x01) >> 0
des.internediate[(i*4)+2] = (tem & 0x02) >> 1
des.internediate[(i*4)+1] = (tem & 0x04) >> 2
des.internediate[(i*4)+0] = (tem & 0x08) >> 3
if err != nil {
fmt.Println(i, "error")
}
tem, err = strconv.ParseUint(des.key[i:i+1], 16, 64)
des.key_inter_v[(i*4)+3] = (tem & 0x01) >> 0
des.key_inter_v[(i*4)+2] = (tem & 0x02) >> 1
des.key_inter_v[(i*4)+1] = (tem & 0x04) >> 2
des.key_inter_v[(i*4)+0] = (tem & 0x08) >> 3
if err != nil {
fmt.Println(i, "error")
}
}
des.keyGenerate()
}
func (des *Des) initialPermutations() {
IP := [8][8]int{{58, 50, 42, 34, 26, 18, 10, 2},
{60, 52, 44, 36, 28, 20, 12, 4},
{62, 54, 46, 38, 30, 22, 14, 6},
{64, 56, 48, 40, 32, 24, 16, 8},
{57, 49, 41, 33, 25, 17, 9, 1},
{59, 51, 43, 35, 27, 19, 11, 3},
{61, 53, 45, 37, 29, 21, 13, 5},
{63, 55, 47, 39, 31, 23, 15, 7}}
var temp [64]uint64
for i := 0; i < 8; i++ {
for j := 0; j < 8; j++ {
temp[(i*8)+j] = uint64(des.internediate[IP[i][j]-1])
}
}
des.internediate = temp
}
func (des *Des) initialPermutationsInverse() {
IP := [8][8]int{{40, 8, 48, 16, 56, 24, 64, 32},
{39, 7, 47, 15, 55, 23, 63, 31},
{38, 6, 46, 14, 54, 22, 62, 30},
{37, 5, 45, 13, 53, 21, 61, 29},
{36, 4, 44, 12, 52, 20, 60, 28},
{35, 3, 43, 11, 51, 19, 59, 27},
{34, 2, 42, 10, 50, 18, 58, 26},
{33, 1, 41, 9, 49, 17, 57, 25}}
var temp [64]uint64
for i := 0; i < 8; i++ {
for j := 0; j < 8; j++ {
temp[(i*8)+j] = uint64(des.internediate[IP[i][j]-1])
}
}
des.internediate = temp
}
func (des *Des) separateLeftAndRight() {
for i := 0; i < 32; i++ {
des.left[i] = des.internediate[i]
des.right[i] = des.internediate[i+32]
}
}
func (des *Des) format() string {
var ret string
for j := 0; j < 16; j++ {
tem := des.internediate[j*4] << 3
tem += des.internediate[j*4+1] << 2
tem += des.internediate[j*4+2] << 1
tem += des.internediate[j*4+3]
tem2 := fmt.Sprintf("%01x", tem)
ret += tem2
}
return ret
}
func (des *Des) Encode() string {
des.initialPermutations()
// fmt.Println("初始置换: ", des.format())
des.separateLeftAndRight()
// ff
for i := 0; i < 16; i++ {
des.ff(i)
for i := 0; i < 32; i++ {
des.internediate[i+32] = des.right[i]
des.internediate[i] = des.left[i]
}
// fmt.Println("key ", i, ": ", des.eachKey[i])
// fmt.Println("Round ", i, ": ", des.format())
}
// ip-1
for i := 0; i < 32; i++ {
des.internediate[i] = des.right[i]
des.internediate[i+32] = des.left[i]
}
des.initialPermutationsInverse()
// fmt.Println("初始IP置换后:", des.internediate)
return des.format()
}
func (des *Des) Decode() string {
for i := 0; i < 8; i++ {
tem := des.eachKey[i]
des.eachKey[i] = des.eachKey[15-i]
des.eachKey[15-i] = tem
}
return des.Encode()
}
func (des *Des) ff(i int) {
tem := des.eTransform()
tem2 := des.xorWithKey(i, tem)
tem3 := des.ss(tem2)
tem4 := des.pTransform(tem3)
tem5 := des.xorWithL0(tem4)
des.left = des.right
des.right = tem5
}
func (des *Des) eTransform() [48]uint64 {
var ret [48]uint64
bitChoiceLabel := [48]uint64{32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1}
for i := 0; i < 48; i++ {
ret[i] = des.right[bitChoiceLabel[i]-1]
}
return ret
}
func (des *Des) xorWithKey(i int, tempv [48]uint64) [48]uint64 {
var ret [48]uint64
for j := 0; j < 48; j++ {
ret[j] = tempv[j] ^ des.eachKey[i][j]
}
return ret
}
func (des *Des) ss(tempv [48]uint64) [32]uint64 {
boxS := [8][4][16]uint64{ //S1
{{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
//S2
{{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
//S3
{{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
//S4
{{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
//S5
{{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
//S6
{{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
//S7
{{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
//S8
{{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}}
var row uint64 = 0
var column uint64 = 0
var ret [32]uint64
for i := 0; i < 8; i++ {
column = 0
row = tempv[i*6]*2 + tempv[(i*6)+5]
for j := 1; j < 5; j++ {
base := uint64(math.Pow(2, float64(4-j)))
column += tempv[(i*6)+j] * base
}
tem_ret := boxS[i][row][column]
ret[i*4] = (tem_ret & 0x08) >> 3
ret[i*4+1] = (tem_ret & 0x04) >> 2
ret[i*4+2] = (tem_ret & 0x02) >> 1
ret[i*4+3] = (tem_ret & 0x01)
}
return ret
}
func (des *Des) pTransform(tempv [32]uint64) [32]uint64 {
P := [32]uint64{16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25}
var ret [32]uint64
for i := 0; i < 32; i++ {
ret[i] = tempv[P[i]-1]
}
return ret
}
func (des *Des) xorWithL0(tempv [32]uint64) [32]uint64 {
var ret [32]uint64
for i := 0; i < 32; i++ {
ret[i] = tempv[i] ^ des.left[i]
}
return ret
}
func (des *Des) keyGenerate() {
left_move := [16]int{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
var c [28]uint64
var d [28]uint64
tem_56 := des.pc1Trancform()
// c, d
for j := 0; j < 28; j++ {
c[j] = tem_56[j]
d[j] = tem_56[j+28]
}
for i := 0; i < 16; i++ {
//c1, d1
c = des.leftShift(left_move[i], c)
d = des.leftShift(left_move[i], d)
for j := 0; j < 28; j++ {
tem_56[j] = c[j]
tem_56[j+28] = d[j]
}
des.eachKey[i] = des.pc2Trancform(tem_56)
}
}
func (des *Des) leftShift(i int, c [28]uint64) [28]uint64 {
var ret [28]uint64
for j := 0; j < i; j++ {
tem_0 := c[0]
for k := 0; k < 27; k++ {
ret[k] = c[k+1]
}
ret[27] = tem_0
c = ret
}
return ret
}
func (des *Des) pc1Trancform() [56]uint64 {
pc_1 := [8][7]uint64{{57, 49, 41, 33, 25, 17, 9},
{1, 58, 50, 42, 34, 26, 18},
{10, 2, 59, 51, 43, 35, 27},
{19, 11, 3, 60, 52, 44, 36},
{63, 55, 47, 39, 31, 23, 15},
{7, 62, 54, 46, 38, 30, 22},
{14, 6, 61, 53, 45, 37, 29},
{21, 13, 5, 28, 20, 12, 4}}
var temp [56]uint64
for i := 0; i < 8; i++ {
for j := 0; j < 7; j++ {
temp[(i*7)+j] = uint64(des.key_inter_v[pc_1[i][j]-1])
}
}
return temp
}
func (des *Des) pc2Trancform(cd [56]uint64) [48]uint64 {
pc_2 := [8][6]uint64{{14, 17, 11, 24, 1, 5},
{3, 28, 15, 6, 21, 10},
{23, 19, 12, 4, 26, 8},
{16, 7, 27, 20, 13, 2},
{41, 52, 31, 37, 47, 55},
{30, 40, 51, 45, 33, 48},
{44, 49, 39, 56, 34, 53},
{46, 42, 50, 36, 29, 32}}
var temp [48]uint64
for i := 0; i < 8; i++ {
for j := 0; j < 6; j++ {
temp[(i*6)+j] = uint64(cd[pc_2[i][j]-1])
}
}
return temp
}
2.des_core.go
/*
************************************************************************
> File Name: main.go
> Author: Yu/Jinyang
> Created Time: 2022/11/15
***********************************************************************
*/
package main
import (
"des-demo/des"
"fmt"
)
func main() {
var plaintext string
// fmt.Println("请输入64位明文(16进制):")
fmt.Scanln(&plaintext)
// plaintext = "5469875321456045"
var key string
// fmt.Println("请输入64位密钥(16进制):")
fmt.Scanln(&key)
// key = "5987423651456987"
des := des.Des{}
des.SetVariable(plaintext, key)
ciphertext := des.Encode()
fmt.Println(ciphertext)
plain_text_decoded := des.Decode()
fmt.Println(plain_text_decoded)
}
3.main.py
import binascii
import os
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QMessageBox
from random import *
from StaticUI.MainWindow import Ui_MainWindow
import subprocess
# 22kb 50s
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.init_ui()
self.bind_button()
self.plaintext = ""
self.key = ""
self.key2 = ""
self.filepath = ""
def init_ui(self):
self.label_12.setTextInteractionFlags(Qt.TextSelectableByMouse)
pass
def bind_button(self):
self.pushButton_2.clicked.connect(self.auto_gen_plaintext)
self.pushButton_3.clicked.connect(self.auto_gen_key)
self.pushButton_6.clicked.connect(self.auto_gen_key2)
self.pushButton_4.clicked.connect(self.str_encode_decode)
self.pushButton_5.clicked.connect(self.file_encode_decode)
self.toolButton_4.clicked.connect(self.pick_file)
pass
def str_encode_decode(self):
if len(self.plaintext) != 17 or len(self.key) != 17:
QMessageBox.information(self, "警告", "明文或密钥长度不对!", QMessageBox.Yes)
else:
ret = subprocess.Popen(
"des_core.exe",
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
)
ret.stdin.write(self.plaintext.encode())
ret.stdin.flush()
ret.stdin.write(self.key.encode())
ret.stdin.flush()
ans1 = ret.stdout.readline().decode()
ans2 = ret.stdout.readline().decode()
ret.wait()
self.lineEdit_3.setText(ans1)
self.lineEdit_4.setText(ans2)
pass
def file_encode_decode(self):
if len(self.key2) != 17:
QMessageBox.information(self, "警告", "明文或密钥长度不对!", QMessageBox.Yes)
else:
self.lineEdit_6.setText("加密中, 请等待!")
self.lineEdit_5.setText("解密中, 请等待!")
f = open(self.filepath, "rb")
output_encode_file = open("des_encrypted.txt", "wb")
output_decode_file = open("decode" + self.filepath[-4:], "wb")
output_encode_buff = ""
output_decode_buff = ""
while 1:
c = f.read(4)
if not c:
break
else:
cc = binascii.hexlify(c)
cc = str(cc, encoding="utf-8")
fill = 0
if len(cc) < 16:
fill = 16 - len(cc)
cc += (fill) * "0"
cc += "\n"
cy, m = self.encode_decode(cc, self.key2)
# cy = str(cy, encoding='utf-8')
cy = cy[:16]
cy = binascii.unhexlify(cy)
# m = str(m, encoding='utf-8')
m = m[:16 - fill]
m = binascii.unhexlify(m)
# output_encode_buff += cy
# output_decode_buff += m
output_encode_file.write(cy)
output_decode_file.write(m)
pass
self.lineEdit_6.setText(os.getcwd() + "\\des_encrypted.txt")
self.lineEdit_5.setText(os.getcwd() + "\\decode" + self.filepath[-4:])
pass
def auto_gen_plaintext(self):
plaintext = "".join([choice("0123456789abcdef") for i in range(16)])
self.plaintext = plaintext + "\n"
self.lineEdit.setText(plaintext)
pass
def auto_gen_key(self):
plaintext = "".join([choice("0123456789abcdef") for i in range(16)])
self.key = plaintext + "\n"
self.lineEdit_2.setText(plaintext)
pass
def auto_gen_key2(self):
plaintext = "".join([choice("0123456789abcdef") for i in range(16)])
self.key2 = plaintext + "\n"
self.lineEdit_7.setText(plaintext)
pass
def pick_file(self):
filename, filetype = QtWidgets.QFileDialog.getOpenFileName(self, "选取文件",
os.getcwd() + '\\',
"All Files(*);;Text Files(*.txt)")
self.filepath = filename
self.toolButton_4.setText(filename)
@staticmethod
def encode_decode(plaintext, key):
ret = subprocess.Popen(
"des_core.exe",
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
)
ret.stdin.write(plaintext.encode())
ret.stdin.flush()
ret.stdin.write(key.encode())
ret.stdin.flush()
ans1 = ret.stdout.readline()
ans2 = ret.stdout.readline()
ret.wait()
# print(ans1, ans2)
return ans1, ans2
pass
def main():
app = QtWidgets.QApplication(sys.argv) # 初始化app
test = MainWindow()
test.show()
sys.exit(app.exec_())
pass
if __name__ == '__main__':
main()