对称密码系列|DES杂谈以及CTF中的考点

前言

本文讨论了数据加密标准 (DES),这是一种历史悠久的加密算法,以其 56 位密钥长度而闻名。我们将探讨它的运行、密钥转换和加密过程,阐明它在数据安全中的作用及其在当今背景下的脆弱性。


一、DES是什么?

DES的具体流程如下

加密

对明文M的加密流程可以简单理解为

解密

那么我们要如何解密呢,只需要将密文经过最后一步逆置换,那么就可以得到最后一轮的输出,这时候每一轮的输出为:

解密我们可以理解为

Feistal结构的精妙之处正体现在加密和加密上,DES 加解密使用同一套逻辑,只是密钥使用的顺序不一致,解密时只需将密钥倒置再走一步与加密相同的流程即可。

核心部件

  • 初始置换
  • F 函数
    • E 扩展函数
    • S 盒,设计标准未给出。
    • P 置换
  • 最后P置换

在 DES 的基础上,衍生了以下两种加密方式,我们在这里就不过多阐述了。

  • 双重 DES
  • 三种 DES

二、常见的DES解密

from operator import add
from typing import List
from functools import reduce

_IP = [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,
	56, 48, 40, 32, 24, 16, 8,  0,
	58, 50, 42, 34, 26, 18, 10, 2,
	60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
	  0, 57, 49, 41, 33, 25, 17,
	  9,  1, 58, 50, 42, 34, 26,
	  6, 61, 53, 45, 37, 29, 21,
	 18, 10,  2, 59, 51, 43, 35,
	 62, 54, 46, 38, 30, 22, 14,
	 13,  5, 60, 52, 44, 36, 28,
	 20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
	13, 16, 10, 23,  0,  4,
	 2, 27, 14,  5, 20,  9,
	22, 18, 11,  3, 25,  7,
	43, 48, 38, 55, 33, 52,
	15,  6, 26, 19, 12,  1,
	40, 51, 30, 36, 46, 54,
	29, 39, 50, 44, 32, 47,
	45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 3, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半

    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
	31,  0,  1,  2,  3,  4,
	 3,  4,  5,  6,  7,  8,
	 7,  8,  9, 10, 11, 12,
	11, 12, 13, 14, 15, 16,
	15, 16, 17, 18, 19, 20,
	19, 20, 21, 22, 23, 24,
	23, 24, 25, 26, 27, 28,
	27, 28, 29, 30, 31,  0
]
__sbox = [
		# 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],
	]
__p = [
	15, 6, 19, 20, 28, 11,
	27, 16, 0, 14, 22, 25,
	4, 17, 30, 9, 1, 7,
	23,13, 31, 26, 2, 8,
	18, 12, 29, 5, 21, 10,
	3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    """
    index: 代表这是第几轮
    R: 输入数据
    skeys: 子密钥数组
    """
    R = EP(R)  # 扩展置换
    R = list(map(lambda x, y: x ^ y, R, skeys[index]))  # 异或

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
	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,
	32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))

plain = b'********'
key = b'12345678'

# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
plain = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in plain])
skeys = get_sub_key(key)

block = IP(plain)

L, R = block[:32], block[32:]
for i in range(16):
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)
enc = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
    
print(enc) 
# b'O5\xc9}\x7f`\xe8\xa8'

该题中能直接获取密钥和对应的密文,所以直接解密即可得出明文

题解:

from operator import add
from typing import List
from functools import reduce

_IP = [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,
    56, 48, 40, 32, 24, 16, 8,  0,
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
    0, 57, 49, 41, 33, 25, 17,
    9,  1, 58, 50, 42, 34, 26,
    6, 61, 53, 45, 37, 29, 21,
    18, 10,  2, 59, 51, 43, 35,
    62, 54, 46, 38, 30, 22, 14,
    13,  5, 60, 52, 44, 36, 28,
    20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
    13, 16, 10, 23,  0,  4,
    2, 27, 14,  5, 20,  9,
    22, 18, 11,  3, 25,  7,
    43, 48, 38, 55, 33, 52,
    15,  6, 26, 19, 12,  1,
    40, 51, 30, 36, 46, 54,
    29, 39, 50, 44, 32, 47,
    45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 3, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半

    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
    31,  0,  1,  2,  3,  4,
    3,  4,  5,  6,  7,  8,
    7,  8,  9, 10, 11, 12,
    11, 12, 13, 14, 15, 16,
    15, 16, 17, 18, 19, 20,
    19, 20, 21, 22, 23, 24,
    23, 24, 25, 26, 27, 28,
    27, 28, 29, 30, 31,  0
]
__sbox = [
        # 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],
    ]
