分组密码之DES

一个人炫耀什么,说明内心缺少什么。

算法分析

1.DES是一个对称密码体制,加密解密使用同一秘钥,有效密钥长度为56比特。
2.DES是一个分组密码算法,明文分组和密文分组长度均为64比特。
3.DES使用Feistel结果,具有加密相似特性,加解密算法相同,只是解密子密钥与加密子密钥的使用顺序相反。
4.DES由初始置换,16轮迭代,逆初始置换组成。
5.具体过程如下:

  • 64位明文经过初始置换(IP)而重新排列,并将其分为左右两个分组L0和R0,各为32位。
  • 在秘钥的参与下,对左右两个分组进行16轮相同轮函数的迭代。最后一轮输出为64位,且其左半部分和右半部分不进行交换。
  • 最后的与输出再通过初始逆置换产生64位密文。

算法实现

import re

# Permutation and translation tables for DES
# 压缩置换矩阵  从64位里选56位
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
]

# number left rotations of pc1
shifttimes = [
    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
]

# permuted choice key (table 2)
# 压缩置换矩阵  从56位里选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]


# The (in)famous S-boxes
# S盒 的置换矩阵
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],
]

# 32-bit permutation function P used on the output of the S-boxes
# P置换的置换矩阵
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]

# initial permutation IP
# IP置换的 置换矩阵
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]

# Expansion table for turning 32 bit blocks into 48 bits
# E扩展置换矩阵
e_expansion = [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]

# final permutation IP^-1
# IP逆置换矩阵
ipreverse = [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]

# IP置换
def IP(text):
    #如果长度不是64位 就退出
    assert len(text) == 64
    t = ""
    #通过循环 进行IP置换
    for i in ip :
        t += text[i - 1]
    return t

# 秘钥移位
def shift(s, times):
    s = s[times:] + s[0:times]
    return s

# 生成子秘钥
def createSubkey(key):
    # 如果key长度不是64 就退出
    assert len(key) == 64
    # DES的密钥由64位减至56位,每个字节的第8位作为奇偶校验位
    # 把56位 变成 2个28位
    Llist = pc1[0:28]
    Rlist = pc1[28:56]
    # 初始生成 左右两组28位密钥
    L0 = ""
    R0 = ""
    for i in Llist:
        L0 += key[i - 1]
    for i in Rlist:
        R0 += key[i - 1]
    assert len(L0) == 28
    assert len(R0) == 28
    # 定义返回的subkey
    subkey = []
    # 轮函数生成 48位密钥开始轮置换
    for i in range(0, 16):
        # 获取左半边 和 右半边  shift函数用来左移生成轮数
        L0 = shift(L0, shifttimes[i])
        R0 = shift(R0, shifttimes[i])
        #合并左右部分
        merge = L0 + R0
        tempkey = ""
        # 压缩置换矩阵  从56位里选48位
        # 选出48位子密钥
        for i in pc2:
            tempkey += merge[i - 1]
        assert len(tempkey) == 48
        # 加入生成子密钥
        subkey.append(tempkey)
    return subkey

# E扩展
def E_expand(Ri):
    expand = ""
    for i in e_expansion:
        expand += Ri[i - 1]
    assert len(expand) == 48
    return expand

# S盒代换
def S_replace(s):
    # 从第二位开始的子串,去掉0X
    s = bin(s)[2:]
    while len(s) < 48:
        s = "0" + s
    index = 0
    replace = ""
    for S in sbox:
        # 输入的高低两位做为行数row
        row = int(s[index] + s[index + 5], base=2)
        # 中间四位做为列数L
        col = int(s[index + 1:index + 5], base=2)
        # 得到result的单个四位输出
        out = bin(S[row * 16 + col])[2:]
        # 尾数为0,要把0补全
        while len(out) < 4:
            out = "0" + out
        # 合并单个输出
        replace += out
        # index + 6 进入下一个六位输入
        index += 6
    assert len(replace) == 32
    return replace

