您好,登錄后才能下訂單哦!
簡述
希爾密碼是利用矩陣進行加密的一種加密算法,其本質是一種多表代換密碼。
百科:
希爾密碼是運用基本矩陣論原理的替換密碼,由Lester S. Hill在1929年發明。
每個字母當作26進制數字:A=0, B=1, C=2… 一串字母當成n維向量,跟一個n×n的矩陣相乘,再將得出的結果模26。
注意用作加密的矩陣(即密匙)在 必須是可逆的,否則就不可能解碼。只有矩陣的行列式和26互質,才是可逆的。
希爾密碼由于采用矩陣運算加密,因此在相同的明文加密時,可能會出現不同的密文,因此可以很好的抵御字母頻率攻擊法。
加解密
加密:
1、定義一個矩陣a(須存在逆矩陣)作為加密密鑰:
[1,2,1]
[0,2,1]
[1,0,2]
2、將需要加密的明文字母轉換為其對應的字母表數字(1-a,2-b……);
3、將轉換后的明文數字序列按照密鑰矩陣的階數進行分組(如本次為3個字符一組);
4、每組數字序列和密鑰矩陣進行矩陣的乘法運算(1x3 矩陣乘以 3x3矩陣),結果即為密文數字序列;
5、可將密文數字序列轉換為其對應字母,即為密文字符串。
解密:
解密流程與加密相同,唯一不同之處在于:需先求出加密密鑰的逆矩陣
在做矩陣相成時,用密文分組乘以逆矩陣,結果即為明文
代碼實現
#!/usr/bin/python3.7
# -*- coding: utf-8 -*-
# @Time : 2019/12/11 14:53
# @Author : SystemDefenser
# @Email : mrwx1116@163.com
# @Software: PyCharm
from numpy import linalg
# 輸入矩陣并判斷是否存在逆矩陣
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 judgeInverse(matrix):
try:
linalg.inv(matrix)
except:
return False
return True
# 生成密鑰(矩陣的逆矩陣)
def createMatrixInverse(matrix):
try:
matrix_inverse = linalg.inv(matrix)
except:
return -1
return matrix_inverse
# 生成消息分組
def createMassageList(massage, matrix):
matrixRank = len(matrix)
massageList = []
# 擴充消息序列并創建分組
while len(massage) % matrixRank != 0:
massage += " "
for i in range(1, len(massage) + 1, matrixRank):
massageList.append(massage[i-1:i + matrixRank - 1])
return massageList
# 字母序列轉化為數字
def letterToDigit(massageList):
massageDigitList = [] # 替換后的數字列表
letterList = [] # 字母列表
for i in range(ord("a"), ord("z") + 1):
letterList.append(chr(i))
for i in range(10):
letterList.append(str(i))
# 添加空格,解決分組填充問題
letterList.append(" ")
# 替換字母為數字
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 i in range(10):
letterList.append(str(i))
letterList.append(" ")
# 替換數字為字母
for massage in massageList:
massageLetterList.append(letterList[massage % 37])
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 % 37)
return ciphertextList
# 解密
def decrypt(massage, matrix):
plaintextList = [] # 解密結果列表
matrix_inverse = createMatrixInverse(matrix)
massageList = createMassageList(massage, matrix)
# 矩陣相乘
for msg in massageList:
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 % 37)
# 浮點型轉換為整型(采用四舍五入——round())
plaintextList = list(map(lambda x: int(round(x)), plaintextList))
plaintextList = digitToLetter(plaintextList) # 數字轉換為字母
plaintext = ""
for item in plaintextList:
plaintext += item
return plaintext
if __name__ == "__main__":
while True: 鄭州婦科醫院 http://fk.zyfuke.com/
print("—————希爾密碼—————")
choice = input("1、加密 2、解密\n請選擇:")
if choice == "1":
print("輸入矩陣:")
matrix = inputMatrix()
massage = input("輸入msg:")
massageList = createMassageList(massage, matrix)
ciphertextList = encrypt(massage, matrix)
print("加密結果:", ciphertextList)
elif choice == "2":
massageList = list(map(int, list(input("輸入密文序列:").split(","))))
print("輸入矩陣:")
matrix = inputMatrix()
matrix_inverse = createMatrixInverse(matrix)
print("逆矩陣:")
for item in matrix_inverse:
print(item)
plaintext = decrypt(massageList, matrix)
print("解密結果:", plaintext)
其中,求逆矩陣部分未能手算,調用了numpy庫中的linalg函數,慚愧………………
加密測試
—————希爾密碼—————
1、加密 2、解密
請選擇:1
輸入矩陣:
1 0 1 1
0 1 0 1
1 1 0 0
1 1 0 1
輸入msg:systemdefenser
加密結果: [18, 24, 18, 24, 11, 19, 4, 20, 36, 35, 5, 27, 2, 15, 4, 20]
—————希爾密碼—————
1、加密 2、解密
請選擇:2
輸入密文序列:18, 24, 18, 24, 11, 19, 4, 20, 36, 35, 5, 27, 2, 15, 4, 20
輸入矩陣:
1 0 1 1
0 1 0 1
1 1 0 0
1 1 0 1
逆矩陣:
[ 0. -1. 0. 1.]
[ 0. 1. 1. -1.]
[ 1. 1. 1. -2.]
[ 0. 0. -1. 1.]
解密結果: systemdefenser
加密:
解密:
部分代碼詳解
輸入矩陣部分
代碼片段:
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
該片段位于 inputMatrix() 函數中。
輸入矩陣部分未讓用戶先定義階數,而是通過用戶輸入的矩陣第一行,來決定本次矩陣的階數,并且不斷進行合法判斷。
解密部分
代碼片段:
# 浮點型轉換為整型(采用四舍五入——round())
plaintextList = list(map(lambda x: int(round(x)), plaintextList))
plaintextList = digitToLetter(plaintextList) # 數字轉換為字母
該片段位于 decrypt(massage, matrix) 函數中。
由于逆矩陣存在不可約分或整除的小數,因此在此處采用四舍五入round(x) 的方法不嚴謹地解決此問題。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。