DES Learning

之前做题目的时候知道了DES使用的Feistel结构,比较有意思,顺带把DES的原理弄清楚一点

Feistel密码结构

简单来说Feistel结构是顺序地执行两个或多个基本密码系统,使最后结果的密码强度高于每个密码系统的结构

工作流程如下

image

F为轮函数,K0~Kn作为轮密钥

对于Encryption

原始数据被分成长度相等的两部分(L0,R0)

每一轮的操作如下:
·Li+1=Ri

·Ri+1=LixorF(Ri,Ki)

最终输出(Rn+1,Ln+1)

相关参数与Feistel密码结构安全性

分组大小 分组越多安全性越高,但是会减慢加密速度
密钥长度 密钥越长安全性越高,同样会减慢速度,一般采取128bits
加密轮数 轮数越多安全性越高,一般16轮
密钥扩展算法 同上
轮函数 ···

一个很有意思的地方是使用Feistel体系的加密算法,解密与加密完全相同,只需把加密时所生成的密钥组倒置即可

DES算法

算法概述:

DES(Data Encryption Standard)算法是一种采用64bits的密钥(56位参与运算,其余八位为校验位)对64bits的分块进行加密的密码体制

下面是DES的Feistel结构

image

书上对Feistel网络的代数描述:每轮使用的Feistel结构都将一个64位的输入分组映射到一个64位的输出分组。对任意函数f而言,即使f本身不是双向映射的这个映射仍是双向映射。在DES中f函数实际是一个满射,使用了非线性的基本构造分组,并使用48位的轮密码ki(1≤i≤16)将32位的输入映射到32位输出上

这里我把之前的一道赛题放上,那题直接把DES的所有步骤都写全了,便于我们接下来的分析

import base64
import random

flag = "flag{************************************}"

hexadecimalcontrast = {
    '0': '0000',
    '1': '0001',
    '2': '0010',
    '3': '0011',
    '4': '0100',
    '5': '0101',
    '6': '0110',
    '7': '0111',
    '8': '1000',
    '9': '1001',
    'a': '1010',
    'b': '1011',
    'c': '1100',
    'd': '1101',
    'e': '1110',
    'f': '1111',
}
IP = [58, 50, 42, 34, 26, 18, 10, 2,
      60, 52, 44, 36, 28, 20, 12, 4,
      62, 54, 46, 38, 30, 22, 14, 6,
      64, 56, 48, 40, 32, 24, 16, 8,
      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]
IP_1 = [40, 8, 48, 16, 56, 24, 64, 32,
        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]
E = [32, 1, 2, 3, 4, 5,
     4, 5, 6, 7, 8, 9,
     8, 9, 10, 11, 12, 13,
     12, 13, 14, 15, 16, 17,
     16, 17, 18, 19, 20, 21,
     20, 21, 22, 23, 24, 25,
     24, 25, 26, 27, 28, 29,
     28, 29, 30, 31, 32, 1]
S = [[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, ],
     [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, ],
     [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, ],
     [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, ],
     [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, ],
     [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, ],
     [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, ],
     [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, ]]
PC_1 = [57, 49, 41, 33, 25, 17, 9, 1,
        58, 50, 42, 34, 26, 18, 10, 2,
        59, 51, 43, 35, 27, 19, 11, 3,
        60, 52, 44, 36, 63, 55, 47, 39,
        31, 23, 15, 7, 62, 54, 46, 38,
        30, 22, 14, 6, 61, 53, 45, 37,
        29, 21, 13, 5, 28, 20, 12, 4, ]
PC_2 = [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, ]
P = [16, 7, 20, 21,
     29, 12, 28, 17,
     1, 15, 23, 26,
     5, 18, 31, 10,
     2, 8, 24, 14,
     32, 27, 3, 9,
     19, 13, 30, 6,
     22, 11, 4, 25, ]
movnum = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]


def HexToBin(string):
    "Convert sixteen to binary"

    Binstring = ""
    string = string.lower()
    for i in string:
        try:
            Binstring += hexadecimalcontrast[i]
        except:
            return -1
    return Binstring