__p = [
    15, 6, 19, 20, 28, 11,
    27, 16, 0, 14, 22, 25,
    4, 17, 30, 9, 1, 7,
    23,13, 31, 26, 2, 8,
    18, 12, 29, 5, 21, 10,
    3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    R = EP(R)  # 扩展置换
    R = list(map(lambda x, y: x ^ y, R, skeys[index]))  # 异或

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
    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,
    32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))

enc = b'O5\xc9}\x7f`\xe8\xa8'
key = b'12345678'

# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
enc = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in enc])
skeys = get_sub_key(key)

block = IP(enc)

L, R = block[:32], block[32:]
for i in range(15, -1, -1):
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)
plain = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
    
print(plain)

解密关键点只需要将16轮循环逆过来操作即可,这个设计很巧妙

三、DES缺少密钥

from operator import add
from typing import List
from functools import reduce

_IP = [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,
	56, 48, 40, 32, 24, 16, 8,  0,
	58, 50, 42, 34, 26, 18, 10, 2,
	60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
	  0, 57, 49, 41, 33, 25, 17,
	  9,  1, 58, 50, 42, 34, 26,
	 18, 10,  2, 59, 51, 43, 35,
	 62, 54, 46, 38, 30, 22, 14,
	  6, 61, 53, 45, 37, 29, 21,
	 13,  5, 60, 52, 44, 36, 28,
	 20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
	13, 16, 10, 23,  0,  4,
	 2, 27, 14,  5, 20,  9,
	22, 18, 11,  3, 25,  7,
	15,  6, 26, 19, 12,  1,
	40, 51, 30, 36, 46, 54,
	29, 39, 50, 44, 32, 47,
	43, 48, 38, 55, 33, 52,
	45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半

    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
	31,  0,  1,  2,  3,  4,
	 3,  4,  5,  6,  7,  8,
	 7,  8,  9, 10, 11, 12,
	11, 12, 13, 14, 15, 16,
	15, 16, 17, 18, 19, 20,
	19, 20, 21, 22, 23, 24,
	23, 24, 25, 26, 27, 28,
	27, 28, 29, 30, 31,  0
]
__sbox = [
		# 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],
	]
__p = [
	15, 6, 19, 20, 28, 11,
	27, 16, 0, 14, 22, 25,
	4, 17, 30, 9, 1, 7,
	23,13, 31, 26, 2, 8,
	18, 12, 29, 5, 21, 10,
	3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    R = EP(R)  # 扩展置换

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
	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,
	32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))


key = b'********'
plain = b'********'

# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
plain = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in plain])
skeys = get_sub_key(key)

block = IP(plain)

L, R = block[:32], block[32:]
for i in range(16):
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)
enc = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
    
print(enc)  # b'1qSH\xf4\xcf\xd5\x92'

本题并没给出密钥,DES在没有泄露密钥的前提下实现攻击是不现实的。

仔细观察可以发现在加密函数F函数中,R并没有和子密钥进行异或,也就是说此时根本不需要密钥,只是对原文进行了一些置换、异或等操作,我们可以直接正常解密即可。

题解:

from operator import add
from typing import List
from functools import reduce

_IP = [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,
	56, 48, 40, 32, 24, 16, 8,  0,
	58, 50, 42, 34, 26, 18, 10, 2,
	60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
	  0, 57, 49, 41, 33, 25, 17,
	  9,  1, 58, 50, 42, 34, 26,
	 18, 10,  2, 59, 51, 43, 35,
	 62, 54, 46, 38, 30, 22, 14,
	  6, 61, 53, 45, 37, 29, 21,
	 13,  5, 60, 52, 44, 36, 28,
	 20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
	13, 16, 10, 23,  0,  4,
	 2, 27, 14,  5, 20,  9,
	22, 18, 11,  3, 25,  7,
	15,  6, 26, 19, 12,  1,
	40, 51, 30, 36, 46, 54,
	29, 39, 50, 44, 32, 47,
	43, 48, 38, 55, 33, 52,
	45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半

    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
	31,  0,  1,  2,  3,  4,
	 3,  4,  5,  6,  7,  8,
	 7,  8,  9, 10, 11, 12,
	11, 12, 13, 14, 15, 16,
	15, 16, 17, 18, 19, 20,
	19, 20, 21, 22, 23, 24,
	23, 24, 25, 26, 27, 28,
	27, 28, 29, 30, 31,  0
]
__sbox = [
		# 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],
	]
