简化版的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)的过程图示


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"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容