简化版的DES加密Python实现

简化版的DES(S-DES,https://en.wikipedia.org/wiki/Data_Encryption_Standard#Simplified_DES)是用来是用来教学的加密算法,可为理解DES、AES等加密算法打下基础。

本文通过Python实现S-DES加密算法。
在写程序的时候为了和资料上的函数名称一致,便于理解,有些函数、变量的命名不是很符合编程规范,也没有异常处理,主要用来加深理解S-DES算法。

算法说明

简化版DES(S-DES)的过程图示


简化版的DES加密Python实现_第1张图片
S-DES加解密图示

加密过程


S-DES加密

书写公式不方便,上述公式用字符表示如下

秘文 = IPinv(fK(SW(fK(IP(明文)))))

设计

输入

  1. 等待加密的文字,以十六进制字符串输入
  2. 10位秘钥,以列表输入

输出

加密的字符,以十六进制字符表示

接口设计

# 加密
ciphertext = sdesEncrypt('59616e67', [0,1,0,1,1,1,1,1,0,1])
# 解密
plaintext = sdesDecrypt(ciphertext, [0,1,0,1,1,1,1,1,0,1])

实现

秘钥(key)变换

S-DES需要一个10位(bit)的秘钥。每位表述为k1,k2,k3,k4,k5,k6,k7,k8,k9,k10。
用到Shift、P10和P8三个函数

P10:对10位秘钥重排
P8:选取其中8位排列
Shift:循环左移1位

P10函数如下
P10(k1,k2,k3,k4,k5,k6,k7,k8,k9,k10) = (k3,k5,k2,k7,k4,k10,k1,k9,k8,k6)

P10函数实现

def P10(key):
    k = [None] + key
    return [k[3],k[5],k[2],k[7],k[4],k[10],k[1],k[9],k[8],k[6]]

编程语言的列表索引是从0开始,这里表述行位操作时,索引0存放无用值None,仅仅作占位用。从索引1开始存放数据。比如4位二进制1011存放到在长度为5的列表[None, 1, 0, 1, 1]中。这样的好处是代码的位索引和文本说明次序一致,后面代码有类似思路。

P8和Shift函数的实现

def P8(key):
    k = [None] + key
    return [k[6],k[3],k[7],k[4],k[8],k[5],k[10],k[9]]

def Shift(value):
    return value[1:] + value[0:1]

S-DES 加解密1个字节

IP和 IPinv 函数

IP和IPinv互相为反函数,即:IPinv(IP(X)) = X,IP(IPinv(X)) = X

def IP(value):
    v = [None] + value
    return [k[2],k[6],k[3],k[1],k[4],k[8],k[5],k[7]]

def IPinv(value):
    v = [None] + value
    return [k[4],k[1],k[3],k[5],k[7],k[2],k[8],k[6]]

SW 函数

SW函数交换左边和右边的4位

def SW(value):
    return value[4:] + value[:4]

fK函数

fK操作8位二进制,最左边的4位记作L,最右边的4位记作作R,表示如下

fK(L,R) = (L⊕F(R,K), R)

⊕是异或运算
K表示子秘钥K1或者K2
F函数是新引入的函数,可通过下面的两个步骤求出:

  1. 创建一个2行4列的表格P
    对输入的4的位数字(n1,n2,n3,n4)
    对输入K(k11,k12,k13,k14,k15,k16,k17,k18)
    表格P的值如下
P(0,0) = n4 ⊕ k11 P(0,1) = n1 ⊕ k12 P(0,2) = n2 ⊕ k13 P(0,3) = n3 ⊕ n14
P(1,0) = n2 ⊕ k15 P(1,1) = n3 ⊕ k16 P(1,2) = n4 ⊕ k17 P(1,3) = n1 ⊕ k18
  1. 在盒中查找

有两个盒子S0和S1,值如下

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]]

P(0,0)和P(0,1)组合成二进制的值row0,比如P(0,0) = 1, P(0,1) = 0,则row0 = 二进制10 = 2

P(0,2)和P(0,3)组合成二进制的值col0

P(1,0)和P(1,1)组合成二进制的值row1

P(1,2)和P(1,3)组合成二进制的值col1

S0的第row0行col0列的值S0(row0,col0)表示成两位二进制v1,v2,类似地S1(row1,col1)表示成两位二进制v3,v4

(v2,v4,v3,v1)组合成的二进制的值便是F函数的值

fK函数和F函数实现

def F(value, key):
    val = lambda x, y: x * 2 + y
    highLow = lambda x: (1 if x & 0b10 > 0 else 0), (x & 0b01)
    P = [[0, 0, 0, 0],
         [0, 0, 0, 0]]
    n = [None] + value
    k = [None] * 11 + key  # 这里前面空11无用的值None
    P[0][0] = n[4] ^ k[11]
    P[0][1] = n[1] ^ k[12]
    P[0][2] = n[2] ^ k[13]
    P[0][3] = n[3] ^ k[14]
    P[1][0] = n[2] ^ k[15]
    P[1][1] = n[3] ^ k[16]
    P[1][2] = n[4] ^ k[17]
    P[1][3] = n[1] ^ k[18]
    row0 = val(P[0][0], P[0][1])
    col0 = val(P[0][2], P[0][3])
    row1 = val(P[1][0], P[1][1])
    col1 = val(P[1][2], P[1][3])
    v1, v2 = highLow(S0[row0][col0])
    v3, v4 = highLow(S1[row1][col1])
    return [v2, v4, v3, v1]

def fK(value, key):
    L = value[:4]
    R = value[4:]
    return list(map(lambda x:x[0]^x[1], zip(L, F(R))) + R

加密单字节函数 sdesEncryptByte
用上文出现过的公式:秘文 = IPinv(fK(SW(fK(IP(明文)))))
代码实现

def sdesEncryptByte(value, key):
    K1 = P8(Shift(P10(key)))
    K2 = P8(Shift(Shift(P10(key))))
    fK1Value = fK(IP(value), K1)
    swValue = SW(fK1Value)
    fK2Value = fK(swValue, K2)
    return IPinv(fK2Value)

解密单字节函数 sdesDecryptByte
代码实现

def sdesDecryptByte(value, key):
    K1 = P8(Shift(P10(key)))
    K2 = P8(Shift(Shift(P10(key))))
    fK2Value = fK(IPinv(value), K2)
    swValue = SW(fK2Value)
    fK1Value = fK(swValue, K1)
    return IP(fK1Value)

S-DES加密

使用了一个辅助函数makeByteList,把十六进制文本转化成字节数组,每个字节又是一个数组。

def makeByteList(hextext):
    l = list(hextext)
    arr = []
    for i in range(len(l) // 2):
        arr += [ l[2*i] + l[2*i+1] ]
    binaryList = []
    for value in arr:
        text = list(bin(int(value, 16))[2:].zfill(8))
        binaryList += [text]
        
def sdesEncrypt(hextext, key):
    encryptedString  = ''
    for value in makeByteList(hextext)
        encryptedByte = sdesEncryptByte(value, key)
        encryptedString += encryptedByte

def sdesDecrypt(hextext, key):
    encryptedString  = ''
    for value in makeByteList(hextext)
        encryptedByte = sdesDecryptByte(value, key)
        encryptedString += encryptedByte

相关文章

密码学基础系列

参考文献

William Stallings. "Appendix G: Simplified DES"

你可能感兴趣的:(简化版的DES加密Python实现)