# playfair

# 基本原理

Playfair 算法基于一个 5*5 的字母矩阵,该矩阵使用一个关键词构造,方法是按从左到右、从上到下顺序,填入关键词的字母 (去除重复字母) 后,将字母表其作余字母填入。

例如:关键词取:monarchy 时,字母矩阵为下图如示 (矩阵只能放 25 个字母,I 与 J 同)

# 加密规则

Playfair 加密算法是先将明文按两个字母一组进行分组,然后在矩阵中找对应的密文。

取密文的规则如下:

1. 若明文出现相同字母在一组,则在重复的明文字母中插入一个填充字母 (eg:z) 进行分隔后重新分组 (eg: balloon 被重新分组为 ba lz lo on)

2. 若分组到最后一组时只有一个字母,则补充字母 z

3. 若明文字母在矩阵中同行,则循环取其右边下一个字母为密文 (矩阵最右边的下一个是最左边的第一个)(eg: ar 被加密为 RM)

4. 若明文字母在矩阵中同列,则循环取其下边下一个字母为密文 (矩阵最下边的下一个是最上边的第一个)(eg: mu 被加密为 CM)

5. 若明文字母在矩阵中不同行不同列,则取其同行且与同组另一字母同列的字母为密文 (eg: hs 被加密为 BP,ea 被加密为 IM 或 JM)

  • 举例:

明文为 we are discovered save yourself,分组成为 we ar ed is co ve re ds av ey ou rs el fz;

用上述矩阵加密后的密文为:UG RM KC SX HM UF MK BT OX GC MV AT LU KV

下面为代码 解密之后还没解决一些问题

import string
#j 用 i 代替
table="abcdefghiklmnopqrstuvwxyz"
def get_key(key):
    key=key.lower()
    k=[]
    c=[]
    j=0
    k1=[]
    for i in key:
        if(i not in k1):
            if(i=='j'):
                i='i'
            c.append(i)
            k1.append(i)
            j+=1
        if(j==5):
            j=0
            k.append(c)
            c=[]
    for i in table:
        if(i not in k1):
            c.append(i)
            k1.append(i)
            j += 1
        if (j == 5):
            j = 0
            k.append(c)
            c = []
    return k
def get_position(m,key):
    for i in range(5):
        for j in range(5):
            if(m==key[i][j]):
                return i,j
def encrypt(m,key):
    m1=''
    l=len(m)
    i=0
    #两两分组相同字母不能在同一组
    while(i<len(m)-1):
        if(m[i]==m[i+1]):
            m1=m1+m[i]+'z'
            i=i+1
            l+=1
        else:
            m1=m1+m[i]+m[i+1]
            i+=2
    #两两分组如果长度为奇数则末尾加 z
    if(l%2==1):
        m1=m1+m[len(m)-1]+'z'
    print(m1)
    c=''
    for i in range(0,l,2):
        i1,j1=get_position(m1[i],key)
        i2,j2=get_position(m1[i+1],key)
        #在同一行
        if(i1==i2):
            c=c+key[i1][(j1+1)%5]+key[i1][(j2+1)%5]
        #在同一列
        elif(j1==j2):
            c=c+key[(i1+1)%5][j1]+key[(i2+1)%5][j2]
        else:
            c=c+key[i1][j2]+key[i2][j1]
    return c
def decrypt(c,key):
    m = ''
    for i in range(0, len(c), 2):
        i1, j1 = get_position(c[i], key)
        i2, j2 = get_position(c[i + 1], key)
        # 在同一行
        if (i1 == i2):
            m = m + key[i1][(j1 - 1) % 5] + key[i1][(j2 - 1) % 5]
        # 在同一列
        elif (j1 == j2):
            m = m + key[(i1 - 1) % 5][j1] + key[(i2 - 1) % 5][j2]
        else:
            m = m + key[i1][j2] + key[i2][j1]
    #如果最后一位是 z 则去掉
    if(m[len(m)-1]=='z'):
        m=m[:-1]
    return m
key=input("输入密钥: ")
key=get_key(key)
message=input("输入明文: ")
message=message.replace('j','i').replace(' ','')
cipher=encrypt(message,key)
print(cipher)
message=decrypt(cipher,key)
print(message)