# P 盒置换
def P(Ri):
    t = ""
    for i in p:
        t += Ri[i - 1]
    return t

# Ri_P(P置换后的输出)和Li(上一轮次的L)异或
def requirexor(Ri_P , Li, Ri): # Ri上一轮次的R
    # P盒置换的结果与最初的64位分组左半部分L0异或
    RI = int(Ri_P, base=2) ^ int(Li, base=2)
    RI = bin(RI)[2:] # RI这一轮次的R
    while len(RI) < 32:
        RI = "0" + RI
    assert len(RI) == 32
    # 这一轮次的L即为上一轮次的R,即LI=Ri
    LI = Ri
    return (LI, RI)

# IP逆置换
def IP_reverse(L16, R16):
    t = L16 + R16
    res = ""
    for i in ipreverse:
        res += t[i - 1]
    assert len(res) == 64
    return res

# DES 算法实现 flag是标志位 当为-1时, 是DES解密, flag默认为0
def DES(text, key, flag = "0"):
    InitKeyCode = IP(text)
    # 产生子密钥 集合
    subkeylist = createSubkey(key)
    # 获得Ln 和 Rn
    Ln = InitKeyCode[0:32]
    Rn = InitKeyCode[32:]
    # 如果是解密的过程 把子密钥次序反过来 就变成解密过程了
    if (flag == "-1") :
        subkeylist = subkeylist[::-1]
    for subkey in subkeylist:
        while len(Rn) < 32:
            Rn = "0" + Rn
        while len(Ln) < 32:
            Ln = "0" + Ln
        # 对右边进行E-扩展
        Rn_expand = E_expand(Rn)
        # 压缩后的密钥与扩展分组异或以后得到48位的数据,将这个数据送入S盒
        S_Input = int(Rn_expand, base=2) ^ int(subkey, base=2)
        # 进行S盒替代
        S_sub = S_replace(S_Input)
        # P盒置换
        tem = P(S_sub)
        #  获得下一轮的Ln和Rn
        (Ln, Rn) = requirexor(tem, Ln, Rn)
        #进行下一轮轮置换
    # 最后一轮之后  左、右两半部分并未进行交换
    # 而是两部分合并形成一个分组做为末置换的输入
    # 所以要置换 一次
    (Ln, Rn) = (Rn, Ln)
    # IP逆置换得到密文
    re_text = IP_reverse(Ln, Rn)
    return re_text

# 字符串转换为二进制字符串
def strtobin(s):
    res = []
    for c in s:
        tem = bin(ord(c)).replace('b', '')
        # 转为字符串时,后7位中,如果存在前面为0,会自动去掉,需要加回来,使之满足8位
        if len(tem) < 8:
            tem = "0" + tem
        res.append(tem)
    return ''.join(res)

# 二进制转字符串
def bintostr(s):
    tem = ""
    for i in s:
        tem += str(chr(int(i, base=2)))
    return tem

# 将明文字符串分割为指定长度字符串并存于列表中
def cut_text(text, lenth):
    tem = re.findall('.{' + str(lenth) + '}', text)
    tem.append(text[(len(tem) * lenth):])
    # 由于分割后,末尾出现一个空字符,故去掉
    result = [i for i in tem if i != '']
    return result

