Simplified-DES的实现

Simplified-DES的实现

题目描述

2.1实验目的

1) 学习S-DES密码算法的原理
2) 掌握S-DES密码算法的实现

2.2实验原理

1) 算法原理

Simplified DES方案,简称S-DES方案,是DES算法的简化版。它是一个供教学而非安全的加密算法,它与DES的特性和结构类似,但参数小。

加密算法涉及五个函数:

(1)初始置换IP(initial permutation)

(2)复合函数fk1,它是由密钥K确定的,具有置换和代换的运算。

(3)置换函数SW

(4)复合函数fk2

(5)初始置换IP的逆置换IP-1

img

image-20221117163107876

image-20221117163120527

image-20221117163129135

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的解密。

输入

第一行输入主密钥

第二行输入明文

输入样例1:

1100011110
00101000
0111111101
00010110

输出

输出密文

输出样例1

10001010
01110110

AC代码

(虽然看着很长,但是注释占了快一半),核心逻辑的函数都封装好了,实现起来很简单。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Simplified-DES的实现
 *
 * @author xzx
 * @date 2022/11/17
 */
public class Main {

    /**
     * 算法参数——S-DES所需的几个置换表
     */
    static final int[] P10 = new int[]{3, 5, 2, 7, 4, 10, 1, 9, 8, 6};
    static final int[] P8 = new int[]{6, 3, 7, 4, 8, 5, 10, 9};
    static final int[] P4 = new int[]{2, 4, 3, 1};
    static final int[] IP = new int[]{2, 6, 3, 1, 4, 8, 5, 7};
    static final int[] IP_1 = new int[]{4, 1, 3, 5, 7, 2, 8, 6};
    static final int[] EP = new int[]{4, 1, 2, 3, 2, 3, 4, 1};
    static final int[][] S0 = new int[][]{
            {1, 0, 3, 2},
            {3, 2, 1, 0},
            {0, 2, 1, 3},
            {3, 1, 3, 2},
    };
    static final int[][] S1 = new int[][]{
            {0, 1, 2, 3},
            {2, 0, 1, 3},
            {3, 0, 1, 0},
            {2, 1, 0, 3},
    };

