题目描述
实验目的
1) 学习S-DES密码算法的原理
2) 掌握S-DES密码算法的实现
实验原理
1) 算法原理
Simplified DES方案,简称S-DES方案,是DES算法的简化版。它是一个供教学而非安全的加密算法,它与DES的特性和结构类似,但参数小。
加密算法涉及五个函数:
(1)初始置换IP(initial permutation)
(2)复合函数fk1,它是由密钥K确定的,具有置换和代换的运算。
(3)置换函数SW
(4)复合函数fk2
(5)初始置换IP的逆置换IP-1
[图片上传失败...(image-13062e-1668674986761)]
2) 算法参数——S-DES所需的几个置换表
① P10={3,5,2,7,4,10,1,9,8,6}
② P8={6,3,7,4,8,5,10,9} 注意这个置换选择输入10位输出8位
③ P4={2,4,3,1}
④ IP={2,6,3,1,4,8,5,7}
⑤ IP-1={4,1,3,5,7,2,8,6}
⑥ EP={4,1,2,3,2,3,4,1} 注意这个是扩展置换,输入4位输出8位
⑦ 两个S盒:
S0:
{1,0,3,2}
{3,2,1,0}
{0,2,1,3}
{3,1,3,2}
S1:
{0,1,2,3}
{2,0,1,3}
{3,0,1,0}
{2,1,0,3}
3) 算法说明
若明文为: m=0001 0110, key选为(01111 11101),给出加密过程和解密过程,并计算出密文和明文。
a)子密钥的生成
① 10位密钥key = 01111 11101
② 对key做P10置换(P10={3,5,2,7,4,10,1,9,8,6})得到 11111 10011
③ 记左半(高位)的为Lk=11111,右半(低位)为Rk=10011
④ LS-1:Lk和Rk均循环左移1位,得到Lk=11111,Rk=00111
⑤ 对Lk和Rk组合得到的11111 00111做P8置换(P8={6,3,7,4,8,5,10,9})选择,得到子密钥K1=0101 1111
⑥ LS-2:Lk和Rk均再次循环左移2位,得到Lk=11111,Rk=11100
⑦ P8:对Lk和Rk组合得到的11111 11100做P8置换选择,得到子密钥K2=1111 1100
以上,通过密钥得到了算法所需的子密钥。
b)加密过程
首先是初始置换
① 对明文m=0001 0110做IP置换(IP={2,6,3,1,4,8,5,7}),得m’=0100 1001
接下来是标准的Feistel密码结构,共有两次循环。
第一次循环
② 记左半(高位)为Lm=0100,右半(低位)为Rm=1001
③ 对Rm做EP扩展置换(EP={4,1,2,3,2,3,4,1}),得Rm’=1100 0011
④ Rm’与子密钥K1按位异或(K1=0101 1111),得Rm’=1001 1100
⑤ Rm’左半1001(A1A2A3A4)进入S0盒替代选择得11(第4行A1A4 /第1列A2A3的数字3,再转成二进制11,A1A4中A1是数位高位),右半1100进入S1盒替代选择的01(第3行10/第3列10的数字1),组合后得Rm’=1101
⑥ 对Rm’做P4置换(P4={2,4,3,1}),得Rm’=1101
⑦ Rm’与Lm按位异或,得Lm’=1001
⑧ Lm’与Rm(最开始的那个Rm)组合得到输出 1001(Lm’) 1001(Rm)
至此完成第一次循环。
⑨ 然后交换高低位,作为第二次循环的输入,即1001(Rm)1001(Lm’)作为输入
开始第二次循环
⑩ 记左半为Ln=1001,右半为Rn=1001
11 对Rn做EP扩展置换(EP={4,1,2,3,2,3,4,1}),得Rn’=1100 0011
12 Rn’与子密钥K2按位异或(K2=1111 1100),得Rn’=0011 1111
13 Rn’左半0011进入S0盒替代选择得10(第2行01/第2列01的数字2,再转成二进制10),右半1111进入S1盒替代选择的11(第4行11/第4列11的数字3,再转成二进制11),组合后得Rn’=1011
14 对Rn’做P4置换(P4={2,4,3,1}),得Rn’=0111
15 Rn’与Ln按位异或,得Ln’=1110
16 Ln’与Rn(最开始的那个Rn)组合得到输出 1110(Ln’) 1001(Rn)
至此完成第二次循环
17 最后进行逆初始置换对上面的输出m’=1110 1001做IP-1置换得到密文m’=0111 0110.
OK,到这里就完成了将明文加密为密文,S-DES加密结束。
c)解密过程
解密过程与加密基本一致,就是密钥使用顺序是相反的,第一次循环使用K2第二次循环使用K1。
首先还是初始置换
① 对密文m=0111 0110做IP置换(IP={2,6,3,1,4,8,5,7}),得m’=1110 1001
Feistel密码结构
第一次循环
② 记左半(高位)为Lm=1110,右半(低位)为Rm=1001
③ 对Rm做EP扩展置换(EP={4,1,2,3,2,3,4,1}),得Rm’=1100 0011
④ Rm’与子密钥K2按位异或(K2=1111 1100),得Rm’=0011 1111
⑤ Rm’左半0011进入S0盒替代选择得10(第2行01/第2列01的数字2,再转成二进制10),右半1111进入S1盒替代选择的11(第4行11/第4列11的数字3,再转成二进制11),组合后得Rm’=1011
⑥ 对Rm’做P4置换(P4={2,4,3,1}),得Rm’=0111
⑦ Rm’与Lm按位异或,得Lm’=1001
⑧ Lm’与Rm(最开始的那个Rm)组合得到输出 1001(Lm’) 1001(Rm)
至此完成第一次循环。
⑨ 然后交换高低位,作为第二次循环的输入,即1001(Rm) 1001(Lm’)作为输入
开始第二次循环
⑩ 记左半为Ln=1001,右半为Rn=1001
11 对Rn做EP扩展置换(EP={4,1,2,3,2,3,4,1}),得Rn’=1100 0011
12 Rn’与子密钥K1按位异或(K1=0101 1111),得Rn’=1001 1100
13 Rn’左半1001进入S0盒替代选择得11(第4行11/第1列00的数字3,再转成二进制11),右半1100进入S1盒替代选择的01(第3行10/第3列10的数字1),组合后得Rn’=1101
14 对Rn’做P4置换(P4={2,4,3,1}),得Rn’=1101
15 Rn’与Ln按位异或,得Ln’=0100
16 Ln’与Rn(最开始的那个Rn)组合得到输出0100(Ln’) 1001(Rn)
至此完成第二次循环。
17 最后进行逆初始置换
18 对上面的输出m’=0100 1001做IP-1置换(IP-1={4,1,3,5,7,2,8,6})得到明文m’=0001 0110.
这样就完成的S-DES的解密。
输入
第一行输入主密钥
第二行输入明文
输出
输出密文
输入样例
1100011110
00101000
0111111101
00010110
输出样例
10001010
01110110
解题
这里先贴代码,因为当初我按照一步一步来,没有分模块。可能是一种面向过程的编程。
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
func id193(_r io.Reader, _w io.Writer) {
in := bufio.NewReader(_r)
out := bufio.NewWriter(_w)
defer out.Flush()
var key, text string
P10 := []int{3, 5, 2, 7, 4, 10, 1, 9, 8, 6}
P8 := []int{6, 3, 7, 4, 8, 5, 10, 9}
P4 := []int{2, 4, 3, 1}
IP := []int{2, 6, 3, 1, 4, 8, 5, 7}
IP1 := []int{4, 1, 3, 5, 7, 2, 8, 6}
S0 := [][]string{{"01", "01", "11", "10"},
{"11", "10", "01", "00"},
{"00", "10", "01", "11"},
{"11", "01", "11", "10"}}
S1 := [][]string{{"00", "01", "10", "11"},
{"10", "00", "01", "11"},
{"11", "00", "01", "00"},
{"10", "01", "00", "11"}}
EP := []int{4, 1, 2, 3, 2, 3, 4, 1}
for {
if _, err := fmt.Fscan(in, &key, &text); err != io.EOF {
var convP10 strings.Builder
for i := range P10 {
fmt.Fprint(&convP10, string(key[P10[i]-1]))
}
Lk := convP10.String()[1:5] + convP10.String()[0:1]
Rk := convP10.String()[6:] + convP10.String()[5:6]
key2 := Lk + Rk
var convP8 strings.Builder
for i := range P8 {
fmt.Fprint(&convP8, string(key2[P8[i]-1]))
}
K1 := convP8.String()
key2 = Lk[2:5] + Lk[0:2] + Rk[2:5] + Rk[0:2]
var K2_ strings.Builder
for i := range P8 {
fmt.Fprint(&K2_, string(key2[P8[i]-1]))
}
K2 := K2_.String()
// fmt.Println(K1, K2)
var convText_ strings.Builder
for i := range IP {
fmt.Fprint(&convText_, string(text[IP[i]-1]))
}
Lm := convText_.String()[:4]
Rm := convText_.String()[4:]
Rm_ := []int{}
for i := range EP {
v, err := strconv.Atoi(string(Rm[EP[i]-1]))
if err == nil {
Rm_ = append(Rm_, v)
}
}
// fmt.Println(Rm_)
for i := range Rm_ {
v, _ := strconv.Atoi(string(K1[i]))
Rm_[i] ^= v
}
// fmt.Println(Rm_)
Rm1 := S0[Rm_[0]*2+Rm_[3]][Rm_[1]*2+Rm_[2]]
Rm2 := S1[Rm_[4]*2+Rm_[7]][Rm_[5]*2+Rm_[6]]
var Lm_ []int
Rm__ := Rm1 + Rm2
for i := range P4 {
tmp1, _ := strconv.Atoi(string(Rm__[P4[i]-1]))
tmp2, _ := strconv.Atoi(string(Lm[i]))
Lm_ = append(Lm_, tmp1^tmp2)
}
// fmt.Println(Lm_, Rm)
Rn_ := []int{}
for i := range EP {
v, _ := strconv.Atoi(string(K2[i]))
Rn_ = append(Rn_, Lm_[EP[i]-1]^v)
}
Rn1 := S0[Rn_[0]*2+Rn_[3]][Rn_[1]*2+Rn_[2]]
Rn2 := S1[Rn_[4]*2+Rn_[7]][Rn_[5]*2+Rn_[6]]
res := ""
for i := range P4 {
v, _ := strconv.Atoi(string((Rn1 + Rn2)[P4[i]-1]))
b, _ := strconv.Atoi(string(Rm[i]))
res += strconv.Itoa(v ^ b)
}
var ans strings.Builder
fmt.Fprint(&ans, res)
for i := range Lm_ {
v := strconv.Itoa(Lm_[i])
fmt.Fprint(&ans, v)
}
ans1 := ans.String()
for i := range IP1 {
fmt.Print(string(ans1[IP1[i]-1]))
}
fmt.Println()
} else {
break
}
}
}
func main() {
id193(os.Stdin, os.Stdout)
}