if __name__ == "__main__":
    # 秘钥,长度必须为64位
    key = "asdfghjk"
    #明文
    plaintext = "ifnottothesunforsmilingwarmisstillinthesuntherebutwewilllaughmoreconfidentcalmifturnedtofoundhisownshadowappropriateescapethesunwillbethroughtheheartwarmeachplacebehindthecornerifanoutstretchedpalmcannotfallbutterflythenclenchedwavingarmsgivenpowerificanthavebrightsmileitwillfacetothesunshineandsunshinesmiletogetherinfullbloom"
    print("明文为: \n" + plaintext)

    # 加密
    key = strtobin(key)
    # 当明文长度不为64位的倍数时,填充空格满足条件
    while len(plaintext) % 8 != 0:
        plaintext += " "
    # 将明文分割成每组8字节,即64位
    mlist = cut_text(plaintext, 8)
    ciphertext = ""
    for t in mlist:
        mtext = strtobin(t)
        # 对每组明文分别加密
        ciphertext += DES(mtext, key)
    # 将结果转换成16进制表示,并去掉头部0X
    print("加密后的密文为: \n" + hex(int(ciphertext, base=2))[2:].upper())

    #解密
    ctext = ""
    # 加密得到的密文为二进制,故直接分割为64位每组
    clist = cut_text(ciphertext, 64)
    for c in clist:
        ctext += DES(c, key, "-1")
    # 将二进制字符串按每字节分割
    result = cut_text(ctext, 8)
    # 转换为相应字符并合并成字符串
    ans = bintostr(result)
    print("解密后的明文为: \n" + ans.rstrip())

加密与解密

当key = “asdfghjk”,时,加密与解密如图所示:

安全性分析

如今,DES的安全性已经无法满足需求(三重DES安全性能达到要求,但存在许多缺陷)故存在许多可行攻击。
1.固有的安全问题:互补性和弱密钥问题。

  • 互补性: 对明文𝑚和密钥𝐾逐位取补,则加密后的密文同样为原密文的补。故互补性使得DES在选择明文攻击下所需的工作量减半。
  • 弱密钥:初始密钥会生成16个相同的子密钥,这样的弱密钥有
0x0101010101010101
0xFEFEFEFEFEFEFEFE
0xE0E0E0E0F1F1F1F1
0x1F1F1F1F0E0E0E0E
  • 半弱密钥:即用K2加密明文,可以用K1解密,这种半弱密钥有:
0x011F011F010E010E:0x1F011F010E010E01
0x01E001E001F101F1:0xE001E001F101F101
0x01FE01FE01FE01FE:0xFE01FE01FE01FE01
0x1FE01FE00EF10EF1:0xE01FE01FF10EF10E
0x1FFE1FFE0EFE0EFE:0xFE1FFE1FFE0EFE0E
0xE0FEE0FEF1FEF1FE:0xFEE0FEE0FEF1FEF1 
  • 还有四分之一弱密钥,八分之一弱密钥等。这些秘钥的安全性很差,故一般生成秘钥后,都x需要进行弱密码检查。

2.穷举攻击:如今,穷举时间已经减少到不足24小时。
3.差分分析:这种方法对破译16轮的DES不能提供一种实用的方法,但对破译轮数较低的DES是很成功的。
4.线性分析:用这种方法破译DES比差分分析方法更有效。可用2^47个已知明文破译8-轮DES。