__p = [
	15, 6, 19, 20, 28, 11,
	27, 16, 0, 14, 22, 25,
	4, 17, 30, 9, 1, 7,
	23,13, 31, 26, 2, 8,
	18, 12, 29, 5, 21, 10,
	3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    R = EP(R)  # 扩展置换

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
	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,
	32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))


key = b'********'
plain = b'********'

# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
plain = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in plain])
skeys = get_sub_key(key)

block = IP(plain)

enc = b'1qSH\xf4\xcf\xd5\x92'

# 转为二进制数组
enc = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in enc])
skeys = []
block = IP(enc)

L, R = block[:32], block[32:]
for i in range(15, -1, -1):
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)
plain = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
    
print(plain)

四、对初始密钥k爆破

from operator import add
from typing import List
from functools import reduce

_IP = [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,
	56, 48, 40, 32, 24, 16, 8,  0,
	58, 50, 42, 34, 26, 18, 10, 2,
	60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
	  0, 57, 49, 41, 33, 25, 17,
	  9,  1, 58, 50, 42, 34, 26,
	 18, 10,  2, 59, 51, 43, 35,
	 62, 54, 46, 38, 30, 22, 14,
	  6, 61, 53, 45, 37, 29, 21,
	 13,  5, 60, 52, 44, 36, 28,
	 20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
	13, 16, 10, 23,  0,  4,
	 2, 27, 14,  5, 20,  9,
	22, 18, 11,  3, 25,  7,
	15,  6, 26, 19, 12,  1,
	40, 51, 30, 36, 46, 54,
	29, 39, 50, 44, 32, 47,
	43, 48, 38, 55, 33, 52,
	45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(key: List[int]):
    key = PC_1(key) # PC-1置换
    L, R = key[:28], key[28:] # 分成两半
    print(f'L = {L}')
    print(f'R = {R[:20]}')
    
    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
	31,  0,  1,  2,  3,  4,
	 3,  4,  5,  6,  7,  8,
	 7,  8,  9, 10, 11, 12,
	11, 12, 13, 14, 15, 16,
	15, 16, 17, 18, 19, 20,
	19, 20, 21, 22, 23, 24,
	23, 24, 25, 26, 27, 28,
	27, 28, 29, 30, 31,  0
]
__sbox = [
		# 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],
	]
__p = [
	15, 6, 19, 20, 28, 11,
	27, 16, 0, 14, 22, 25,
	4, 17, 30, 9, 1, 7,
	23,13, 31, 26, 2, 8,
	18, 12, 29, 5, 21, 10,
	3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    R = EP(R)  # 扩展置换
    R = list(map(lambda x, y: x ^ y, R, skeys[index]))  # 异或

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
	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,
	32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))


key = b'********'
plain = b'********'
# 转为二进制数组
key = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in key])
plain = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in plain])
skeys = get_sub_key(key)

block = IP(plain)

L, R = block[:32], block[32:]
for i in range(16):
    tpR = R[:]
    R = F(i, R, skeys)
    R = list(map(lambda x, y: x ^ y, R, L))
    L = tpR
block = R + L
block = FP(block)
enc = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
    
print(enc)

 运行题目代码后我们得到

观察题目我们发现L和R是get_sub_key中生成子密钥时产生的,而且R少了8位,我们只需要得到完整的L和R就可以继续运行生成子密钥从而解密。(爆破八位二进制数只有256种可能,这个范围很小)

题解:

from operator import add
from typing import List
from functools import reduce

_IP = [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,
    56, 48, 40, 32, 24, 16, 8,  0,
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6
]

def IP(plain: List[int]):
    return list(map(lambda x: plain[x], _IP))

__pc1 = [56, 48, 40, 32, 24, 16,  8,
    0, 57, 49, 41, 33, 25, 17,
    9,  1, 58, 50, 42, 34, 26,
    18, 10,  2, 59, 51, 43, 35,
    62, 54, 46, 38, 30, 22, 14,
    6, 61, 53, 45, 37, 29, 21,
    13,  5, 60, 52, 44, 36, 28,
    20, 12,  4, 27, 19, 11,  3
]

