python密码学编程 学习笔记
第1章 制作纸质加密工具
本章主要内容:
+ 密码学是什么
+ 代码和加密法
+ 凯撒加密法
+ 加密轮盘
+ St.Cyr滑条
+ 用纸笔做加密
+ “双重强度”加密
1.1 密码学是什么
- 密码学是使用秘密代码的科学
1.2 代码与加密法
- 用于电报(后来也用于无线电)的代码叫摩斯代码
1.3 制作纸质加密轮盘
加密轮盘
维基:
在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系。
虚拟加密轮盘
如何使用加密轮盘加密解密
- 给一个数字作为密钥,旋转,取对应的字母
另一个加密法工具:St.Cyr滑条
- 类似加密轮盘
不用纸质工具加密
- 给A-Z分别分配编号0-25
加密一个字母的步骤:
- 从1到25选一个密钥,保管好
- 找出明文字母的数字
- 把密钥加到这个明文字母的数字
- 如果结果大于25,则减去26
- 找出你计算的数字的字母,这就是密文字母
- 对明文消息里的每个字母重复步骤2-5
如果是解密,则密文字母的数字减去密钥
双重强度加密
- 对明文进行一次加密后,再对密文再进行一次加密
- 对于大多数加密法而言,多次加密不会增加密文的强度
第6章 凯撒加密法
代码
# Caesar Cipher
# http://inventwithpython.com/hacking (BSD Licensed)
import pyperclip
# the string to brypted/decrypted
message = 'This is my secret message.'
e enc
# the encryption/decryption key
key = 13
# tells the program to encrypt or decrypt
mode = 'encrypt' # set to 'encrypt' or 'decrypt'
# every possible symbol that can be encrypted
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# stores the encrypted/decrypted form of the message
translated = ''
# capitalize the string in message
message = message.upper()
# run the encryption/decryption code on each symbol in the message string
for symbol in message:
if symbol in LETTERS:
# get the encrypted (or decrypted) number for this symbol
num = LETTERS.find(symbol) # get the number of the symbol
if mode == 'encrypt':
num = num + key
elif mode == 'decrypt':
num = num - key
# handle the wrap-around if num is larger than the length of
# LETTERS or less than 0
if num >= len(LETTERS):
num = num - len(LETTERS)
elif num < 0:
num = num + len(LETTERS)
# add encrypted/decrypted number's symbol at the end of translated
translated = translated + LETTERS[num]
else:
# just add the symbol without encrypting/decrypting
translated = translated + symbol
# print the encrypted/decrypted string to the screen
print(translated)
# copy the encrypted/decrypted string to the clipboard
pyperclip.copy(translated)
第7章 暴力破译凯撒加密法
本章主要内容:
+ 科克霍夫原则和香农格言
+ 暴力破译技术
+ range()函数
+ 字符串格式化
破译加密
- 科克霍夫原则:加密系统应该是安全的,即使这个系统除了密钥之外的一切都为大家所知
- 香农格言:敌人知道系统
暴力破译
- 尝试每种可能的解密密钥的技术叫暴力破译
凯撒加密法破译程序
# Caesar Cipher Hacker
# http://inventwithpython.com/hacking (BSD Licensed)
message = 'GUVF VF ZL FRPERG ZRFFNTR.'
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# loop through every possible key
for key in range(len(LETTERS)):
# It is important to set translated to the blank string so that the
# previous iteration's value for translated is cleared.
translated = ''
# The rest of the program is the same as the original Caesar program:
# run the encryption/decryption code on each symbol in the message
for symbol in message:
if symbol in LETTERS:
num = LETTERS.find(symbol) # get the number of the symbol
num = num - key
# handle the wrap-around if num is 26 or larger or less than 0
if num < 0:
num = num + len(LETTERS)
# add number's symbol at the end of translated
translated = translated + LETTERS[num]
else:
# just add the symbol without encrypting/decrypting
translated = translated + symbol
# display the current key being tested, along with its decryption
print('Key #%s: %s' % (key, translated))
运行结果:
Key #0: GUVF VF ZL FRPERG ZRFFNTR.
Key #1: FTUE UE YK EQODQF YQEEMSQ.
Key #2: ESTD TD XJ DPNCPE XPDDLRP.
Key #3: DRSC SC WI COMBOD WOCCKQO.
Key #4: CQRB RB VH BNLANC VNBBJPN.
Key #5: BPQA QA UG AMKZMB UMAAIOM.
Key #6: AOPZ PZ TF ZLJYLA TLZZHNL.
Key #7: ZNOY OY SE YKIXKZ SKYYGMK.
Key #8: YMNX NX RD XJHWJY RJXXFLJ.
Key #9: XLMW MW QC WIGVIX QIWWEKI.
Key #10: WKLV LV PB VHFUHW PHVVDJH.
Key #11: VJKU KU OA UGETGV OGUUCIG.
Key #12: UIJT JT NZ TFDSFU NFTTBHF.
Key #13: THIS IS MY SECRET MESSAGE.
Key #14: SGHR HR LX RDBQDS LDRRZFD.
Key #15: RFGQ GQ KW QCAPCR KCQQYEC.
Key #16: QEFP FP JV PBZOBQ JBPPXDB.
Key #17: PDEO EO IU OAYNAP IAOOWCA.
Key #18: OCDN DN HT NZXMZO HZNNVBZ.
Key #19: NBCM CM GS MYWLYN GYMMUAY.
Key #20: MABL BL FR LXVKXM FXLLTZX.
Key #21: LZAK AK EQ KWUJWL EWKKSYW.
Key #22: KYZJ ZJ DP JVTIVK DVJJRXV.
Key #23: JXYI YI CO IUSHUJ CUIIQWU.
Key #24: IWXH XH BN HTRGTI BTHHPVT.
Key #25: HVWG WG AM GSQFSH ASGGOUS.
可以看出密钥13输出的是普通的英文
第8章 使用换位加密法加密
- 步骤:
- 数一下消息里的字符个数
- 画一行个数等于密钥的格子
- 从左到右开始填充格子,每个格子填一个字符
- 当你用完格子还有字符剩下时,再加一行格子
- 把最后一行剩下不用的格子涂成灰色
- 从最上角开始往下写出字符。当你到达这一行的底部后,移到右边那一列。跳过任何灰色的格子。这就是密文
# Transposition Cipher Encryption
# http://inventwithpython.com/hacking (BSD Licensed)
import pyperclip
def main():
myMessage = 'Common sense is not so common.'
myKey = 8
ciphertext = encryptMessage(myKey, myMessage)
# Print the encrypted string in ciphertext to the screen, with
# a | (called "pipe" character) after it in case there are spaces at
# the end of the encrypted message.
print(ciphertext + '|')
# Copy the encrypted string in ciphertext to the clipboard.
pyperclip.copy(ciphertext)
def encryptMessage(key, message):
# Each string in ciphertext represents a column in the grid.
ciphertext = [''] * key
# Loop through each column in ciphertext.
for col in range(key):
pointer = col
# Keep looping until pointer goes past the length of the message.
while pointer < len(message):
# Place the character at pointer in message at the end of the
# current column in the ciphertext list.
ciphertext[col] += message[pointer]
# move pointer over
pointer += key
# Convert the ciphertext list into a single string value and return it.
return ''.join(ciphertext)
# If transpositionEncrypt.py is run (instead of imported as a module) call
# the main() function.
if __name__ == '__main__':
main()
第9章 使用换位加密解密
# Transposition Cipher Decryption
# http://inventwithpython.com/hacking (BSD Licensed)
import math, pyperclip
def main():
myMessage = 'Cenoonommstmme oo snnio. s s c'
myKey = 8
plaintext = decryptMessage(myKey, myMessage)
# Print with a | (called "pipe" character) after it in case
# there are spaces at the end of the decrypted message.
print(plaintext + '|')
pyperclip.copy(plaintext)
def decryptMessage(key, message):
# The transposition decrypt function will simulate the "columns" and
# "rows" of the grid that the plaintext is written on by using a list
# of strings. First, we need to calculate a few values.
# The number of "columns" in our transposition grid:
numOfColumns = math.ceil(len(message) / key)
# The number of "rows" in our grid will need:
numOfRows = key
# The number of "shaded boxes" in the last "column" of the grid:
numOfShadedBoxes = (numOfColumns * numOfRows) - len(message)
# Each string in plaintext represents a column in the grid.
plaintext = [''] * numOfColumns
# The col and row variables point to where in the grid the next
# character in the encrypted message will go.
col = 0
row = 0
for symbol in message:
plaintext[col] += symbol
col += 1 # point to next column
# If there are no more columns OR we're at a shaded box, go back to
# the first column and the next row.
if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes):
col = 0
row += 1
return ''.join(plaintext)
# If transpositionDecrypt.py is run (instead of imported as a module) call
# the main() function.
if __name__ == '__main__':
main()
第11章 加密与解密文件
# Transposition Cipher Encrypt/Decrypt File
# http://inventwithpython.com/hacking (BSD Licensed)
import time, os, sys, transpositionEncrypt, transpositionDecrypt
def main():
inputFilename = 'frankenstein.txt'
# BE CAREFUL! If a file with the outputFilename name already exists,
# this program will overwrite that file.
outputFilename = 'frankenstein.encrypted.txt'
myKey = 10
myMode = 'encrypt' # set to 'encrypt' or 'decrypt'
# If the input file does not exist, then the program terminates early.
if not os.path.exists(inputFilename):
print('The file %s does not exist. Quitting...' % (inputFilename))
sys.exit()
# If the output file already exists, give the user a chance to quit.
if os.path.exists(outputFilename):
print('This will overwrite the file %s. (C)ontinue or (Q)uit?' % (outputFilename))
response = input('> ')
if not response.lower().startswith('c'):
sys.exit()
# Read in the message from the input file
fileObj = open(inputFilename)
content = fileObj.read()
fileObj.close()
print('%sing...' % (myMode.title()))
# Measure how long the encryption/decryption takes.
startTime = time.time()
if myMode == 'encrypt':
translated = transpositionEncrypt.encryptMessage(myKey, content)
elif myMode == 'decrypt':
translated = transpositionDecrypt.decryptMessage(myKey, content)
totalTime = round(time.time() - startTime, 2)
print('%sion time: %s seconds' % (myMode.title(), totalTime))
# Write out the translated message to the output file.
outputFileObj = open(outputFilename, 'w')
outputFileObj.write(translated)
outputFileObj.close()
print('Done %sing %s (%s characters).' % (myMode, inputFilename, len(content)))
print('%sed file is %s.' % (myMode.title(), outputFilename))
# If transpositionCipherFile.py is run (instead of imported as a module)
# call the main() function.
if __name__ == '__main__':
main()
第12章 通过编程检测英文
- 由于解密后产生的结果可能有成千上万种,如果单靠人眼来判断结果是不是英文,显然这是一个很大的问题。
- 英文是由可以在字典中找到的单词组成的,而乱码则不然。
字典文件:包含了几乎所有的英语单词
因此,我们只要写一个函数检查字符串里这些单词是否大部分存在于字典文件中就可以判断是否为英文。
# Detect English module
# http://inventwithpython.com/hacking (BSD Licensed)
# To use, type this code:
# import detectEnglish
# detectEnglish.isEnglish(someString) # returns True or False
# (There must be a "dictionary.txt" file in this directory with all English
# words in it, one word per line. You can download this from
# http://invpy.com/dictionary.txt)
UPPERLETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
LETTERS_AND_SPACE = UPPERLETTERS + UPPERLETTERS.lower() + ' \t\n'
def loadDictionary():
"""
加载英文字典,该字典中所有单词都转为大写,每行一个单词
"""
dictionaryFile = open('dictionary.txt')
englishWords = {}
for word in dictionaryFile.read().split('\n'):
englishWords[word] = None
dictionaryFile.close()
return englishWords
ENGLISH_WORDS = loadDictionary()
def getEnglishCount(message):
"""
获取要判断是否为英文的消息,分别判断消息中的单词是否在字典中,最后判断该消息中,单词的比例
"""
message = message.upper()
message = removeNonLetters(message)
possibleWords = message.split()
if possibleWords == []:
return 0.0 # no words at all, so return 0.0
matches = 0
for word in possibleWords:
if word in ENGLISH_WORDS:
matches += 1
return float(matches) / len(possibleWords)
def removeNonLetters(message):
"""
去除空格,制表符,换行符
"""
lettersOnly = []
for symbol in message:
if symbol in LETTERS_AND_SPACE:
lettersOnly.append(symbol)
return ''.join(lettersOnly)
def isEnglish(message, wordPercentage=20, letterPercentage=85):
"""
如果一个字符串中有20%的单词是字典文件中的英文单词,并且有80%的字符是字母(或空格),我们的isEnglish()函数就会认为这个字符串是英文
"""
# By default, 20% of the words must exist in the dictionary file, and
# 80% of all the characters in the message must be letters or spaces
# (not punctuation or numbers).
wordsMatch = getEnglishCount(message) * 100 >= wordPercentage
numLetters = len(removeNonLetters(message))
messageLettersPercentage = float(numLetters) / len(message) * 100
lettersMatch = messageLettersPercentage >= letterPercentage
return wordsMatch and lettersMatch
第13章 破译换位加密法
- detectEnglish.py程序免除了判断解密之后的输出是否为英文的大量工作。这让暴力破译技术可以用于成千上万个加密法
# Transposition Cipher Hacker
# http://inventwithpython.com/hacking (BSD Licensed)
import pyperclip, detectEnglish, transpositionDecrypt
def main():
# You might want to copy & paste this text from the source code at
# http://invpy.com/transpositionHacker.py
myMessage = """Cb b rssti aieih rooaopbrtnsceee er es no npfgcwu plri ch nitaalr eiuengiteehb(e1 hilincegeoamn fubehgtarndcstudmd nM eu eacBoltaeteeoinebcdkyremdteghn.aa2r81a condari fmps" tad l t oisn sit u1rnd stara nvhn fsedbh ee,n e necrg6 8nmisv l nc muiftegiitm tutmg cm shSs9fcie ebintcaets h aihda cctrhe ele 1O7 aaoem waoaatdahretnhechaopnooeapece9etfncdbgsoeb uuteitgna.rteoh add e,D7c1Etnpneehtn beete" evecoal lsfmcrl iu1cifgo ai. sl1rchdnheev sh meBd ies e9t)nh,htcnoecplrrh ,ide hmtlme. pheaLem,toeinfgn t e9yce da' eN eMp a ffn Fc1o ge eohg dere.eec s nfap yox hla yon. lnrnsreaBoa t,e eitsw il ulpbdofgBRe bwlmprraio po droB wtinue r Pieno nc ayieeto'lulcih sfnc ownaSserbereiaSm-eaiah, nnrttgcC maciiritvledastinideI nn rms iehn tsigaBmuoetcetias rn"""
hackedMessage = hackTransposition(myMessage)
if hackedMessage == None:
print('Failed to hack encryption.')
else:
print('Copying hacked message to clipboard:')
print(hackedMessage)
pyperclip.copy(hackedMessage)
def hackTransposition(message):
print('Hacking...')
# Python programs can be stopped at any time by pressing Ctrl-C (on
# Windows) or Ctrl-D (on Mac and Linux)
print('(Press Ctrl-C or Ctrl-D to quit at any time.)')
# brute-force by looping through every possible key
for key in range(1, len(message)):
print('Trying key #%s...' % (key))
decryptedText = transpositionDecrypt.decryptMessage(key, message)
if detectEnglish.isEnglish(decryptedText):
# Check with user to see if the decrypted key has been found.
print()
print('Possible encryption hack:')
print('Key %s: %s' % (key, decryptedText[:100]))
print()
print('Enter D for done, or just press Enter to continue hacking:')
response = input('> ')
if response.strip().upper().startswith('D'):
return decryptedText
return None
if __name__ == '__main__':
main()