def BinToStr(strbin):
    "Turn the binary string to a ASCII string"

    strten = ""
    for i in range(len(strbin) // 8):
        num = 0
        test = strbin[i * 8:i * 8 + 8]
        for j in range(8):
            num += int(test[j]) * (2**(7 - j))
        strten += chr(num)
    return strten


def StrToHex(string):
    "Converts a string to HEX"

    hexStr = ''
    for i in string:
        tmp = str(hex(ord(i)))
        if len(tmp) == 3:
            hexStr += tmp.replace('0x', '0')
        else:
            hexStr += tmp.replace('0x', '')
    return hexStr

def Binxor(string1, string2):
    "If the length is different, only the short one is returned."

    strlen = 0
    xorstr = ""
    if len(string1) > len(string2):
        strlen = len(string2)
    else:
        strlen = len(string1)
    for i in range(strlen):
        if string1[i] == string2[i]:
            xorstr += '0'
        else:
            xorstr += '1'
    return xorstr


def SubstitutionBox(keyfield, sub):

    newkeyfield = ''
    for i in range(len(sub)):
        newkeyfield += keyfield[sub[i] - 1]
    return newkeyfield


def SubkeyGeneration(freq, C, D):

    for i in range(movnum[freq]):
        C = C[1:] + C[:1]
        D = D[1:] + D[:1]
    return C, D, SubstitutionBox(C + D, PC_2)


def enkey(secretkey): 

    netss = SubstitutionBox(HexToBin(StrToHex(secretkey)), PC_1)
    C, D = netss[:28], netss[28:]
    key = []
    for i in range(16): 
        C, D, keyone = SubkeyGeneration(i, C, D)
        key.append(keyone)
    return key


def Sbox(plaintext, sub):

    return HexToBin("%x" % S[sub][int(plaintext[:1] + plaintext[-1:], 2) * 16 + int(plaintext[1:-1], 2)])


def Function(plaintext, secretkey):

    plaintext = Binxor(SubstitutionBox(plaintext, E),
                       secretkey)
    sout = ''
    for i in range(8):
        sout += Sbox(plaintext[i * 6:(i + 1) * 6], i)
    sout = SubstitutionBox(sout, P)
    return sout


def endecrypt(plaintext, secretkey):

    netss = SubstitutionBox(HexToBin(StrToHex(plaintext)), IP)
    L, R = netss[:32], netss[32:]
    for i in range(16):
        L, R = R, Binxor(L, Function(R, secretkey[i]))
    return SubstitutionBox(R + L, IP_1)


def encryption(plaintext, secretkey):

    plaintext = plaintext + (8 - len(plaintext) % 8) * '\0'
    keys = enkey(secretkey[:8])
    ciphertext = ''
    for i in range(len(plaintext) / 8):
        ciphertext += endecrypt(plaintext[i * 8:(i + 1) * 8], keys)
    return base64.b64encode(BinToStr(ciphertext))


def generate():
    fw = open("random", "w")
    for i in range(700):
        fw.write(str(random.getrandbits(32))+"\n")
    fw.close()

generate()
f = open("flag.txt", "w")
key = str(random.getrandbits(32))
ciphertext = encryption(flag, key)
f.write(ciphertext)
f.close()

Part1:IP置换

按照一定规则,将原来的64位二进制位重新排序

即上述代码中的IP与IP_1,分别为IP和IP逆置换的表

一开始觉得这两个表不应该一样才对嘛?实际上并不是,很容易想到问题在哪

下面这个图能帮助我们更好理解

image

IP置换并不会增加加密的安全性,好像是为了适应当时寄存器大小而设计

Part2:f函数

step1:E扩展置换

为了适应异或密钥的48bits需要将每个32bits的部分扩充为48bits参与异或

即代码的E部分

效果如图

image

随后与密钥进行异或

step2:S盒压缩

根据异或所得的48bits数据,采用6进4出的8个S盒进行压缩

选取每个6bits数据的首尾组成的二进制数为行数,中间4bits所组成的二进制数为列数进行查表

代码所示的S盒的顺序好像有点问题,当时采用Crypto库里的DES解密没解出明文或许也是这个原因

需要注意的是S盒是DES中唯一一个非线性元素,人们通常通过精心设计S盒来抵御各种高级的数学攻击,如差分密码分析等

step3:P盒置换

与IP置换一样,查表即可

Part3:密钥编排

step1

PC-1表置换(同时除去8,16,···,64位(8个校验位))

step2

将剩余的56bits分为两部分,分别进行循环移位

image

step3

移位后将两部分合并,进行PC-2表置换,最终得到48bits的密钥

总流程如下

image

总的来说DES的确是个很精彩的算法,但是由于密钥空间较小容易受到攻击,故单重DES只用于短期安全性或加密数据价值较低的情况,但DES的变体如3DES仍然十分安全

在DES产生的几十年时间内产生了针对DES的DC及LC攻击,但是由于这两种分析攻击所需的明密文对的量并不现实,故我们认为DC和LC在现实系统中无法破解DES

posted @ 2022-02-10 11:08  hash_hash  阅读(70)  评论(0编辑  收藏  举报