加解密數據、操作密鑰、操作SSL協議普遍使用了OpenSSL。雖然還有其它的使用C/C++開發的加密處理庫,但是Python環境下支持最好的使用最廣泛的還是OpenSSL。
據python.org官方網站,目前有幾個庫提供了加密功能。
PyOpenSSL。這個庫是比較早的,但是作者已經停止開發,並且只支持SSL功能,而沒有提供加密、解密、X509等功能的包裝,最好不要繼續使用這個庫了。
M2Crypto。完整支持OpenSSL。單元測試比較全面。在原有C語言API的基礎上提供了Python的封裝。
ssl4py。與M2Crypto類似。但是完全使用C編寫,與OpenSSL的API很類似。估計是用SWIG之類的工具生成的。據我本人看他的源代碼,在調用EVP_CipherUpdate()函數的時候,輸出大小沒有計算正確。此錯誤會造成數據不正確,是一個比較嚴重的BUG。我估計應該還有其它的BUG存在,可能比較不成熟。有使用過的來說一下吧。
ezPyCrypto。全名是Python Cryptography Toolkit。據水木網友josephpei說,這個很強大,有望進入官方CPython的標准庫內。不使用OpenSSL的API。
PyCrypto。這個庫目前使用也相當廣泛。不使用OpenSSL的API
考慮到OpenSSL使用很廣泛。我決定在開發中使用M2Crypto。
M2Crypto的API手冊處於:http://www.heikkitoivonen.net/m2crypto/api/
目前,截止到2009年10月23日,官網上提供的M2Crypto for Python 2.6(win32)安裝包是不正確的。因為它提供的0.19版本並沒有兼容0.20。所以需要下載M2Crypto的源代碼自行編譯。以下是編譯的步驟:
下載安裝mingw32:http://www.mingw.org.
下載安裝 swig: http://www.swig.org。選擇下載SWIG for python(win32)的版本。並且把swig的路徑加入$PATH環境變量內。
下載安裝OpenSSL的Windows版本:http://www.slproweb.com/products/Win32OpenSSL.html
把OpenSSL的include文件夾復制到Python的include文件夾內。把OpenSSL的幾個庫文件(*.a)復制到mingw32的lib文件夾內。
OpenSSL for windows的庫文件與for Unix版本名字有些不大一樣。需要把libeay32.dll.a改名liblibeay32.a,把libssl32.dll.a改名libssleay32.a。測試的版本是0.9.8h
運行setup.py build -c mingw32 bdist_wininst
一切順利的話在dist文件夾下可以找到安裝程序。
(附記)M2Crypto主頁提供了一處描述如何在windows平台下使用msvc編譯openssl和M2Crypto的鏈接。經過試驗,該方法不能在mingw32下成功。不過在一個用戶評論上描述了mingw32下的方法,當時沒仔細看,害我搞了半天沒成功。(再附記)截止2012年1月1日止,在M2Crypto提供了最新版本的Windows安裝程序。所以自己編譯通常是沒必要的了。
經過我測試,編譯后的M2Crypto雖然導入正常,但是一旦使用BIO進行文件操作,M2Crypto就會異常退出。並打印出No AppLink這樣的錯誤信息。如果不使用BIO的話,好像又沒啥問題。
安裝程序缺少openssl的幾個動態鏈接庫,如果要發布這些個安裝程序,應該把將OpenSSL的動態鏈接庫一起打包進去。
下面是幾個模塊的大致介紹:
M2Crypto.BIO 用於操作IO抽象類型。
M2Crypto.BN 用於操作大數
M2Crypto.DH 用於操作Diffie-Hellman key exchange protocol
M2Crypto.EVP 高級的加密解密接口。與直接使用具體的加密算法不同。使用該接口,可以用相同的編程方式,調用不同的算法處理數據。它包含了對稱加密算法與非對稱加密算法的支持。
M2Crypto.EC 橢圓曲線非對稱加密算法
M2Crypto.DSA DSA非對稱加密算法
M2Crypto.RSA RSA非對稱加密算法
M2Crypto.Rand 操作隨機數
M2Crypto.SSL 操作SSL協議
M2Crypto.X509 操作X509
接下來,我們通過日常的編程任務來看看如何使用這些接口。
如何使用MD5、SHA1等消息散列算法。
雖然OpenSSL提供了直接操作MD5、SHA1算法以及blowfish等各種對稱加密算法的API,但是M2Crypto並沒有將其包含進來。不過也好,各種算法都有各自的API,記起來麻煩。通過M2Crypto.EVP,我們仍然可以調用這些算法。下面是一個MD5的例子:
def md5(s):
#在構造函數中傳入算法的名字可以選擇不同的消息散列算法
m=EVP.MessageDigest("md5")
m.update(s)
return m.digest() #或者m.final()
常用的散列算法還有SHA1。使用方法與MD5類似,只是構造函數是:
m=EVP.MessageDigest("sha1")
使用對稱加密算法加密數據。
如前所述,我們需要使用EVP.Cipher這個比較抽象的API,而不是具體的算法。與EVP.MessageDigest()類似,EVP.Cipher主要提供四個函數:
EVP.Cipher.init(self, alg, key, iv, op, key_as_bytes=0,
d='md5', salt='12345678', i=1, padding=1)
EVP.Cipher.update(self, data)
EVP.Cipher.final()
EVP.Cipher.set_padding(self, padding=1)
下面是一段使用blowfish算法將明文"fish is here"加密成密文的函數代碼:
def blowfish_encrypt(s, password):
out=StringIO()
m=EVP.Cipher("bf_ecb", password, "123456", 1, 1, "sha1", "saltsalt", 5, 1)
out.write(m.update(s))
out.write(m.final())
return out.getvalue()
可以發現,最主要的是Cipher的構造函數:
EVP.Cipher.init(self, alg, key, iv, op, key_as_bytes=0,
d='md5', salt='12345678', i=1, padding=1)
alg是指算法的名字,OpenSSL支持以下算法:
des_cbc des_ecb des_cfb des_ofb
des_ede_cbc des_ede des_ede_ofb des_ede_cfb ------- 2DES算法
des_ede3_cbc des_ede3 des_ede3_ofb des_ede3_cfb ------- 3DES算法
desx_cbc
rc4
rc4_40 ------- 密鑰為40位的RC4算法
idea_cbc idea_ecb idea_cfb idea_ofb idea_cbc
rc4_cbc rc2_ecb rc2_cfb rc2_ofb
rc2_40_cbc rc2_64_cbc
bf_cbc bf_ecb bf_cfb bv_ofb ------- Blowfish算法
cast5_cbc cast5_ecb cast5_cfb cast5_ofb
rc5_32_12_16_cbc rc5_32_12_16_ecb rc5_32_12_16_cfb rc5_32_12_16_ofb
可以注意到各種算法的名字除了算法本身的名字外,還帶有各種后綴。比如blowfish有bf_cbc, bf_ecb多個名字。這些后綴是什么意思呢?在本文的最后附帶了我另一份學習筆記,其中有不完整的解釋。現在先來看看技術上如何使用這些算法吧。
key是加密所用的密鑰。傳入的是一段二進制數據,其長度是密鑰的長度。不過,如果后面的參數key_as_bytes1,那key是一個普通的任意長度的字符串,將與salt, i參數一起生成一個真正的密鑰。比如說,假設算法alg的密鑰長度是16,如果key_as_bytes0,那么key應該傳入"\xff\xff"兩個字節的字符串。如果key_as_bytes==1,則可以傳入類似於123456這樣子的字符串。
iv是指初始向量。與加密算法所使用的加密塊的長度一致。有些加密算法並不使用iv這個變量。如果key_as_bytes==1。雖然OpenSSL的key_to_bytes()函數可以使用alt, key ,salt ,d, i四個參數生成真正的密鑰和iv。但是M2Crypto內部並沒有這樣子做。而是直接使用原來的iv.如果iv的長度超過了加密算法所使用的加密塊的長度,超過的長度會被截取。
op用於指示解密或者加密操作。op1表示加密操作;op0表示解密操作。在做逆操作的時候,除了op不一樣,其它參數應當保持一致。
key_as_bytes參數如前所述。如果key_as_bytes1。M2Crypto會使用alg, key, d, salt, i五個參數生成真正的密鑰(注意,沒有使用IV)。如果key_as_bytes0,表示傳入的是真正的密鑰,d, salt, i三個參數就沒有意義了。
d是指生成密鑰時所使用的散列算法。可以選擇md5, sha1等。最好使用sha1,因為md5的破解看來只是時間問題了。
salt是指生成密鑰時所使用的鹽。M2Crypto默認是123456。
i是指生成密鑰時所迭代的次數。迭代次數越多,使用暴力攻擊就越不容易。
padding是指填充加密塊。大多數加密算法是以塊為單位進行加密的。明文被切分為一個個固定大小的塊。然后分別進行加密,得到與原來大小一致的加密塊。但是明文的長度並不一定是加密塊長度的整數倍。因此在處理最后一個塊時需要進行填充。常用的填充算法是PKCS padding.如果沒有允許padding並且最后一段明文不足以達到加密塊的長度。EVP_EncryptFinal_ex()會返回一個錯誤。如果padding是允許的,但是密文最后並沒有包含一個正確的填充塊,EVP_DecryptoFinal()就會返回一個錯誤。padding默認是允許的。
生成RSA密鑰
DSA與RSA是比較常用的兩種非對稱加密算法。他們的使用方法與特性正如他們的名字,基本上大同小異。在OpenSSL內,使用與其它名字一樣的結構體來表示這兩個算法的密鑰。在M2Crypto里,也是如此。只是在M2Crypto里DSA與RSA是兩個類,帶有簽名、驗證等方法。
一般並不構造RSA與DSA類。而使用相應的工廠方法。比如生成RSA密鑰:
from M2Crypto import BIO, RSA
此函數生成一個1024位的RSA密鑰,將其轉化成PEM格式返回
def genrsa():
bio=BIO.MemoryBuffer()
rsa=RSA.gen_key(1024, 3, lambda *arg:None)
rsa.save_key_bio(bio, None)
return bio.read_all()
RSA.gen_key()是一個工廠方法,它返回一個存儲了新的RSA密鑰的RSA.RSA()實例。它的方法簽名是:gen_key(bits, e, callback=keygen_callback)
bits參數是指RSA密鑰的長度,1024以下的RSA密鑰雖然還沒有被破解,但是已經認為是不安全的了。作為CA使用的RSA密鑰通常要求達到2048位以上。e是RSA算法的"public exponent"。功能是什么?我也不大清楚,據OpenSSL的文檔說,這個函數通常是三個奇數3,17,65537之一。callback是一個回調函數。用於顯示生成密鑰的進度。具體請查閱OpenSSL的文檔。
這里是OpenSSL中對應的函數原型:
include <openssl/rsa.h>
RSA RSA_generate_key(int num,
unsigned long e,
void (callback)(int,int,void *),
void *cb_arg);
生成DSA密鑰
DSA算法相關的估計是另外一伙人開發的。API有些不大一樣。它首先需要生成參數,然后才能生成密鑰。以下是一段代碼:
from M2Crypto import BIO, DSA
此函數生成一個1024位的DSA密鑰,將其轉化成PEM格式返回
def gendsa():
bio=BIO.MemoryBuffer()
dsa = DSA.gen_params(1024, lambda *arg: None)
dsa.gen_key()
dsa.save_key_bio(bio,None)
return bio.read_all()
可以發現生成DSA密鑰時需要首先使用DSA.gen_params()生成DSA參數。gen_params()函數的第一個參數是DSA密鑰的長度,第二個密鑰與RSA.gen_key()的回調函數相同。DSA.gen_params()返回一個DSA類的實例。調用DSA.gen_key()方法生成密鑰。其它的與RSA類似。
載入DSA密鑰與RSA密鑰
RSA:
返回RSA類型:
load_key(file, callback=util.passphrase_callback)
load_key_bio(bio, callback=util.passphrase_callback)
load_key_string(string, callback=util.passphrase_callback)
返回RSA_pub類型:
load_pub_key(file)
load_pub_key_bio(bio)
DSA:
返回DSA類型:
load_params(file, callback=util.passphrase_callback)
load_params_bio(bio, callback=util.passphrase_callback)
load_key(file, callback=util.passphrase_callback)
load_key_bio(bio, callback=util.passphrase_callback)
返回DSA_pub類型:
load_pub_key(file, callback=util.passphrase_callback)
load_pub_key_bio(bio, callback=util.passphrase_callback)
這些函數大同小異。如果參數名字是file的話,代表的是一個文件名。如果參數名字是bio的話,代表的是一個BIO對像。BIO對象與Python的file對象類似都是用於表示一個可以讀寫的類似於文件的類型。BIO對象除了可以是一個普通的文件,還可以是一個ssh連接,還可以是一段內存(BIO.MemoryBuffer)。BIO.MemoryBuffer與Python的StringIO.StringIO類似。因為之前我們提到我編譯的M2Crypto在進行文件IO的時候會異常退出,所以最好只使用BIO.MemoryBuffer。
在本文里,提到密鑰,是同時指公鑰與私鑰。
在OpenSSL及大多數軟件里,因為公鑰會被單獨分發出去,所以公鑰可以單獨保存在公鑰文件里。而密鑰的所有者既然保存私鑰,肯定也會同時保存公鑰。故而私鑰並不會單獨保存到一個私鑰文件里,而是和公鑰一起保存在密鑰文件里。
RSA類型的操作——使用RSA加密、解密、簽名、認證;保存RSA密鑰
RSA類型封裝了一些可以使用RSA密鑰進行的操作。
首先,可以使用len(rsa)獲得RSA密鑰的長度。單位是位,通常使用1024位以上的密鑰才是安全的。
def public_encrypt(self, data, padding):
使用公鑰進行加密。data是數據,是一段普通的字符串。而padding參數是指填充加密塊的模式。它是一個枚舉類型。根據OpenSSL的文檔,padding有四個取值:no_padding,pkcs1_padding,sslv23_padding,pkcs1_oaep_padding。最好是只使用pkcs1_oaep_padding,因為它會在加密過程中插入一些隨機數,防止相同的明文產生相同的密文,缺點是密文肯定會比明文長很多。要注意的是,一次加密的明文不能太長,只能等於或者小於密鑰的長度。當paddingRSA.no_padding時因為沒有填充,所以要求len(data)len(rsa)//8,不能多不能少。對於pkcs1_oaep_padding,必須小於等於len(rsa)//8-42。如前所述,len(rsa)是密鑰的長度,單位是位,換算成字節要除8。
def public_decrypt(self, data, padding):
使用公鑰進行解密。
def private_encrypt(self, data, padding):
使用私鑰進行加密。
def private_decrypt(self, data, padding):
使用公鑰進行加密。
因為RSA是一種非對稱加密算法。所以用私鑰加密的數據,要用公鑰才能解密。反之,用公鑰加密的數據,要用私鑰才能解密。通常在通信中,發送方使用接收方的公鑰加密數據。_只有_接收方才有私鑰能夠解密數據。因為非對稱加密算法的速度一般比對稱加密算法慢,所以在一個連續的通信過程中,經常是發送方隨機生成一個對稱加密算法的密鑰,然后使用非對稱加密算法發送給接收方,以后所有的通信過程都是使用這個隨機密鑰。只要保證每隔一段時間就換一個密鑰,這個通信過程就跟直接使用非對稱加密算法一樣安全了。直接使用非對稱加密算法的情況很少見。
非對稱算法還經常用於對數據進行簽名。簽名可以保證發送方不能否認自己發送的數據是自己的。比如,在一個電子商務交易中,客戶下了一個訂單,不能等工廠已經生產完了才否認這個訂單是自己下的。簽名最簡單的辦法當然是使用發送方的私鑰進行加密。如果不使用發送方的公鑰就不能解密數據。反之,也可以說,凡是可以使用發送方的公鑰解密出數據,就說明數據是使用發送方的私鑰加密的。在現實生活中,人們一般是使用SHA1之類的散列算法算出數據的散列值,然后再用私鑰加密這個散列值。接收方接收到數據與散列值之后,同樣使用SHA1算法算出數據的散列值,與使用公鑰解密出來的散列值作對比。如果是一樣的,說明數據正確。如果不一樣,或者是在傳輸過程中被更改了,或者根本不是發送方所發送的。
RSA算法提供了兩種簽名的方式,其分別可能是不同的國際標准。我還不是很清楚。
第一組:
sign_rsassa_pss(self, digest, algo='sha1', salt_length=20)
verify_rsassa_pss(self, data, signature, algo='sha1', salt_length=20)
這組API與下面兩個函數類似。看起來差不多的樣子,不過我沒有進行過測試。實際上OpenSSL中並沒有sign_rsassa_pss()這樣函數。它實際上是分為兩個步驟:RSA_padding_add_PKCS1_PSS()和RSA_private_encrypt()。而verify_rsassa_pss()函數則分為RSA_public_decrypt()與RSA_verify_PKCS1_PSS()兩個步驟
第二組:
sign(self, digest, algo='sha1')
verify(self, data, signature, algo='sha1')
這組API對應於OpenSSL中的RSA_sign()與RSA_verify()函數。分別是簽名與驗證。雖然sign()方法接收散列算法的名字作為名字,但實際上digest參數應該是已經計算出的散列值。以下是對一段數據進行簽名的代碼:
發送方對數據進行簽名
from M2Crypto import *
m=EVP.EVP.MessageDigest("sha1") #先計算散列值
m.update("fish is here")
digest=m.final()
key_str=file("fish_private.pem", "rb").read() #讀入私鑰
key=RSA.load_key_string(key_str, util.no_passphrase_callback)
簽名后得到的數據。與原始數據一起發送出去。
result=key.sign(digest, "sha1")
:::python
接收方驗證數據
from M2Crypto import *
m=EVP.EVP.MessageDigest("sha1") #先計算散列值
m.update("fish is here")
digest=m.final() #先計算散列值
cert_str=file("fish_public.pem", "rb").read() #讀入公鑰
mb=BIO.MemoryBuffer(cert_str)
RSA模式沒有load_pub_key_string()方法,需自行使用MemoryBuffer
cert=RSA.load_pub_key_bio(mb)
cert.verify(digest, result, "sha1") #返回True/False
一個小型的CA,電子證書。
說到CA,不得不說到PKI認證體系。PKI體系是一個概念性的認證系統。它的基本原理是,通信系統內所有節點都承認一個權威的機構,稱為CA。所有參與通信的節點都有一個電子證書,由該節點的公鑰和身份認證信息組成。CA核查這個電子證書的身份信息是否正確。如果正確的話,就使用CA的秘鑰進行簽名。這樣,所有的通信節點就可以使用電子證書內包含的身份信息而不必親自核查了。
所有通信節點都持有CA的電子證書。CA的電子證書是CA自己簽名的。在PKI系統運行之前,人們會事先設置好CA證書。
通信節點生成電子證書的過程是:
通信節點生成RSA或者DSA等非對稱加密算法的密鑰。
通信節點生成電子證書請求文件(X509_Request)。其中包含通信節點的身份信息、公鑰,並且用通信節點的私鑰簽名。
CA讀取電子證書請求文件。核查身份信息是否正確。如果身份信息正確就生成通信節點的電子證書。其中包含CA的身份信息、通信節點的身份信息、通信節點的公鑰、電子證書的起始有效時間,電子證書的結束有效時間。通常還會記錄這是CA所頒發的第幾個證書。
生成非對稱加密算法的密鑰在之前已經有提到過了。接下來是如何生成證書請求文件的代碼:
from M2Crypto import *
首先載入密鑰文件。此文件同時保存了通信節點的私鑰與公鑰。
這里並不像之前直接使用
pkey_str=file("fish_private.pem", "rb").read()
pkey=EVP.load_key_string(pkey_str, util.no_passphrase_callback)
req=X509.Request()
req.set_pubkey(pkey) #包含公鑰
req.set_version(1)
身份信息不是簡單的字符串。而是X509_Name對象。
name=X509.X509_Name()
CN是Common Name的意思。如果是一個網站的電子證書,就要寫成網站的域名
name.CN="Goldfish"
Organization Unit,通常是指部門吧,組織內單元
name.OU="Dev Department"
Organization。通常是指公司
name.O="Besteam"
State or Province。州或者省
name.ST="Fujian"
Locale。
name.L="Quanzhou"
國家。不能直接寫國家名字,比如China之類的,而應該是國家代碼。
CN代表中國。US代表美國,JP代表日本
name.C="CN"
req.set_subject(name) #包含通信節點的身份信息
req.sign(pkey, "sha1") #使用通信節點的密鑰進行簽名
file("fish_req.pem", "wb").write(req.as_pem()) #寫入到文件
可以發現,如果簡化那些設置身份信息的代碼,實際上就是三步:包含公鑰、包含身份信息、簽名。
接下來,我們看看CA是如何給一個通信節點發放證書的。
from M2Crypto import *
import time
首先讀取證書請求文件。
req_str=file("fish_req.pem", "rb").read()
返回一個X509.Request類型代表證書請求文件
req=X509.load_request_string(req_str)
首先驗證一下,是不是真的是使用它本身的私鑰簽名的。
如果是,返回非0值。如果不是,說明這是一個非法的證書請求文件。
print req.verify(req.get_pubkey())
接下來載入CA的電子證書。與CA的密鑰不一樣,CA的電子證書包含了CA的身份信息。
CA的電子證書會分發給各個通信節點。
ca_str=file("ca.pem", "rb").read()
ca=X509.load_cert_string(ca_str)
可以使用check_ca()方法判斷這個證書文件是不是CA。
本質是判斷它是不是自簽名。如果是的話,就返回非0值。如果不是的話就返回0。
print ca.check_ca()
接下來載入CA的密鑰
cakey_str=file("cakey.pem", "rb").read()
一般CA的密鑰要加密保存。回調函數返回密碼
cakey=EVP.load_key_string(cakey_str, lambda *args:"1234")
接下來開始生成電子證書
cert=X509.X509()
首先,設定開始生效時間與結束生效時間
t = long(time.time()) + time.timezone #當前時間,單位是秒
開始生效時間。證書的時間類型不是普通的Python datetime類型。
now = ASN1.ASN1_UTCTIME()
now.set_time(t)
nowPlusYear = ASN1.ASN1_UTCTIME() #結束生效時間
nowPlusYear.set_time(t + 60 * 60 * 24 * 365) #一年以后。
cert.set_not_before(now)
cert.set_not_after(nowPlusYear)
把證書請求附帶的身份信息復制過來
cert.set_subject(req.get_subject())
設置頒發者的身份信息,把CA電子證書內身份信息復制過來
cert.set_issuer(ca.get_subject())
序列號是指,CA頒發的第幾個電子證書文件
cert.set_serial_number(2)
把證書請求內的公鑰復制過來
cert.set_pubkey(req.get_pubkey())
使用CA的秘鑰進行簽名。
cert.sign(cakey, "sha1")
file("fishcert2.pem", "wb").write(cert.as_pem())#保存文件。
補充:加密模式與初始向量,為什么對稱加密算法有各種后綴?
對稱加密算法除了要指明填充方式以外,在使用塊加密前還需要指定它所使用的模式。這個模式定義了Cipher如何應用加密算法。改變模式可以容許一個塊加密程序變為流加密程序。
分組密碼每次加密一個數據分組,這個分組的位數可以是隨意的,一般選擇64或者128位。另一方面,流加密程序每次可以加密或解密一個字節的數據,這就使它比流加密的應用程序更為有用。
ECB(Electronic Code Book:電碼本)
ECB是最簡單的模式,同樣的明文分組總是加密成相同的密文分組。這對於發送單一的塊數據來說是非常好的,如密鑰。但對執行一個加密的信息流來說不是很好,因為如果相同的明文多次發送以后,同樣的密文也會被多次發送。
ECB最大的弱點是對每一個塊用相同的方式進行加密。如果我們的密鑰或者數據不斷發生變化,ECB是完全安全的。但是如果類似的塊經過同樣的密鑰加密發出以后,攻擊者可能獲得一些我們並不想讓別人知道的信息。
CBC(Cipher Block Chaining:密碼分組鏈接)
CBC模式改變了加密方式,同樣的明文分組不一定加密或解密同樣的密文塊,因此解決了ECB存在的主要問題。CBC使用前一分組的信息加密當前分組。因此和ECB模式大不相同。這個方法依然存在問題,那就是相同的信息仍然加密成相同的密文,因為所有的分組是同時變成密文分組的。為了解決這個問題,我們引入一個Initialization Vector(初始化向量),也就是前不久有人問到的IV問題。IV僅僅是一個初始化加密程序的隨機數。它無需秘密保存,但隊每一個信息來說它都是不同的,通過這個方式,即使有兩條相同的信息,只要他們有不同的IV,那么他們加密后的密文也是不同的。從這個意義上來說,初始化向量無疑就和口令加密過程中使用的鹽值是一樣的。
CBC很適合文本傳輸,但它每一次都需要傳送一個完整的數據塊,一般選8個字符。
CFB(Cipher FeedBack:密碼反饋)
CFB的工作方式與CBC類似,但它可以執行更小的數據塊,典型的有8位,這非常適合加密像聊天對話這樣的信息,因為每次可以發送單一的字節數據塊。
和CBC一樣,CFB也需要一個IV,且相同及鑰發送的每條信息的IV都必須是唯一的。
OFB(Output FeedBack:輸出反饋)
OFB除了在傳輸中能給數據提供更好的保護,防止數據丟失外,其他和CFB類似。密文中一位出錯,也只造成明文中的一位出錯,其他的方式會造成整個塊丟失。
和CBC以及CFB一樣,OFB也需要一個IV。
各種加密模式一般在密碼學的教程中可以找到。
補充:X509電子證書的文件格式。
X509定義了用於存儲公鑰電子證書,證書撤回列表的文件格式。還定義了一個電子證書驗證的路徑算法。X509通常也稱為PKIX for Public Key Infrastructure (X.509),這說明了它是PKI體系的一種實現方式。X509所使用的多種文件格式:
.DER - DER encoded certificate,是ASN.1的一種編碼規則。
.PEM - (Privacy Enhanced Mail) Base64 encoded DER certificate, enclosed between "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" (also sometimes represented as .CRT, but double check to be sure.)
.cer, .crt - usually in binary DER form (same as .der), but also can be Base64-encoded (like .pem).
.P7B - See .p7c
.P7C - PKCS#7 SignedData structure without data, just certificate(s) or CRL(s)
.PFX - See .p12
.P12 - PKCS#12, may contain certificate(s) (public) and private keys (password protected)
其中,PKCS12是指RSA提出的一種X509文件格式標准。X509還有很多的文件格式標准,比如PEM,不過PKCS12的好處是可以存儲使用密碼加密保存的私鑰。它用於代替微軟的PFX格式。
PEM實際上DER的BASE64形式,並且在文件頭與文件尾各加上:"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"。OpenSSL可以在這兩種格式之間互轉。OpenSSL在PEM文件里保存私鑰的時候,文件頭與文件尾分別是:"-----BEGIN RSA PRIVATE KEY-----"和"-----END RSA PRIVATE KEY-----"。
安裝M2Crypto
內容
先決條件
在類Unix系統上安裝,包括Cygwin
在Windows上安裝時的差異
MacOSX的
先決條件
使用 M2Crypto(安裝后)需要以下內容:
Python 2.6,2.7,3.5,或較新的
OpenSSL 1.0.1e 或者更新
要安裝 M2Crypto,您必須能夠針對Python和OpenSSL頭文件/庫編譯和鏈接C源代碼。例如,在基於Debian的系統上,需要以下軟件包:
build-essential
python3-dev 和/或 python-dev
libssl-dev
swig 2.0.4 或者更新(某些人也可以安裝)
具有swig v1的特殊舊系統。*)
在類Unix系統上安裝,包括Cygwin
(未經測試且很可能已過時,歡迎使用Cygwin建立更新信息):
$ tar zxf m2crypto-
$ cd m2crypto-
$ python setup.py build
$ python setup.py install
如果你已經安裝了setuptools,你也可以選擇運行這樣的測試::
$ python setup.py test
這假定安裝了OpenSSL /usr。您可以使用--openssl選項為build_ext(或build)命令提供備用OpenSSL前綴位置
。因此,例如,如果您構建本地版本的OpenSSL並使用/usr/local前綴(您的包含在
/usr/local/include/openssl和libs中/usr/local/lib)安裝它
,那么您將添加--openssl=/usr/local到您的build
命令。
在Windows上安裝時的差異
(Windows上不再支持Python 2.6,如果你想留在Python 2上,只需更新到2.7)
(需要更新)
在從源構建之前,您需要安裝OpenSSL的包含文件,導入庫和DLL。OpenSSL 1.1.0及更高版本默認安裝在%ProgramFiles(86)%\OpenSSL(32位)或%ProgramW6432%\OpenSSL(64位)中,或作為最后的手段,安裝在
%ProgramFiles%\OpenSSL。setup.py將查看這些位置。1.1.0之前的OpenSSL沒有默認安裝位置,因此您必須明確指定其安裝位置。
與其他平台一樣,您可以使用--openssl選項指定build_ext(或build)命令的OpenSSL位置。例如,--openssl=c:\pkg\openssl將指定可以c:\pkg\openssl\include在庫中找到OpenSSL包含文件c:\pkg\openssl\lib。
'--openssl'選項將配置swig和編譯器以查找標頭和庫的默認位置。如果您的OpenSSL安裝在一個或者您想修改默認選項,請運行帶有正常distutils選項的build_ext步驟: - swig-opts, - include-dirs, - library-dirs和--libraries。
MSVC ++〜:sub:~ setup.py已配置為默認使用MSVC ++。 使用MSVC ++,OpenSSL pre 1.1.0 DLL,如構建,命名 libeay32.dll和ssleay32.dll。OpenSSL 1.1.x DLL名稱libcrypto-1_1.dll和libssl-1_1.dll。在你的PATH上安裝這些; 例如c:\bin,與...一起 openssl.exe。 對於MSVC ++中,導入庫,如OpenSSL的預構建1.1.0,被命名為libeay32.lib和ssleay32.lib。OpenSSL 1.1.x導入庫已命名libcrypto.lib並且libssl.lib。 MINGW :sub:~
注意
以下有關使用MINGW構建M2Crypto的說明來自M2Crypto 0.12。這些說明應繼續適用於此版本,但我尚未對其進行測試。
閱讀Sebastien Sauvage的網頁:
http://sebsauvage.net/python/mingw.html
對於mingw32的,OpenSSL的預1.1.0導入庫命名為
libeay32.dll.a和libssl32.dll.a。您可能需要編輯這些的setup.py文件。
您還需要創建libpython2[123].a,具體取決於您的Python版本。
OpenSSL的預1.1.0的DLL的mingw32的命名libeay32.dll和
libssl32.dll。OpenSSL 1.1.x DLL名稱libcrypto-1_1.dll
和libssl-1_1.dll。在你的PATH上安裝這些; 例如c:\bin,與...一起openssl.exe。
構建M2Crypto:
python setup.py build -cmingw32
python setup.py install
BC ++ :sub:~
~
注意
以下有關使用MSVC ++ 6.0和BC ++ 5.5免費編譯器套件構建M2Crypto的說明來自M2Crypto 0.10。這些說明應繼續適用於此版本,但我尚未對其進行測試。
注意
OpenSSL 1.1.x不支持BC ++。
對於BC ++,這些文件是使用該工具從MSVC ++創建的coff2omf.exe。我打電話給他們libeay32_bc.lib,並
ssleay32_bc.lib分別。您需要編輯這些的setup.py文件。
您還需要Python的導入庫,例如,python22.lib與BC ++兼容的版本; 即,創建python22_bc.lib從
python22.lib,保存的副本python22.lib(如
python22_vc.lib,說的),然后重命名python22_bc.lib到
python22.lib。
現在您已准備好構建M2Crypto。執行以下操作之一:
python setup.py build
python setup.py build -cbcpp
然后,:
python setup.py install
MacOSX的
Apple沒有提供更新版本的Mac OS X(至少從10.11開始)提供任何版本的OpenSSL,因此有必要使用brew或類似的打包系統來安裝第三方軟件包。Mac OS X用戶建議,這一系列命令在他的系統上為他提供了M2Crypto的工作副本:
$ brew install openssl && brew install swig
$ brew --prefix openssl
/usr/local/opt/openssl
$ LDFLAGS="-L\((brew --prefix openssl)/lib" \ CFLAGS="-I\)(brew --prefix openssl)/include"
SWIG_FEATURES="-I$(brew --prefix openssl)/include"
pip install m2crypto