现代密码学教程—古典密码体制

作业(尚未订正)

  1. 令仿射密码的密钥k = (9, 3),gcd(9, 26) = 1。明文hot = (7, 14, 19),求加解密过程。

    加密:

            (9 × 7 + 3) mod 26 = 14        (9 × 14 + 3) mod 26 = 25

            (9 × 19 + 3) mod 26 = 18      密文为(14, 25, 18) = (o, z, s)

    解密:

               $9^{-1}=3 mod 26$

            (14 - 3) × 3mod 26 = 7          (25 - 3 ) × 3mod 26 = 14

            (18 - 3) × 3mod 26 = 19          明文为(7, 14, 190) = hot

  2. 用维吉尼亚密码加密明文please keep this message in secret,其中使用的密钥为computer,试求其密文。

    密文为:rzqpmxovgdfwclqvugmvybrjgqdtn

  3. 用Hill密码加密明文hill,使用的密钥是$k =
    \begin{bmatrix}
    1 & 2 & 3 \\
    4 & 5 & 6 \\
    7 & 8 & 9
    \end{bmatrix}
    $

  4. 试设计实现仿射密码和单表代换密码:给出密钥生成(随机选择小于26的数、选择和26互素的密钥;以及生成0-25上的一个随机指挥)、加解密的伪代码。

    仿射密码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    import random

    def gcda, b):
    if b == 0:
    return a
    else:
    return gcd(b, a % b)

    # 求模26下x的逆
    def inv_x):
    for inv_a in range1, 26, 2):
    for j in range27):
    if x * inv_a == 26 * j + 1:
    return inv_a

    # 仿射密码
    print'仿射密码'
    while True:
    state = input"加密/解密:"
    if state == "加密":
    # 字母表
    alphabet = dict()
    for i in range26):
    alphabet[chr(i + 97)] = i
    # 生成密钥a和b,生成随机数后判断是否与26互素
    while True:
    a = random.randint(1, 25
    if gcd(a, 26) == 1:
    break
    b = random.randint(0, 25
    print'key:({},{})'.format(a, b))
    # 输入明文,产生密文
    c = ''
    p = input'明文:').lower()
    for word in p:
    num = (a * alphabet[word] + b) % 26
    for key, value in alphabet.items():
    if value == num:
    c += key
    print'密文:{}'.format(c))
    break
    elif state == "解密":
    c = input"密文:").lower()
    key_a, key_b = mapint, input"密钥:").split())
    a_ = inv_(key_a)
    print"明文:", end=''
    for word in c:
    printchr((((ord(word) - 97 - key_b) * a_) % 26) + 97), end=''
    break
    else:
    print"请输入:加密或解密"

    单表代换:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import random

    alphabet = list()
    for i in range26):
    alphabet.append(chr(i + 97))

    # 打乱列表,并对应原来字母表
    random.shuffle(alphabet)
    key = dict()
    for i in range26):
    key[chr(i + 97)] = alphabet[i]
    print'加密表:\n{}'.format(key))
    print'*' * 15 + '加密' + '*' * 15
    p = input'明文:').lower()
    c = ''
    for word in p:
    c += key[word]
    print'密文:{}'.format(c))

    print'*' * 15 + '解密' + '*' * 15
    p = input'密文:').lower()
    print"明文:", end=''
    for word in p:
    for k, value in key.items():
    if value == word:
    print(k, end=''
  5. 给出移位、仿射、单表代换、维吉尼亚密码、多表代换(每个密钥是一个单表代换)、置换密码穷尽搜索的复杂度(即密钥空间大小)。

    • 移位:25
    • 仿射: $\varphi(26)*26=312$
    • 单表代换:26!
    • 维吉尼亚:$26^{m}$
    • 多表代换:$(26!)^{m}$ (m为密钥长度)
    • 置换: m! (m为分组长度)
  6. 区分单表代换、多表代换、置换密码、希尔密码,哪个属于分组加密范畴,为什么?

    多表代换,置换密码,希尔密码属于分组加密。多表代换要将明文m个分组成一段,不足m的元素填充按密钥对应不同的密码表加密。置换密码和希尔密码分组后不足m的要进行补齐,然后进行换位或与矩阵做乘法。

  7. 已知下列密文是通过维吉尼亚密码加密得来的,试求其明文。

    点击查看 Per zlrracm, vxmcs r qipqlczhs. Qs fcv rihw sxx hblrxh sm nkidhvzphw. Ixxvn qsn, lysh sifecs uui jrrfyg, mk xj suvc kd ss wbrzrrz uqh jpp zyw qv ylgn osfz fin isi bpgyoj, fg dm zdqzap, cl sifecs qks cdfy iu xyxey iu tipp zcni dt. Sin lj nt rfy jszcx hi jik iyfixky iysmh hzuwwwxpk izayv; mw lv olh kfxeu nr gitrhy d afgcr qkiit vjyucsdum bdw kwv cjssiilbcwc kd wwhg e ads, ohg ewuffx fscavuy; lj nt rfy jszcx hi vemt kvy hrmxichpiei rbx giwtrh zxxlgv duqhvbzqm, wlvc ns uui xdzba ws ypms nr hf xk hijikwvf.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    import re
    from functools import reduce
    # 最大公因数
    def GCDa, b):
    if b == 0:
    return a
    else:
    return GCD(b, a % b)

    # 整理原文段,删去除字母以外的内容,都改成小写
    def neatc):
    c_new = ''
    for word in c:
    if65 <= ord(word) <= 90or97 <= ord(word) <= 122):
    c_new += word.lower()
    return c_new

    def toletteroffset):
    letter = ''
    alphabet = [chr(i) for i in range97, 123)]
    for i in offset:
    letter += alphabet[i]
    print"密钥:{}".format(letter))
    return letter

    # 26字母出现的频数字典,原文按照秘钥长度分组
    def P_freqc_new, key_len, col):
    text = list() # 存放原文按秘钥长度分组后的内容
    P_fre = list() # 存放text中26字母的频数/秘钥长度
    alphabet = [chr(i) for i in range97, 123)] # 26字母列表
    # 原文分组
    for i in rangelen(c_new)):
    if i % key_len == col:
    text.append(c_new[i])
    # 频率计算
    for i in range26):
    P_fre.append(text.count(alphabet[i]) / key_len)
    return P_fre

    # 计算P、Q相关卷积,最大值对应位移量
    def CorrelationP, Q):
    max_cor = 0 # 记录最大的卷积
    for i in range26):
    cor = 0
    for j in range26):
    # 卷积计算
    cor += P[(j + i) % 26] * Q[j]
    # 找出最大的卷积,其索引为key
    if cor > max_cor:
    max_cor = cor
    key = i
    return key

    # Kasiski测试:秘钥长度
    def Kasiskic_new):
    # 储存单个重复字段开始索引
    indexes = list()
    # 设定重复字段长度
    word_len = 3
    # 记录大重复字段出现次数
    count = 0
    # 记录重复字段
    K_word_dict = dict()
    # 用于存储多个距离差 重复字段的索引-重复字段第一次出现索引
    tpl = tuple()
    # gcd的结果
    gcd_result_lst = list()

    # 滑动窗口样式的遍历全文,找到全部存在的重复字段,存到字典当中,重复字段:出现次数
    for i in rangelen(c_new) - 2):
    K_word = ''
    for j in range0, word_len):
    K_word += c_new[i + j]
    # 查询整段密文字段重复次数
    count = c_new.count(K_word)
    # 记录最多出现的
    if count >= 2:
    if K_word not in K_word_dict.keys():
    K_word_dict[K_word] = count

    # 遍历字典
    for w in K_word_dict.keys():
    # 找出一个重复字段的出现的位置
    index = re.finditer(w, c_new)
    for i in index:
    indexes.append(i.span()[0] + 1
    # 位置存放在indexes中,计算距离差:每个值都减去第一次出现这个字段的位置索引,并删去第一个位置。
    for j in rangelen(indexes)):
    if j > 0:
    indexes[j] -= indexes[0]
    indexes.pop(0
    tpl += tuple(indexes)
    indexes.clear()
    # 算出这个重复字段距离差的GCD
    gcd_result_lst.append(reduce(GCD, tpl))

    print'密文中重复出现的文字段:\n{}'.format(K_word_dict))
    print'对应文字段距离差为:\n{}'.format(gcd_result_lst))
    # 如果计算出为1,则猜测为列表中的非1数值
    gcd_result = reduce(GCD, tuple(gcd_result_lst))
    if gcd_result == 1:
    print'猜测密钥为:{}'.format((listset(gcd_result_lst)))))
    else:
    print'猜测密钥为:{}'.format(gcd_result))

    # 拟重合指数测试法

    # 拟重合指数法:求偏移量
    def Chic_new, key_len):
    result = list() # 存放全部位移量
    # 通常文本的字母概率分布Q
    Q = [8.19, 1.47, 3.83, 3.91, 12.25, 2.26, 1.71, 4.57, 7.10, 0.14, 0.41, 3.77, 3.34, 7.06, 7.26, 2.89, 0.09, 6.85,
    6.36, 9.41, 2.58, 1.09, 1.59, 0.21, 1.58, 0.08]
    # 密文的字母概率分布P
    P = list()
    for i in range0, key_len):
    P = P_freq(c_new, key_len, i)
    result.append(Correlation(P, Q))
    P.clear()
    print'偏移量分别为:{}'.format(result))
    return result

    # 加密
    def encryptomingwen, key):
    miwen = [0] * (len(mingwen))
    count = 0
    for i in rangelen(mingwen)):
    if (mingwen[i].isalpha()):
    if (mingwen[i].isupper()):
    offset1 = ord(key[(i - count) % len(key)]) - ord'a'
    miwen[i] = chr(((ord(mingwen[i]) - ord'A')) + offset1) % 26 + ord'A'))
    else:
    offset2 = ord(key[(i - count) % len(key)]) - ord'a'
    miwen[i] = chr(((ord(mingwen[i]) - ord'a')) + offset2) % 26 + ord'a'))
    else:
    miwen[i] = mingwen[i]
    count = count + 1
    return miwen

    # 解密
    def decryptomiwen, key):
    mingwen = [0] * (len(miwen))
    count = 0
    for i in rangelen(miwen)):
    if (miwen[i].isalpha()):
    if (miwen[i].isupper()):
    offset1 = ord(key[(i - count) % len(key)]) - ord'a'
    mingwen[i] = chr(((ord(miwen[i]) + ord'A')) - offset1) % 26 + ord'A'))
    else:
    offset2 = ord(key[(i - count) % len(key)]) - ord'a'
    mingwen[i] = chr(((ord(miwen[i]) - ord'a')) - offset2) % 26 + ord'a'))
    else:
    mingwen[i] = miwen[i]
    count = count + 1
    print'明文:'
    print''.join(mingwen))

    if __name__ == '__main__':
    c = input'请输入密文:'
    # 密文优化:删除标点,改为小写
    ciphertext = neat(c)
    # 密钥长度
    key_len = Kasiski(ciphertext)
    while True:
    # 输入密钥长度
    key_len_input = intinput'请输入想要实验的密钥长度:'))
    # 拟重合指数测试法:求偏移量
    offset = Chi(ciphertext, key_len_input)
    # 转换成英文字母
    key = toletter(offset)
    # 解密
    decrypto(ciphertext, key)
    # 多次试验
    stop = input'是否试验其他密钥(y/n):').lower()
    if stop == 'n':
    break