python-密码学编程

Python标准库hashlib实现了SHA1、SHA224、SHA256、SHA384、SHA512以及MD5等多个安全哈希算法。

标准库zlib提供了adler32和crc32算法的实现。

标准库hmac实现了HMAC算法。

在众多的Python扩展库中,pycrypto可以说是密码学编程模块中最成功也是最成熟的一个,具有很高的市场占有率。另外,cryptography也有一定数量的用户在使用。扩展库pycrypto和cryptography提供了SHA系列算法和RIPEMD160等多个安全哈希算法,以及DES、AES、RSA、DSA、EIGamal等多个加密算法和数字签名算法的实现。

1.经典密码算法(古典密码)

很多经典密码算法的安全性很低,甚至很容易被词频分析这样的简易攻击手段破解,因此已经很少再使用。尽管如此,经典密码算法的一些思想还是很有借鉴意义和参考价值的。

(1)凯撒密码

def KaiSaEncrypt(ch, k):
    if (not isinstance(ch, str)) or len(ch)!=1:
        print('The first parameter must be a character')
        return
    if (not isinstance(k, int)) or (not 1<=k<=25):
        print('The second parameter must be an integer between 1 and 25')
        return
    #把英文字母变换为后面第k个字母
    if 'a'<=ch<=chr(ord('z')-k):
        return chr(ord(ch)+k)
    #把英文字母首尾相连
    elif chr(ord('z')-k)<ch<='z':
        return chr((ord(ch)-ord('a')+k)%26+ord('a'))
    elif 'A'<=ch<=chr(ord('Z')-k):
        return chr(ord(ch)+k)
    elif chr(ord('Z')-k)<ch<='Z':
        return chr((ord(ch)-ord('A')+k)%26+ord('A'))
    else:
        return ch

def encrypt(plain, k):
    return ''.join([KaiSaEncrypt(ch, k) for ch in plain])

def KaiSaDecrypt(ch, k):
    if (not isinstance(ch, str)) or len(ch)!=1:
        print('The first parameter must be a character')
        return
    if (not isinstance(k, int)) or (not 1<=k<=25):
        print('The second parameter must be an integer between 1 and 25')
        return
    #把英文字母首尾相连,然后把每个字母变换为前面第k个字母
    if chr(ord('a')+k)<=ch<='z':
        return chr(ord(ch)-k)
    elif 'a'<=ch<chr(ord('a')+k):
        return chr((ord(ch)-k+26))
    elif chr(ord('A')+k)<=ch<='Z':
        return chr(ord(ch)-k)
    elif 'A'<=ch<chr(ord('A')+k):
        return chr((ord(ch)-k+26))
    else:
        return ch

def decrypt(plain, k):
    return ''.join([KaiSaDecrypt(ch, k) for ch in plain])

plainText = 'Explicit is better than implicit.'
cipherText = encrypt(plainText, 5)
print(plainText)
print(cipherText)
print(decrypt(cipherText,5))

输出

github python 密码学 python密码学编程第二版_算法


(2)维吉尼亚密码

from string import ascii_uppercase as uppercase
from itertools import cycle

#创建密码表
table = dict()
for ch in uppercase:
    index = uppercase.index(ch)
    table[ch] = uppercase[index:]+uppercase[:index]

#创建解密密码表
deTable = {'A':'A'}
start = 'Z'
for ch in uppercase[1:]:
    index = uppercase.index(ch)
    deTable[ch] = chr(ord(start)+1-index)

#解密密钥
def deKey(key):
    return ''.join([deTable[i] for i in key])

#加密/解密
def encrypt(plainText, key):
    result = []
    #创建cycle对象,支持密钥字母的循环使用
    currentKey = cycle(key)
    for ch in plainText:
        if 'A'<=ch<='Z':
            index = uppercase.index(ch)
            #获取密钥字母
            ck = next(currentKey)
            result.append(table[ck][index])
        else:
            result.append(ch)
    return ''.join(result)

key = 'TAYLOR'
p = 'I WILL SPEND FOREVER WONDERING IF YOU KNEW I WAS ENCHANGTED TO MEET YOU'
c = encrypt(p, key)
print(p)
print(c)
print(encrypt(c,deKey(key)))

输出

github python 密码学 python密码学编程第二版_加密解密_02


(3)换位密码

def encrypt(plainText, t):
    result = []
    length = len(t)
    #把明文分组
    temp = [plainText[i:i+length] for i in range(0,len(plainText),length)]
    #对除最后一组之外的其他进行换位处理
    for item in temp[:-1]:
        newItem = ''
        for i in t:
            newItem = newItem+item[i-1]
        result.append(newItem)
    return ''.join(result)+temp[-1]
p = 'Errors should never pass silently.'
#加密
c = encrypt(p, (1, 4, 3, 2))
print(c)
#解密
print(encrypt(c, (1, 4, 3, 2)))

