希爾密碼(hill密碼)
簡述
希爾密碼是利用矩陣進行加密的一種加密演算法,其本質是一種多表代換密碼。
百科:
希爾密碼是運用基本矩陣論原理的替換密碼,由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: 鄭州婦科醫院
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) 的方法不嚴謹地解決此問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2670140/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Hill密碼(Java)密碼Java
- 密碼安全:密碼設定要求,密碼爆破辦法,密碼歸類使用,密碼處置方案密碼
- 應用密碼學——古典密碼密碼學
- 序列密碼與分組密碼密碼
- 密碼密碼
- 應用密碼學 - 公鑰密碼密碼學
- 應用密碼學——分組密碼密碼學
- 現代密碼-公鑰密碼RSA密碼
- 《密碼學系列》|| 密碼學中的流密碼是怎麼回事?密碼學
- 拆分密碼密碼
- 移位密碼密碼
- 替代密碼密碼
- 密碼抓取密碼
- 密碼學密碼學
- PbootCMS忘記密碼後的重置密碼流程boot密碼
- 分組密碼(一) — 密碼學複習(四)密碼學
- 群暉NAS忘記密碼如何重置密碼密碼
- PDF密碼忘記了,如何找回口令密碼密碼
- 解碼伯克希爾:股神之道
- PbootCMS後臺登陸密碼忘記/找回密碼後臺登入密碼外掛boot密碼
- 密碼危機:深度學習正在加速密碼破解!密碼深度學習
- 密碼學與密碼安全:理論與實踐密碼學
- 寶塔找回密碼:忘記密碼怎麼辦?密碼
- mysql 5.7 初始化密碼或隨機密碼MySql密碼隨機
- 無密碼身份認證,跟密碼說再見!密碼
- 密碼學基礎概念 — 密碼學複習(一)密碼學
- 古典密碼的演化 (一)— 密碼學複習(二)密碼學
- 古典密碼的演化 (二)— 密碼學複習(三)密碼學
- 重磅 | 我國《密碼法》正式頒佈,解讀密碼分類與密碼裝置管理密碼
- python 建立密碼Python密碼
- ansible 修改密碼密碼
- 密碼安全加固密碼
- 密碼 hd 2043密碼
- PG密碼安全密碼
- 仿射密碼密碼
- Ubuntu 修改密碼Ubuntu密碼
- MySQL——密碼管理MySql密碼
- 密碼體制密碼