Bootstrap

hill(希尔)密码

学习目标:

实现hill(希尔)密码


具体实现过程

  1. 上课听老师讲解古典密码
  2. 掌握基本python语法
  3. 上网查找资料
  4. 了解并实现hill密码的加解密

学习时间:

  • 5月1日到5月2日
  • 周日下午 6 点-下午 9 点
  • 周一早上 8 点到 12 点

学习产出:

  • CSDN 技术博客 1 篇
  • 加解密代码

整体代码


import numpy as np
# 输入矩阵并判断是否存在逆矩阵
def inputMatrix():
    while True:
        # 输入一行、作为行列式的阶数和行列式的第一行
        rank = list(input("").split())
        matrix = [[0] * len(rank) for i in range(len(rank))]
        matrix[0] = rank
        # 输入行列式剩余数据
        for i in range(1, len(matrix)):
            matrix[i] = list(input("").split())
            # 判断每一行输入是否合法
            if len(matrix[i]) != len(matrix):
                print("输入有误,重新输入。")
                continue
        # 转换字符型为整型
        for i in range(len(matrix)):
            matrix[i] = list(map(lambda x: int(x), matrix[i]))
        # 判断是否存在逆矩阵
        if not judgeInverse(matrix):
            print("矩阵不存在逆矩阵,重新输入。")
            continue
        return matrix

def gcd(a,b): # 最大公约数
    while b>0:
        rem=a%b
        a=b
        b=rem
    return a

# 判断是否存在逆元
def judgeInverse(matrix):
    det = np.mat(matrix)
    D = np.linalg.det(det)  # 行列式值
    if gcd(D, 26)==1:
        return True
    return False
# 计算代数余子式
def alge_comple(matrix,i,j):
    Aij1=matrix[(i+1)%len(matrix)][(j+1)%len(matrix)]*matrix[(i+2)%len(matrix)][(j+2)%len(matrix)]
    Aij2=matrix[(i+1)%len(matrix)][(j+2)%len(matrix)]*matrix[(i+2)%len(matrix)][(j+1)%len(matrix)]
    Aij=Aij1-Aij2
    return Aij

# 生成密钥(矩阵的逆矩阵)
def createMatrixInverse(matrix):
    # 计算行列式值的模逆D-invert
    det = np.mat(matrix) # 矩阵
    D = np.linalg.det(det) # 行列式值
    for i in range(26):
        if (i*D-1)%26==0:
            D_invert=i
            break
    matrix_inverse=[]
    # Aij=(-1)^(i+j)|余子式|
    # Aij*D_invert%26每个位置的元素
    for i in range(len(matrix)):
        tmp=[] # 每一行的元素
        for j in range(len(matrix)):
            Aij=alge_comple(matrix,i,j)
            tmp.append((Aij*D_invert)%26)
        matrix_inverse.append(tmp)
    Matrix_inverse=np.matrix.tolist(np.matrix(matrix_inverse).T) # 先转置,再转化为列表
    return Matrix_inverse

# 生成消息分组
def createMassageList(massage, matrix):
    matrixRank = len(matrix)
    massageList = []
    for i in range(0, len(massage), matrixRank):
        massageList.append(massage[i:i + matrixRank])
    return massageList

# 字母序列转化为数字
def letterToDigit(massageList):
    massageDigitList = []  # 替换后的数字列表
    letterList = []  # 字母列表
    for i in range(ord("a"), ord("z") + 1):
        letterList.append(chr(i))
    for massage in massageList:
        listTmp = []
        for i in range(len(massage)):
            listTmp.append(letterList.index(massage[i]))
        massageDigitList.append(listTmp)
    return massageDigitList

# 数字序列转化为字母
def digitToLetter(massageList):
    massageLetterList = []  # 还原后的字母列表
    letterList = []
    for i in range(ord("a"), ord("z") + 1):
        letterList.append(chr(i))
    # 替换数字为字母
    for massage in massageList:
        massageLetterList.append(letterList[massage % 26])
    return massageLetterList

