密码学+piayfair密码大题

 

目录

理论部分 

参考资料

课堂练习

代码部分


本文用于个人学习,如有不足还请指正。


一、理论部分 


参考资料


 Playfair密码_王文强的博客-CSDN博客_playfair密码https://blog.csdn.net/u012429555/article/details/78527195 playfair 加密与解密_Cinnady_的博客-CSDN博客_playfair密码在线解密https://blog.csdn.net/qq_44623737/article/details/106483060 playfair加密过程(密码学_古典密码学_多图加密算法)_weixin_30491641的博客-CSDN博客https://blog.csdn.net/weixin_30491641/article/details/99915755


课堂练习


密钥boys and girls are students ( 按列填充密钥, 不在同一行或列的密文,采用纵向替换)

密文GUUID BCYZC YOETX UUGAB EPBCE TDIUV LDDSB KRPRD IRUW

请对上述的密文进行解密

解密结果:明文(原文):It is not a problem. It is a challenge. Enjoy facing it.


1、整理密钥

  • 删掉空格、删掉重复字母

整理后密钥为:boysandgirletu 

2、编制密码表

  • 5*5密码表(依题意按列编码)
  • i 和 j 算同一格 
bnlfq
odehr
ygtkv
si/jumw
arcpx

3、将密文两两分组

  • 如果有两个相同字母紧挨或最后一个字母是单个的,就插入一个字母X(或者Q)
    如,communist,应成为co,mx,mu,ni,st。

 GU UI DB CY ZC YO ET XU UG AB EP BC ET DI UV LD DS BK RP RD IR UW

 4、编写密文

  • 加密看右看下,解密看左看上

GU——>it 

不在同行同列,则c1 c2是由p1 p2确定的矩形的其他两角的字母

(至于横向替换还是纵向替换要事先约好,或自行尝试)

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

UI——>is 

同行,对应明文c1 c2分别是紧靠p1 p2左端的字母。

其中第一列被看做是最后一列的右方。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

DB——>no 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

 CY——>ta

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

 ZC——>pr

密码表中没有Z。这时候把表中使用频率最少的字母去掉,或把密文中没有出现的字母在密码表中删掉,比如删掉Q。

更改密码表为:

bnlfr
odehv
ygtkw
si/jumx
arcpz

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

 YO——>ob

同列:对应明文p1 p2分别是紧靠c1 c2 上方的字母。其中最后一行被看做是第一行的上方。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_10,color_FFFFFF,t_70,g_se,x_16

 


二、实验报告


要求


 从键盘上接收明文输入,密钥输入。

Ⅰ密钥的处理过程:

①将密钥输入全部转换成大写

②并且遇到J字母替换成I字母

③将密钥中重复出现的字母剔除

④按照字母表顺序将密钥未出现的字母进行填充

⑤按照5*5的矩阵输出密钥

Ⅱ明文的处理过程:

①将密钥输入全部转换成大写

②并且遇到J字母替换成I字母

③将明文两两一组,如果出现两个字母一样则插入Z如果相同的字母是Z则依次A-Y的顺序递推到不相等

④经过处理的字符串如果是奇数长度则最后一个字母补充字母,如果最后一个字母是Z则依次A-Y的顺序递推到不相等

Ⅲ加密过程

明文两两一组,比如NA TZ TE RI AC KT OA DZ,经过填充处理的密钥是STANDERCHBKFGILMOPQUVWXYZ。每次获取两个字母,则有三种处理方式:

第一种:处于同一行情况

比如NA字母在密钥中的位置分别是第3和第2,

row1=3/5=0,col1=3%5=3,可知N字母在5*5的矩阵中是处于0行3列,同理

row2=2/5=0,col2=2%5=2,可知A字母在5*5的矩阵中是处于0行2列,

此时有行相等,故只用列向右挪动1列,即col1=(col1+1)%5计算出挪动1列后新的列,此时保持row1不变的情况下组成新的位置(row1, col1),然后row1*5+co1计算出在密钥中的新位置

第二种:处于同一列情况

比如AC字母在密钥中的位置分别是第2和第7,

row1=2/5=0,col1=2%5=2,可知A字母在5*5的矩阵中是处于0行2列,同理

row2=7/5=1,col2=7%5=2,可知C字母在5*5的矩阵中是处于1行2列,

此时有列相等,故只用行向下挪动1行,即row1=(row1+1)%5计算出挪动1行后新的行,此时保持col1不变的情况下组成新的位置(row1, col1),然后row1*5+co1计算出在密钥中的新位置

第三种:不在同一列或者同一行需要绘制矩形框

S

T

A

N

D

E

R

C

H

B

K

F

G

I

L

M

O

P

Q

U

V

W

X

Y

Z

比如KT字母在密钥中的位置分别是第10和第1,

row1=10/5=2,col1=10%5=0,可知K字母在5*5的矩阵中是处于2行0列,同理

row2=1/5=0,col2=1%5=1,可知T字母在5*5的矩阵中是处于0行1列,行列都不等,故需要绘制矩形框,经过观察可以发现,K的对应点F的坐标就是K的行+T的列,T的对应的S的坐标就是K的行+T的列构成


输出范例


watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_13,color_FFFFFF,t_70,g_se,x_16


 参考资料:

 密码学—Playfair加密算法 python实现_miilue的博客-CSDN博客

信息安全-1:python之playfair密码算法详解[原创] - 前程明亮 - 博客园 (cnblogs.com)


代码部分


 

import pprint