__pc2 = [
    13, 16, 10, 23,  0,  4,
    2, 27, 14,  5, 20,  9,
    22, 18, 11,  3, 25,  7,
    15,  6, 26, 19, 12,  1,
    40, 51, 30, 36, 46, 54,
    29, 39, 50, 44, 32, 47,
    43, 48, 38, 55, 33, 52,
    45, 41, 49, 35, 28, 31
]
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

def PC_1(key: List[int]):
    return list(map(lambda x: key[x], __pc1))

def PC_2(key: List[int]):
    return list(map(lambda x: key[x], __pc2))

def get_sub_key(L, R):
    # key = PC_1(key) # PC-1置换
    # L, R = key[:28], key[28:] # 分成两半
    # print(f'L = {L}')
    # print(f'R = {R[:20]}')
    
    skeys = []

    for i in range(16):
        for j in range(ROTATIONS[i]): # 根据轮次左移
            L = L[1:] + L[:1]
            R = R[1:] + R[:1]

        skeys.append(PC_2(L+R)) # PC-2置换
    
    return skeys

__expansion_table = [
    31,  0,  1,  2,  3,  4,
    3,  4,  5,  6,  7,  8,
    7,  8,  9, 10, 11, 12,
    11, 12, 13, 14, 15, 16,
    15, 16, 17, 18, 19, 20,
    19, 20, 21, 22, 23, 24,
    23, 24, 25, 26, 27, 28,
    27, 28, 29, 30, 31,  0
]
__sbox = [
        # 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],
    ]
__p = [
    15, 6, 19, 20, 28, 11,
    27, 16, 0, 14, 22, 25,
    4, 17, 30, 9, 1, 7,
    23,13, 31, 26, 2, 8,
    18, 12, 29, 5, 21, 10,
    3, 24
]

def EP(data: List[int]):  # 扩展置换
    return list(map(lambda x: data[x], __expansion_table))

def P(data: List[int]):  # P置换
    return list(map(lambda x: data[x], __p))

def F(index: int, R: List[int], skeys: List[List[int]]):
    R = EP(R)  # 扩展置换
    R = list(map(lambda x, y: x ^ y, R, skeys[index]))  # 异或

    B = [R[:6], R[6:12], R[12:18], R[18:24], R[24:30], R[30:36], R[36:42], R[42:]]  # 分成八份

    Bn = [0] * 32
    pos = 0
    for i in range(8):
        #  计算该使用S盒的行坐标和列坐标
        row = (B[i][0] << 1) + B[i][5]
        col = (B[i][1] << 3) + (B[i][2] << 2) + (B[i][3] << 1) + B[i][4]

        sb = __sbox[i][(row << 4) + col]

        Bn[pos + 0] = (sb & 8) >> 3  # 四位输出
        Bn[pos + 1] = (sb & 4) >> 2
        Bn[pos + 2] = (sb & 2) >> 1
        Bn[pos + 3] = (sb & 1)

        pos += 4
    R = P(Bn)
    return R

_FP = [
    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,
    32,  0, 40,  8, 48, 16, 56, 24
]

def FP(plain: List[int]):
    return list(map(lambda x: plain[x], _FP))


enc = b'\x1d\xe8\xd1\xc8\x95{]\xa0'
enc = reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in enc])