输出

github python 密码学 python密码学编程第二版_github python 密码学_03

2.安全哈希算法

安全哈希算法也称报文摘要算法,对任意长度的消息可以计算得到固定长度的唯一指纹。
理论上,即使是内容非常相似的消息也不会得到完全相同的指纹。安全哈希算法是不可逆的,无法从指纹还原得到原始消息,属于单向变换算法。
安全哈希算法常用于数字签名领域,可以验证信息是否被篡改,很多管理信息系统把用户密码的哈希值存储到数据库中而不是直接存储密码明文,大幅度提高了系统的安全性。另外,文件完整性检查也经常用到MD5或其他安全哈希算法,用来验证文件发布之后是否被非法修改。

github python 密码学 python密码学编程第二版_github python 密码学_04

3.对称密钥算法DES和AES

(1)DES

from Crypto.Cipher import DES
des_encrypt_decrypt = DES.new('ShanDong', DES.MODE_ECB)
p = 'Beautiful is better than ugly.'
pp = p.encode()
c = des_encrypt_decrypt.encrypt(pp.ljust((len(pp)//8+1)*8, b'0'))  #按8字节对齐
print(c)                                                                  #加密结果
cp = des_encrypt_decrypt.decrypt(c)                                #解密
print(cp)
print(cp[0:len(pp)].decode())

输出

github python 密码学 python密码学编程第二版_加密解密_05

(2)AES

import string
import random
from Crypto.Cipher import AES

#生成指定长度的密钥
def keyGenerater(length):
    if length not in (16, 24, 32):
        return None
    x = string.ascii_letters+string.digits
    return ''.join([random.choice(x) for i in range(length)])

def encryptor_decryptor(key, mode):
    return AES.new(key, mode, b'0000000000000000')

#使用指定密钥和模式对给定信息进行加密
def AESencrypt(key, mode, text):
    encryptor = encryptor_decryptor(key, mode)
    return encryptor.encrypt(text)

#使用指定密钥和模式对给定信息进行解密
def AESdecrypt(key, mode, text):
    decryptor = encryptor_decryptor(key, mode)
    return decryptor.decrypt(text)

if __name__ == '__main__':
    text = '山东省烟台市 Python3.5 is excellent.'
    key = keyGenerater(16)
    #随机选择AES的模式
    mode = random.choice((AES.MODE_CBC, AES.MODE_CFB, AES.MODE_ECB,
                        AES.MODE_OFB))
    if not key:
        print('Something is wrong.')
    else:
        print('key:', key)
        print('mode:', mode)
        print('Before encryption:', text)
        #明文必须以字节串形式,且长度为16的倍数
        text_encoded = text.encode()
        text_length = len(text_encoded)
        padding_length = 16 - text_length%16
        text_encoded = text_encoded + b'0'*padding_length
        text_encrypted = AESencrypt(key, mode, text_encoded)
        print('After encryption:', text_encrypted)
        text_decrypted =AESdecrypt(key, mode, text_encrypted)
        print('After decryption:', text_decrypted.decode()[:-padding_length])

输出

github python 密码学 python密码学编程第二版_算法_06

4.非对称密钥密码算法RSA与数字签名算法DSA

(1)RSA

import rsa
key=rsa.newkeys(3000)       #随机生成密钥
private=key[1]              #查看私钥分量,输出结果略
print(private.d, '\n',private.e, '\n',private.n,'\n', private.p,'\n', private.q)

github python 密码学 python密码学编程第二版_github python 密码学_07

import rsa

key = rsa.newkeys(3000)        #生成随机密钥
privateKey = key[1]            #私钥
publicKey = key[0]             #公钥

message = '中国山东烟台.Now is better than never.'
print('Before encrypted:',message)
message = message.encode()

cryptedMessage = rsa.encrypt(message, publicKey)
print('After encrypted:\n',cryptedMessage)

message = rsa.decrypt(cryptedMessage, privateKey)
message = message.decode()
print('After decrypted:',message)

github python 密码学 python密码学编程第二版_python_08


(2)DSA

DSA是基于公钥机制的数字签名算法,其安全性基于离散对数问题DLP。即,给定一个循环群中的元素g和h,很难找到一个整数x使得gx=h。

from Crypto.Random import random
from Crypto.PublicKey import DSA
from Crypto.Hash import MD5
message = 'Simple is better than complex.'
key = DSA.generate(1024)                 #生成密钥
h = MD5.new(message.encode()).digest()   #计算消息的哈希值
k = random.StrongRandom().randint(1, key.key.q-1)
sig = key.sign(h, k)
print(key.verify(h, sig))

h1 = MD5.new(message.encode()+b'3').digest()
print(key.verify(h1, sig))

输出

github python 密码学 python密码学编程第二版_加密解密_09