# 字母表
alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'

 
# 处理密钥
def remove_duplicates(key):
    # 将密钥输入全部转换成大写
    key = key.upper()   
    _key = ''
    # J字母替换成I字母
    for ch in key:
        if ch == 'J':
            ch = 'I'           
        if ch in _key:
            continue
        else:
            _key += ch    
    return _key

 
# 建密码表
def create_matrix(key):
    # 删除密钥中的重复字母
    key = remove_duplicates(key)
    # 删除密钥中的空格
    key = key.replace(' ', '')
    print("将J替换成I且去重后的key是:",key)
    # 根据密钥获取新组合的字母表
    for ch in alphabet:  
        if ch not in key:
            key += ch
    # 密码表
    keys = [[i for j in range(5)] for i in range(5)]
    # 将新的字母表里的字母逐个填入密码表中,组成5*5的矩阵
    for i in range(len(key)):  
        keys[i // 5][i % 5] = key[i]  # j用来定位字母表的行       
    print("填充的key是:")    
    pprint.pprint(keys)# pprint用来美化打印的矩阵
    return keys
 
# 获取字符在密码表中的位置
def get_matrix_index(ch, keys):
    # i为行,j为列
    for i in range(5):
        for j in range(5):
            if ch == keys[i][j]:
                return i, j   
            
def get_ctext(ch1, ch2, keys):
    index1 = get_matrix_index(ch1, keys)
    index2 = get_matrix_index(ch2, keys)
    r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    # 若字母在矩阵中同行
    if r1 == r2:
        ch1 = keys[r1][(c1+1) % 5]
        ch2 = keys[r2][(c2+1) % 5]
    # 若字母在矩阵中同列
    elif c1 == c2:
        ch1 = keys[(r1+1) % 5][c1]
        ch2 = keys[(r2+1) % 5][c2]
    # 若字母在矩阵中既不同行也不同列
    else:
        ch1 = keys[r1][c2]
        ch2 = keys[r2][c1]
    text = ''
    text += ch1
    text += ch2
    return text


def get_ptext(ch1, ch2, keys):
    index1 = get_matrix_index(ch1, keys)
    index2 = get_matrix_index(ch2, keys)
    r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    # 若字母在矩阵中同行
    if r1 == r2:
        ch1 = keys[r1][(c1-1) % 5]
        ch2 = keys[r2][(c2-1) % 5]
    # 若字母在矩阵中同列
    elif c1 == c2:
        ch1 = keys[(r1-1) % 5][c1]
        ch2 = keys[(r2-1) % 5][c2]
    # 若字母在矩阵中既不同行也不同列
    else:
        ch1 = keys[r1][c2]
        ch2 = keys[r2][c1]
    text = ''
    text += ch1
    text += ch2
    return text

# 加密过程
def playfair_encode(plaintext, key):
    # 删空格
    plaintext = plaintext.replace(" ", "")
    # 转大写
    plaintext = plaintext.upper()
    # 遇到J字母替换成I字母
    plaintext = plaintext.replace("J", "I")
    # 将字符串转化为列表
    plaintext = list(plaintext)
    plaintext.append('#')
    plaintext.append('#') 
    keys = create_matrix(key)
    ciphertext = ''
    i = 0
    while plaintext[i] != '#':
        # 两个字母一样则插入Z
        if plaintext[i] == plaintext[i+1]:
            plaintext.insert(i+1, 'Z')
        # 奇数长度时补充字母X
        if plaintext[i+1] == '#':
            plaintext[i+1] = 'X'
        ciphertext += get_ctext(plaintext[i], plaintext[i+1], keys)
        i += 2
    return ciphertext


# 解密
def playfair_decode(ciphertext, key):  
    keys = create_matrix(key)
    i = 0
    plaintext = ''
    while i < len(ciphertext):
        plaintext += get_ptext(ciphertext[i], ciphertext[i+1], keys)
        i += 2
    _plaintext = ''
    _plaintext += plaintext[0]
    for i in range(1, len(plaintext)-1):
        if plaintext[i] != 'X':
            _plaintext += plaintext[i]
        elif plaintext[i] == 'X':
            if plaintext[i-1] != plaintext[i+1]:
                _plaintext += plaintext[i]
    _plaintext += plaintext[-1]
    _plaintext = _plaintext.lower()
    return _plaintext
 

while True:
    print("***************************")
    print("    * 1. playfair加密 *    ")
    print("    * 2. playfair解密 *    ")
    print("    * 0. 退出 *    ")
    print("***************************")
    choice = int(input("请选择:"))
    if choice == 1:
        #进行加密        
        plaintext = input("请输入明文:")
        key = input("请输入密钥:")
        ciphertext = playfair_encode(plaintext, key)        
        print('加密后的密文:' + ciphertext)
    elif choice == 2:
        #进行解密
        plaintext = playfair_decode(ciphertext, key)
        print('解密后的明文:' + plaintext)
    elif choice == 0:
        print ("您已退出程序!")
        break
    else: print ("您的输入有误!请输入0~2进行选择!")
   

 


问题1


 输出规则的5*5矩阵

 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_15,color_FFFFFF,t_70,g_se,x_16

 用print(keys) 打印出来是不美观的矩形

 运行结果如下:watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_20,color_FFFFFF,t_70,g_se,x_16

改用pprint,优化输出 

需import pprint

 参考资料:

python美化打印的标准库:pprint() - 简书 (jianshu.com)https://www.jianshu.com/p/b829a428ed3a

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBALVNFVkVOVEVFTi0=,size_15,color_FFFFFF,t_70,g_se,x_16

ae99dec9f2ae43d6a3061213300b8832.png

 

 

 

 

 

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值