1. 程式人生 > >使用Python進行AES加密解密功能實現

使用Python進行AES加密解密功能實現

PyCrypto是一款非常實用的Python加密模組,最近寫了一個檔案加密指令碼需要用到AES加密,和大家分析一下心得。

下載與安裝:PyCrypto專案已經於2015年7月停止了,下面是官方的下載地址。 https://www.dlitz.net/software/pycrypto/
如果是linux系統,PyCrypto的安裝非常簡單,解壓直接安裝即可:
python setup.py build
python setup.py install

但是在windows下就非常麻煩了,網上常見的方法都是需要MinGW或者VisualStudio。不過你也可以在下面的連線中獲取windows適用的pycrypto安裝包。
http://www.voidspace.org.uk/python/modules.shtml#pycrypto
 
OK,接下來是正題。
首先介紹一下專案背景,我的電腦裡有一個檔案,名叫PW.txt,這個檔案裡儲存的都是我在各類網站論壇的賬號密碼,雖然方便,但是!這種明文儲存的方式讓我很沒有安全感。恰逢最近在學Python,於是就寫了一個用AES方式對檔案加密的小指令碼。這裡先和大家大家分享一下使用PyCrypto實現對字串的加密與解密。

1.預處理
AES有三種金鑰長度16(*AES-128*), 24 (*AES-192*), 和 32 (*AES-256*),在對字元進行加密時,密碼和明文長度必須為16,24,或32。
因此要對密碼和明文進行預處理,確保密碼長度為16,24或32,明文長度為16,24或32的整數倍,這裡以16(*AES-128*)為例,程式碼如下:

# 補全字元

def align(str, isKey=False):    

# 如果接受的字串是密碼,需要確保其長度為16    

     if isKey:        

          if len(str) > 16:            

               return str[0:16]        

          else:            

               return align(str)  

 # 如果接受的字串是明文或長度不足的密碼,則確保其長度為16的整數倍    

else:        

     zerocount = 16-len(str) % 16        

     for i in range(0, zerocount):            

           str = str + '\0'        

     return str

2.加密

要呼叫PyCrypto的AES加密模組,首先匯入AES的包,另外為了確保編碼的統一,我選擇將密文儲存為16進位制,因此還需要從binascii中匯入b2a_hex和a2b_hex。

from Crypto.Cipher import AES

from binascii import b2a_hex

from binascii import a2b_hex

這裡加密函式的流程是:預處理密碼和明文->初始化AES->加密->轉碼->輸出結果,程式碼如下:

# ECB模式加密

def encrypt_ECB(str, key):    

    # 補全字串    

    str = align(str)    

    key = align(key, True)    

    # 初始化AES    

    AESCipher = AES.new(key, AES.MODE_ECB)    

    # 加密    

    cipher = AESCipher.encrypt(str)    

    return b2a_hex(cipher)

這裡使用的是ECB的加密模式,關於加密模式,AES共有五種加密模式(ECB,CBC,PCBC,CFB,OFB,CTR),感興趣的同學可以自行查閱相關資料。

3.解密
這裡解密的流程是:預處理密碼->初始化AES->轉碼->解密->輸出結果,程式碼如下:

<code class="language-python"># ECB模式解密  

def decrypt_ECB(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_ECB)      

    # 解密      

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0        、

    paint = paint.rstrip('\0')        

    return paint</code>  

4.AES加密模式——CBC

上面的示例程式碼使用的是ECB模式進行加密解密,這種模式比較簡單,並且安全性相對較差,關於這一點,wiki上有張圖我覺得十分形象。

(https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_.28IV.29)

大部分場景下,我們會使用CBC模式來進行AES加密,和ECB相比,CBC引入了初始向量IV(Initialization vector),每一次加密都使用隨機產生的初始向量可以大大提高密文的安全性(這裡的示例程式碼使用固定的IV),程式碼如下。

<code class="language-python"></code>

 

<code class="language-python"># CFB模式加密  

def encrypt_CFB(str, key):    

     # 補全字串,雖然明文長度沒有限制,但是密碼仍然需要16位     

     key = align(key, True)    

     # 初始化AES      

     AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')    

     # 加密      

     cipher = AESCipher.encrypt(str)      

     return b2a_hex(cipher)      

# CFB模式解密  