LL = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1]
RR = [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

for i in range(2**8):
    R = RR +list(map(int, bin(i)[2:].zfill(8)))
    skeys = get_sub_key(LL, R)

    block = IP(enc)

    L, R = block[:32], block[32:]
    for i in range(15, -1, -1):
        tpR = R[:]
        R = F(i, R, skeys)
        R = list(map(lambda x, y: x ^ y, R, L))
        L = tpR
    block = R + L
    block = FP(block)
    plain = bytes([int(''.join(map(str,block[i*8:(i+1)*8])),2) for i in range(8)])
        
    print(plain)

五、子密钥kn完全泄露

import pyDes

m = b'******'
des = pyDes.des('********', padmode=pyDes.PAD_PKCS5)
print(des.encrypt(m)) #b'3\xb3\xdc\xbfkg\x1b\xceG!\x08\x16\xf6i\x0c\xbd\xde_\xe7#\xe2\x99\xe7\xf0\xd9\x02\xd6Hi=1='
print(des.Kn)

本题使用pyDes包来部署DES,通过vscode可以快捷跟进包内查看des.Kn是什么东西

题解:

def __init__():
    # ....
    self.Kn = [ [0] * 48 ] * 16	# 16 48-bit keys (K1 - K16)
	self.final = []

	self.setKey(key)

def setKey(self, key):
	"""Will set the crypting key for this object. Must be 8 bytes."""
	_baseDes.setKey(self, key)
	self.__create_sub_keys()

最后发现它是存储子密钥的数组,拥有了子密钥我们就可以直接解密了

import pyDes

enc = b'3\xb3\xdc\xbfkg\x1b\xceG!\x08\x16\xf6i\x0c\xbd\xde_\xe7#\xe2\x99\xe7\xf0\xd9\x02\xd6Hi=1='
Kn = [[1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0], [1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1], [1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0], [1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1], [1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]]

des = pyDes.des('00000000', padmode=pyDes.PAD_PKCS5)
des.Kn = Kn
print(des.decrypt(enc))

六、中间子密钥泄露

import pyDes

m = b'{********}'
des = pyDes.des('********', padmode=pyDes.PAD_PKCS5)
print(des.encrypt(m))
print(des.Kn[7])

'''
enc=b'\xed\xb7H\xa8zL\xb5\xff\xb2g\x1c<\x17G^\xda\xd4\xb2\x84X\xb4\x92\x18I\xaf9\xcd\xce\xc1\x182"'
Kn=[0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]
'''

与上题不同的是这里只给出了第8轮的子密钥,我们可以通过一轮子密钥逆向恢复其他子密钥

我们先回顾一下子密钥生成的过程:

  1. 将64位密钥去掉8个校验位,用密钥置换PC-1置换剩下的56位密钥。

  2. 将56位分成前28位C0和后28位D0​。

  3. 根据轮数,这两部分分别循环左移1位或2位

  4. 移动后,将两部分合并成56位后通过压缩置换PC-2后得到48位子密钥。

重点需要考虑PC-2的置换部分,这是一个丢失信息的置换,置换将56位变成了48位,而我们无法知道那8位究竟是什么,如果无法得到56位密钥就无法去生成其他的子密钥,所以我们还需要对这8位内容进行爆破处理。

题解:

import pyDes

enc = b'\xed\xb7H\xa8zL\xb5\xff\xb2g\x1c<\x17G^\xda\xd4\xb2\x84X\xb4\x92\x18I\xaf9\xcd\xce\xc1\x182"'
Kn = [0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]

# Despermuted[48]
PC2 = [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]
# DesRotations
movnum = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]#对应16轮中每一轮的循环左移位数

def gen_key(C1,D1,k):
    tempc=C1
    tempd=D1
    for i in range(k):
        tempc = tempc[1:] + tempc[:1]
        tempd = tempd[1:] + tempd[:1]
    tempCD1=tempc+tempd
    tempkey=[]
    for i in range(len(PC2)):
        tempkey.append(tempCD1[PC2[i]-1])
    return (tempkey,tempCD1)#轮运算得到下一轮子密钥

def re_gen_key(C1,D1):
    tempc=C1[-1:]+C1[:-1]
    tempd=D1[-1:]+D1[:-1]
    tempCD1=tempc+tempd
    return tempCD1 #轮运算得到上一轮CD

d = pyDes.des("0"*8)
CD = ['*']*56

# 获得PC-2置换前的数据,即56位密钥,当然其中有8位我们依然是未知的
for i in range(len(PC2)):
    CD[PC2[i]-1] = Kn[i]

for i in range(256):
    # 遍历2^8种可能
    temp = CD[::]
    bi = bin(i)[2:].zfill(8)
    tot = 0
    for j in range(len(temp)):
        if temp[j] == '*':
            temp[j] = int(bi[tot])  # 将丢失的8位填充进去
            tot += 1

    # 回到初始密钥
    for j in range(sum(movnum[:8])):  # 逆向循环左移操作,回到最初的密钥形态
        temp = re_gen_key(temp[:28],temp[28:])

    tempK=[]
    Z = temp
    # 16轮迭代重新生成新的子密钥
    for j in range(16):
        tempx=gen_key(Z[:28],Z[28:],movnum[j])
        tempK.append(tempx[0])
        Z=tempx[1]
    d.Kn = tempK
    print(d.decrypt(enc))  # 使用子密钥解密消息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值