    public static void main(String[] args) {
        String m, key;
//        m = "00010110";
//        key = "0111111101";
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            key = scanner.next();
            m = scanner.next();
            // a)子密钥的生成
            List<String> childKeys = generateChildKeys(key);
            // b)加密过程
            String encryptedText = encrypt(m, childKeys);
            System.out.println(encryptedText);
            // c) 解密过程
            String decryptedText = decrypt(encryptedText, childKeys);
        }
    }

    /**
     * 解密
     *
     * @param encryptedText
     * @param childKeys
     * @return
     */
    private static String decrypt(String encryptedText, List<String> childKeys) {
        //解密过程与加密基本一致,就是密钥使用顺序是相反的,第一次循环使用K2第二次循环使用K1。
        String tmp = childKeys.get(0);
        childKeys.set(0, childKeys.get(1));
        childKeys.set(1, tmp);
        return encrypt(encryptedText, childKeys);
    }


    /**
     * 加密
     *
     * @param m         明文
     * @param childKeys 子密钥
     * @return
     */
    private static String encrypt(String m, List<String> childKeys) {
        // 首先是初始置换
        // ① 对明文m=0001 0110做IP置换(IP={2,6,3,1,4,8,5,7}),得m’=0100 1001
        String m_ = SW(m, IP);
        String res1 = loop(getLeft(m_), getRight(m_), childKeys.get(0));
        // 接下来是标准的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’)作为输入
        // 开始第二次循环
        String res2 = loop(getRight(res1), getLeft(res1), childKeys.get(1));
        // ⑩ 记左半为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.
        return SW(res2, IP_1);
        // OK,到这里就完成了将明文加密为密文,S-DES加密结束。
    }

    /**
     * @param left
     * @param right
     * @param key
     * @return
     */
    private static String loop(String left, String right, String key) {
        // 1.对右半做EP扩展置换
        String r_ = SW(right, EP);
        // 2.r_与密钥key按位异或
        r_ = xor(r_, key);
        // 3.r_左半进入S0,右半进入S1
        r_ = boxSW(getLeft(r_), S0) + boxSW(getRight(r_), S1);
        // 4. r_P4置换
        r_ = SW(r_, P4);
        // 5.l和r_异或
        String l_ = xor(r_, left);
        // 6.组合
        return l_ + right;
    }

    /**
     * 二维盒置换
     *
     * @param str
     * @param s
     * @return
     */
    private static String boxSW(String str, int[][] s) {
        // ⑤ Rm’左半1001(A1A2A3A4)进入S0盒替代选择得11(第4行A1A4 /第1列A2A3的数字3,再转成二进制11,A1A4中A1是数位高位),
        // 右半1100进入S1盒替代选择的01(第3行10/第3列10的数字1),组合后得Rm’=1101
        int row = getDEC(str.charAt(0), str.charAt(3));
        int col = getDEC(str.charAt(1), str.charAt(2));
        StringBuilder res = new StringBuilder(Integer.toBinaryString(s[row][col]));
        while (res.length() < 2) {
            res.insert(0, '0');
        }
        return res.toString();
    }

    /**
     * 二进制转十进制
     *
     * @param a
     * @param b
     * @return
     */
    private static int getDEC(char a, char b) {
        String s = String.valueOf(a) + b;
        return Integer.valueOf(s, 2);
    }

    /**
     * 按位异或
     *
     * @param s1
     * @param s2
     * @return
     */
    private static String xor(String s1, String s2) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < s1.length(); i++) {
            stringBuilder.append(Character.getNumericValue(s1.charAt(i)) ^ Character.getNumericValue(s2.charAt(i)));
        }
        return stringBuilder.toString();
    }

    /**
     * 生成子密钥
     *
     * @param key
     * @return
     */
    private static List<String> generateChildKeys(String key) {
        // ① 10位密钥key = 01111 11101
        // ② 对key做P10置换(P10={3,5,2,7,4,10,1,9,8,6})得到 11111 10011
        key = SW(key, P10);
        // ③ 记左半(高位)的为Lk=11111,右半(低位)为Rk=10011
        // ④ LS-1:Lk和Rk均循环左移1位,得到Lk=11111,Rk=00111
        String LK = move(getLeft(key), -1);
        String RK = move(getRight(key), -1);
        // ⑤ 对Lk和Rk组合得到的11111 00111做P8置换(P8={6,3,7,4,8,5,10,9})选择,得到子密钥K1=0101 1111
        String K1 = SW(LK + RK, P8);
        // LS-2:Lk和Rk均再次循环左移2位,得到Lk=11111,Rk=11100
        LK = move(LK, -2);
        RK = move(RK, -2);
        // P8:对Lk和Rk组合得到的11111 11100做P8置换选择,得到子密钥K2=1111 1100
        String K2 = SW(LK + RK, P8);
        ArrayList<String> childKeys = new ArrayList<>();
        childKeys.add(K1);
        childKeys.add(K2);
        return childKeys;
    }

    private static String getRight(String key) {
        return key.substring(key.length() / 2);
    }

    private static String getLeft(String key) {
        return key.substring(0, key.length() / 2);
    }

    /**
     * 循环循环移动step位
     *
     * @param str
     * @param step
     * @return
     */
    private static String move(String str, int step) {
        int length = str.length();
        step = step % length;
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int idx = (i - step) % length;
            if (idx < 0) idx += length;
            stringBuilder.append(str.charAt(idx));
        }
        return stringBuilder.toString();
    }

    /**
     * 置换
     *
     * @param key
     * @param p   p4/p8/p10/IP等
     */
    private static String SW(String key, int[] p) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < p.length; i++) {
            stringBuilder.append(key.charAt(p[i] - 1));
        }
        return stringBuilder.toString();
    }

}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奥库甘道夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值