# 加密
def encrypt(massage, matrix):
    ciphertextList = [] # 加密结果列表
    massageList = createMassageList(massage, matrix)
    massageDigitList = letterToDigit(massageList)
    # 矩阵相乘
    for massageDigit in massageDigitList:
        for i in range(len(massageDigit)):
            sum = 0
            for j in range(len(massageDigit)):
                sum += massageDigit[j] * matrix[j][i % len(matrix)]
            ciphertextList.append(sum % 26)
    CiphertextList=digitToLetter(ciphertextList)
    return CiphertextList

# 解密
def decrypt(massage, matrix):
    plaintextList = []  # 解密结果列表
    matrix_inverse = createMatrixInverse(matrix)
    massageList = createMassageList(massage, matrix)
    massageDigitList=letterToDigit(massageList)
    # 矩阵相乘
    for msg in massageDigitList:
        for i in range(len(msg)):
            sum = 0
            for j in range(len(msg)):
                sum += msg[j] * matrix_inverse[j][i % len(matrix)]
            plaintextList.append(sum % 26)
    plaintextList = digitToLetter(plaintextList)    # 数字转换为字母
    plaintext = ""
    for item in plaintextList:
        plaintext += item
    return plaintext

if __name__ == "__main__":
    while True:
        print("—————希尔密码—————")
        choice = input("1、加密        2、解密        0、退出\n请选择:")
        if choice == "1":
            print("输入矩阵:")
            matrix = inputMatrix()
            massage = input("输入msg:")
            massageList = createMassageList(massage, matrix)
            ciphertextList = encrypt(massage, matrix)
            secr=''.join(ciphertextList)
            print("加密结果:", secr)
        elif choice == "2":
            massag = list(input("输入密文:"))
            Massag = [str(i) for i in massag]
            massageList = list(Massag)
            print("输入矩阵:")
            matrix = inputMatrix()
            matrix_inverse = createMatrixInverse(matrix)
            print("逆矩阵:")
            for item in matrix_inverse:
                print(item)
            plaintext = decrypt(massageList, matrix)
            print("解密结果:", plaintext)
        else:
            break

代码块讲解

  • 这部分是判断行列式是否有逆矩阵
def gcd(a,b): # 最大公约数
    while b>0:
        rem=a%b
        a=b
        b=rem
    return a

# 判断是否存在逆元
def judgeInverse(matrix):
    det = np.mat(matrix)
    D = np.linalg.det(det)  # 行列式值
    if gcd(D, 26)==1:
        return True
    return False

  • 这部分是求矩阵在模26的情况下实现的求逆矩阵方法
    具体的求模逆方法会在后面有链接
def createMatrixInverse(matrix):
    # 计算行列式值的模逆D-invert
    det = np.mat(matrix) # 矩阵
    D = np.linalg.det(det) # 行列式值
    for i in range(26):
        if (i*D-1)%26==0:
            D_invert=i
            break
    matrix_inverse=[]
    # Aij=(-1)^(i+j)|余子式|
    # Aij*D_invert%26每个位置的元素
    for i in range(len(matrix)):
        tmp=[] # 每一行的元素
        for j in range(len(matrix)):
            Aij=alge_comple(matrix,i,j)
            tmp.append((Aij*D_invert)%26)
        matrix_inverse.append(tmp)
    Matrix_inverse=np.matrix.tolist(np.matrix(matrix_inverse).T) # 先转置,再转化为列表
    return Matrix_inverse

这里有运行结果:
在这里插入图片描述

总结

  • 写这篇文章我也有借鉴另一篇博主的代码,他的框架我有引用,但是实现过程的思路,以及求逆矩阵我是自己实现的,因为模逆矩阵不是简单意义上的线性变换,这一点我参照的是这篇知乎文章:
    密码学-矩阵求模逆的方法 - 饮笑的文章 - 知乎(链接不能放太多,所以就暂时不放了)
  • 然后大体框架我是借鉴了这位博主的文章:
    http://t.csdn.cn/8Uv7B
    但是因为我在加解密过程中发现一些不合适的地方,再对具体实现过程和思路进行了改造
;