数据加密技术 我们经常需要一种措施来保护我们的数据,防止被一些怀有不良用心的人所看到或者破坏。在信息时代,信息可以帮助团体或个人,使他们受益,同样,信息也可以用来对他们构成威胁,造成破坏。在竞争激烈的大公司中,工业间谍经常会获取对方的情报。因此,在客观上就需要一种强有力的安全措施来保护机密数据不被窃取或篡改。数据加密与解密从宏观上讲是非常简单的,很容易理解。加密与解密的一些方法是非常直接的,很容易掌握,可以很方便的对机密数据进行加密和解密。 一:数据加密方法 在传统上,我们有几种方法来加密数据流。所有这些方法都可以用软件很容易的实现,但是当我们只知道密文的时候,是不容易破译这些加密算法的(当同时有原文和密文时,破译加密算法虽然也不是很容易,但已经是可能的了)。最好的加密算法对系统性能几乎没有影响,并且还可以带来其他内在的优点。例如,大家都知道的pkzip,它既压缩数据又加密数据。又如,dbms的一些软件包总是包含一些加密方法以使复制文件这一功能对一些敏感数据是无效的,或者需要用户的密码。所有这些加密算法都要有高效的加密和解密能力。 幸运的是,在所有的加密算法中最简单的一种就是“置换表”算法,这种算法也能很好达到加密的需要。每一个数据段(总是一个字节)对应着“置换表”中的一个偏移量,偏移量所对应的值就输出成为加密后的文件。加密程序和解密程序都需要一个这样的“置换表”。事实上,80x86 cpu系列就有一个指令‘xlat’在硬件级来完成这样的工作。这种加密算法比较简单,加密解密速度都很快,但是一旦这个“置换表”被对方获得,那这个加密方案就完全被识破了。更进一步讲,这种加密算法对于黑客破译来讲是相当直接的,只要找到一个“置换表”就可以了。这种方法在计算机出现之前就已经被广泛的使用。 对这种“置换表”方式的一个改进就是使用2个或者更多的“置换表”,这些表都是基于数据流中字节的位置的,或者基于数据流本身。这时,破译变的更加困难,因为黑客必须正确的做几次变换。通过使用更多的“置换表”,并且按伪随机的方式使用每个表,这种改进的加密方法已经变的很难破译。比如,我们可以对所有的偶数位置的数据使用a表,对所有的奇数位置使用b表,即使黑客获得了明文和密文,他想破译这个加密方案也是非常困难的,除非黑客确切的知道用了两张表。 与使用“置换表”相类似,“变换数据位置”也在计算机加密中使用。但是,这需要更多的执行时间。从输入中读入明文放到一个buffer中,再在buffer中对他们重排序,然后按这个顺序再输出。解密程序按相反的顺序还原数据。这种方法总是和一些别的加密算法混合使用,这就使得破译变的特别的困难,几乎有些不可能了。例如,有这样一个词,变换起字母的顺序,slient 可以变为listen,但所有的字母都没有变化,没有增加也没有减少,但是字母之间的顺序已经变化了。 但是,还有一种更好的加密算法,只有计算机可以做,就是字/字节循环移位和xor操作。如果我们把一个字或字节在一个数据流内做循环移位,使用多个或变化的方向(左移或右移),就可以迅速的产生一个加密的数据流。这种方法是很好的,破译它就更加困难!而且,更进一步的是,如果再使用xor操作,按位做异或操作,就就使破译密码更加困难了。如果再使用伪随机的方法,这涉及到要产生一系列的数字,我们可以使用fibbonaci数列。对数列所产生的数做模运算(例如模3),得到一个结果,然后循环移位这个结果的次数,将使破译次密码变的几乎不可能!但是,使用fibbonaci数列这种伪随机的方式所产生的密码对我们的解密程序来讲是非常容易的。 在一些情况下,我们想能够知道数据是否已经被篡改了或被破坏了,这时就需要产生一些校验码,并且把这些校验码插入到数据流中。这样做对数据的防伪与程序本身都是有好处的。但是感染计算机程序的病毒才不会在意这些数据或程序是否加过密,是否有数字签名。所以,加密程序在每次load到内存要开始执行时,都要检查一下本身是否被病毒感染,对与需要加、解密的文件都要做这种检查!很自然,这样一种方法体制应该保密的,因为病毒程序的编写者将会利用这些来破坏别人的程序或数据。因此,在一些反病毒或杀病毒软件中一定要使用加密技术。 循环冗余校验是一种典型的校验数据的方法。对于每一个数据块,它使用位循环移位和xor操作来产生一个16位或32位的校验和 ,这使得丢失一位或两个位的错误一定会导致校验和出错。这种方式很久以来就应用于文件的传输,例如 xmodem-crc。 这是方法已经成为标准,而且有详细的文档。但是,基于标准crc算法的一种修改算法对于发现加密数据块中的错误和文件是否被病毒感染是很有效的。 二.基于公钥
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

烜奕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值