def decrypt_CFB(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')    

    # 解密       

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0      

    paint = paint.rstrip('\0')      

    return paint</code>  


5. AES加密模式——CFB

除了CBC模式,這裡再介紹一種加密模式——CFB模式,這個模式下明文長度可以不為16的整數倍,程式碼如下:

# CFB模式加密

def encrypt_CFB(str, key):    

    # 補全字串,雖然明文長度沒有限制,但是密碼仍然需要16位    

    key = align(key, True)    

    # 初始化AES    

    AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')    

    # 加密    

    cipher = AESCipher.encrypt(str)    

    return b2a_hex(cipher)  

# CFB模式解密

def decrypt_CFB(str, key):    

    # 補全字串    

    key = align(key, True)    

    # 初始化AES    

    AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')    

    # 解密    

    paint = AESCipher.decrypt(a2b_hex(str))    

    # 去除/0    

    paint = paint.rstrip('\0')    

    return paint6.

完整的例項程式碼如下
<code class="language-python">

# -*- coding: UTF-8 -*-      

from Crypto.Cipher import AES  

from binascii import b2a_hex  

from binascii import a2b_hex          

# 補全字元  

def align(str, isKey=False):      

# 如果是密碼,需要確保其長度為16      

    if isKey:          

        if len(str) > 16:              

             return str[0:16]          

        else:              

             return align(str)      

# 如果是被加密字串或長度不足的密碼,則確保其長度為16的整數倍      

else:          

    zerocount = 16-len(str) % 16          

    for i in range(0, zerocount):              

        str = str + '\0'          

    return str          

 

# ECB模式加密  

def encrypt_ECB(str, key):      

    # 補全字串      

    str = align(str)      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_ECB)      

    # 加密      

    cipher = AESCipher.encrypt(str)      

    return b2a_hex(cipher)          

# ECB模式解密  

def decrypt_ECB(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES     

    AESCipher = AES.new(key, AES.MODE_ECB)      

    # 解密      

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0      

    paint = paint.rstrip('\0')      

    return paint          

# CBC模式加密  

def encrypt_CBC(str, key):      

    # 補全字串      

    str = align(str)      

    key = align(key, True)      

    # 初始化AES,引入初始向量      

    AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')      

    # 加密      

    cipher = AESCipher.encrypt(str)      

    return b2a_hex(cipher)          

 

# CBC模式解密  

def decrypt_CBC(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')      

    # 解密      

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0      

    paint = paint.rstrip('\0')      

    return paint        

 

# CFB模式加密  

def encrypt_CFB(str, key):      

    # 補全字串,雖然明文長度沒有限制,但是密碼仍然需要16位      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')      

    # 加密      

    cipher = AESCipher.encrypt(str)      

    return b2a_hex(cipher)          

# CFB模式解密  

def decrypt_CFB(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_CFB, '1234567890123456')      

    # 解密      

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0      

    paint = paint.rstrip('\0')      

    return paint          

# OFB模式加密  

def encrypt_OFB(str, key):      

    # 補全字串      

    str = align(str)      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_OFB, '1234567890123456')      

    # 加密      

    cipher = AESCipher.encrypt(str)      

    return b2a_hex(cipher)         

# OFB模式解密  

def decrypt_OFB(str, key):      

    # 補全字串      

    key = align(key, True)      

    # 初始化AES      

    AESCipher = AES.new(key, AES.MODE_OFB, '1234567890123456')      

    # 解密      

    paint = AESCipher.decrypt(a2b_hex(str))      

    # 去除/0      

    paint = paint.rstrip('\0')      

    return paint  

   

    # 先設定一段明文和密碼  

Text = 'Suprise!!****** *****r!'  

key = 'mor'    

 

 # ECB模式加密  

ciphertext = encrypt_ECB(Text, key)  

print ("ECB模式密文:" + ciphertext)  

 

# ECB模式解密  

plaintext = decrypt_ECB(ciphertext, key)  

print ("ECB模式明文:" + plaintext)    

 

 # CBC模式加密  

ciphertext = encrypt_CBC(Text, key)  

print ("CBC模式密文:" + ciphertext)  

 

# CBC模式解密  

plaintext = decrypt_CBC(ciphertext, key)  

print ("CBC模式明文:" + plaintext)      

# CFB模式加密  

ciphertext = encrypt_CFB(Text, key)  

print ("CFB模式密文:" + ciphertext)  

 

# CFB模式解密  

plaintext = decrypt_CFB(ciphertext, key)  

print ("CFB模式明文:" + plaintext)      

 

# OFB模式加密  

ciphertext = encrypt_OFB(Text, key)  

print ("OFB模式密文:" + ciphertext)  

 

# OFB模式解密  

plaintext = decrypt_OFB(ciphertext, key)  

print ("OFB模式明文:" + plaintext)</code>