最近在看一本書。名字是 python密碼學編程。在此做一些筆記,同時也為有需要的人提供一些參考。
********************************************************************
* quote : "http://inventwithpython.com/" *
* python-version : 2.7.11 *
********************************************************************
1.第一種加密方法。反轉加密法。
即通過反向輸出消息來進行加密。例如將“Hello World” 加密成 “dlroW olleH”
這是一種非常弱的加密方式。么什了說它清弄以可然仍你,密加被已息信條這使即
1 message = "Three can keep a secret,if two of them are dead." 2 translated = '' 3 4 i = len(message) - 1 5 while i >= 0: 6 translated = translated + message[i] 7 i = i - 1 8 print translated
實現思路也非常簡單。就是把一個String從后到前拼接到另一個String上。
至於解密。可以使message 為加密后的密文,打印出來的即為明文。
2.凱撒加密法
凱撒加密(Caesar cipher)是一種簡單的消息編碼方式:它根據字母表將消息中的每個字母移動常量位k。舉個例子如果k等於3,則在編碼后的消息中,每個字母都會向前移動3位:a會被替換為d;b會被替換成e;依此類推。字母表末尾將回卷到字母表開頭。於是,w會被替換為z,x會被替換為a
1 message = "this is my secret message" 2 key = 13 3 4 mode = "encrypt" 5 LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 6 translated = '' 7 message = message.upper() 8 9 for symbol in message: 10 if symbol in LETTERS: 11 num = LETTERS.find(symbol) 12 if mode == "encrypt": 13 num = num + key 14 elif mode == "decrypt": 15 num = num - key 16 17 if num >= len(LETTERS): 18 num = num - len(LETTERS) 19 elif num < 0: 20 num = num + len(LETTERS) 21 22 translated = translated + LETTERS[num] 23 24 else: 25 translated = translated + symbol 26 27 print translated
首先。message 保存了要加密的消息。key 保存了秘鑰。mode 表示模式,encrypt為加密,decrypt為解密。translated 為加密后的字符串。.upper()方法用來忽略大小寫。
具體實現。遍歷message 中的每一個字符。
如果該字符屬於26個英文字母。
當模式為加密時,就把這個字符在字母表中的位置加上秘鑰 key。用新的位置的字符來替換。如果加上秘鑰之后的值超過了字母表的長度,我們需要回滾,即減去一個字母表的長度來確定它的新位置。
當模式為解密時,就減去key。注意位置小於0時要加上一個字母表的長度。
字符不是英文字母時不用替換,直接拼接到新字符串上即可。
3.暴力破解凱撒加密法
對於我們上面那種情況的凱撒加密法,我們可以發現可能的秘鑰最多只有26個。於是我們可以嘗試暴力破解,即嘗試每一個可能的秘鑰。
1 message = "GUVF VF ZL FRPERG ZRFFNTR" 2 LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 3 4 for key in range(len(LETTERS)): 5 translated = '' 6 for symbol in message: 7 if symbol in LETTERS: 8 num = LETTERS.find(symbol) 9 num = num - key 10 if num < 0: 11 num += len(LETTERS) 12 translated += LETTERS[num] 13 else: 14 translated += symbol 15 print "Key %s : %s"%(key , translated)
這段代碼和上面的代碼有很多相似。
message 存儲了密文。其余代碼對應了上面的 decrypt 模式。
我們打印出了26中可能的解密。
4.換位加密法
換位加密法不是替換字符,而是搞亂消息符號的順序。
例如消息 Common sense is not so common.
假設使用數字 8 作為秘鑰。也就是我們將在每一行放最多8個字符。(包含空格和標點)
對於上面這條消息,我們可以畫出這樣一個方格圖
C | o | m | m | o | n | s | |
e | n | s | e | i | s | ||
n | o | t | s | o | c | ||
o | m | m | o | n | . |
最后一行的兩個格子塗黑忽略它們。
正常的閱讀方式應該是橫向去讀。如果我們把消息用列向表示出來,它的混亂程度足以讓別人看不清原來的消息
密文是 Cenoonommstmme oo snnio. s s c (表中的空格需要表示,黑色方格直接忽略)
1 def main(): 2 myMessage = "Common sense is not so common." 3 myKey = 8 4 5 ciphertext = encryptMessage(myKey , myMessage) 6 7 print ciphertext + "|" 8 9 def encryptMessage(key , message): 10 ciphertext = ['']*key 11 12 for col in range(key): 13 pointer = col 14 15 while pointer < len(message): 16 ciphertext[col] += message[pointer] 17 pointer += key 18 return ''.join(ciphertext) 19 20 if __name__ == "__main__": 21 main()
具體到 encryptMessage 函數。我們首先創建了一個 list ,其中包含了 8(key)個空元素。這對應了上面表格中的8 (key) 列。
我們遍歷這 8 列。
在第一列,我們依次拼接 原 message 中的 第 0,8,16,24......個字符。直到超出了 message 的長度。
在第二列,我們依次拼接 原 message 中的 第 1,9,17,25......個字符。直到超出了 message 的長度。
以此類推。
.join 方法將 list 轉換為字符串然后 return。
換位加密法的解密過程:
當我們收到密文和秘鑰之后。我們需要畫一個表格。表格行數等於秘鑰,列數等於 密文長度除以秘鑰然后向上取整。
例如 密文 “Cenoonommstmme oo snnio. s s c”長度30,秘鑰key = 8,我們需要畫8行4列的表格
從左上角開始向右填。那么從上往下閱讀時我們會看到明文(其實這兩個表格的關系就類似於矩陣的倒置)
C | e | n | o |
o | n | o | m |
m | s | t | m |
m | e | o | |
o | s | n | |
n | i | o | . |
s | |||
s | c |
1 import math 2 3 def main(): 4 myMessage = "Cenoonommstmme oo snnio. s s c" 5 myKey = 8 6 7 ciphertext = decryptMessage(myKey , myMessage) 8 9 print ciphertext + "|" 10 11 def decryptMessage(key , message): 12 numOfColumns = int(math.ceil(len(message) / float(key))) 13 numOfRows = key 14 numOfShadeBoxes = (numOfColumns * numOfRows) - len(message) 15 plaintext = [''] * numOfColumns 16 17 col = 0 18 row = 0 19 for symbol in message: 20 plaintext[col] += symbol 21 col += 1 22 23 if col == numOfColumns or col == numOfColumns - 1 and row >= numOfRows - numOfShadeBoxes: 24 col = 0 25 row += 1 26 return ''.join(plaintext) 27 28 if __name__ == "__main__": 29 main()
這個程序完全按照和前面填表格的方式進行。
先從第0行開始,依次填第零列,第一列,第二列,第三列
然后跳到下一行,依次進行
其中。numOfShadedboxes 表示的是黑方格數,也就是默認不填字符的位置。程序會跳過這些地方填字符。
好的。現在讓我們來寫一個測試程序證明前面的加密和解密程序在對應不同的 message 和 key 時確實能正常工作。
1 import random,sys,transpositionEncrypt,transpositionDecrypt 2 3 def main(): 4 random.seed(42) 5 for i in xrange(20): 6 message = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" * random.randint(4,40) 7 message = list(message) 8 random.shuffle(message) 9 message = ''.join(message) 10 print "Test #%s : %s..."%(i+1,message[:50]) 11 12 for key in xrange(1,len(message)): 13 if message != transpositionDecrypt.decryptMessage(key , transpositionEncrypt.encryptMessage(key, message)): 14 print "Mismatch with key %s and message %s"%(key , message) 15 sys.exit() 16 print "Transposition cipher test passed." 17 18 if __name__ == "__main__": 19 main()
其中。import 語句中。transpositionEncrypt , transpositionDecrypt 為我們之前寫的換位法 加密 和 解密 的py程序名。
測試中,我們生成了一個全英文字母的隨機字符串並打亂了順序,通過測試在將一個字符串加密再解密后是否能得到原來的字符串來判斷程序是否正常工作。